##// END OF EJS Templates
commands.resolve: don't allow users to mark or unmark driver-resolved files...
Siddharth Agarwal -
r26784:c0aab596 default
parent child Browse files
Show More
@@ -1,6722 +1,6735 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 import streamclone
26 import streamclone
27
27
28 table = {}
28 table = {}
29
29
30 command = cmdutil.command(table)
30 command = cmdutil.command(table)
31
31
32 # Space delimited list of commands that don't require local repositories.
32 # Space delimited list of commands that don't require local repositories.
33 # This should be populated by passing norepo=True into the @command decorator.
33 # This should be populated by passing norepo=True into the @command decorator.
34 norepo = ''
34 norepo = ''
35 # Space delimited list of commands that optionally require local repositories.
35 # Space delimited list of commands that optionally require local repositories.
36 # This should be populated by passing optionalrepo=True into the @command
36 # This should be populated by passing optionalrepo=True into the @command
37 # decorator.
37 # decorator.
38 optionalrepo = ''
38 optionalrepo = ''
39 # Space delimited list of commands that will examine arguments looking for
39 # Space delimited list of commands that will examine arguments looking for
40 # a repository. This should be populated by passing inferrepo=True into the
40 # a repository. This should be populated by passing inferrepo=True into the
41 # @command decorator.
41 # @command decorator.
42 inferrepo = ''
42 inferrepo = ''
43
43
44 # label constants
44 # label constants
45 # until 3.5, bookmarks.current was the advertised name, not
45 # until 3.5, bookmarks.current was the advertised name, not
46 # bookmarks.active, so we must use both to avoid breaking old
46 # bookmarks.active, so we must use both to avoid breaking old
47 # custom styles
47 # custom styles
48 activebookmarklabel = 'bookmarks.active bookmarks.current'
48 activebookmarklabel = 'bookmarks.active bookmarks.current'
49
49
50 # common command options
50 # common command options
51
51
52 globalopts = [
52 globalopts = [
53 ('R', 'repository', '',
53 ('R', 'repository', '',
54 _('repository root directory or name of overlay bundle file'),
54 _('repository root directory or name of overlay bundle file'),
55 _('REPO')),
55 _('REPO')),
56 ('', 'cwd', '',
56 ('', 'cwd', '',
57 _('change working directory'), _('DIR')),
57 _('change working directory'), _('DIR')),
58 ('y', 'noninteractive', None,
58 ('y', 'noninteractive', None,
59 _('do not prompt, automatically pick the first choice for all prompts')),
59 _('do not prompt, automatically pick the first choice for all prompts')),
60 ('q', 'quiet', None, _('suppress output')),
60 ('q', 'quiet', None, _('suppress output')),
61 ('v', 'verbose', None, _('enable additional output')),
61 ('v', 'verbose', None, _('enable additional output')),
62 ('', 'config', [],
62 ('', 'config', [],
63 _('set/override config option (use \'section.name=value\')'),
63 _('set/override config option (use \'section.name=value\')'),
64 _('CONFIG')),
64 _('CONFIG')),
65 ('', 'debug', None, _('enable debugging output')),
65 ('', 'debug', None, _('enable debugging output')),
66 ('', 'debugger', None, _('start debugger')),
66 ('', 'debugger', None, _('start debugger')),
67 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
67 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
68 _('ENCODE')),
68 _('ENCODE')),
69 ('', 'encodingmode', encoding.encodingmode,
69 ('', 'encodingmode', encoding.encodingmode,
70 _('set the charset encoding mode'), _('MODE')),
70 _('set the charset encoding mode'), _('MODE')),
71 ('', 'traceback', None, _('always print a traceback on exception')),
71 ('', 'traceback', None, _('always print a traceback on exception')),
72 ('', 'time', None, _('time how long the command takes')),
72 ('', 'time', None, _('time how long the command takes')),
73 ('', 'profile', None, _('print command execution profile')),
73 ('', 'profile', None, _('print command execution profile')),
74 ('', 'version', None, _('output version information and exit')),
74 ('', 'version', None, _('output version information and exit')),
75 ('h', 'help', None, _('display help and exit')),
75 ('h', 'help', None, _('display help and exit')),
76 ('', 'hidden', False, _('consider hidden changesets')),
76 ('', 'hidden', False, _('consider hidden changesets')),
77 ]
77 ]
78
78
79 dryrunopts = [('n', 'dry-run', None,
79 dryrunopts = [('n', 'dry-run', None,
80 _('do not perform actions, just print output'))]
80 _('do not perform actions, just print output'))]
81
81
82 remoteopts = [
82 remoteopts = [
83 ('e', 'ssh', '',
83 ('e', 'ssh', '',
84 _('specify ssh command to use'), _('CMD')),
84 _('specify ssh command to use'), _('CMD')),
85 ('', 'remotecmd', '',
85 ('', 'remotecmd', '',
86 _('specify hg command to run on the remote side'), _('CMD')),
86 _('specify hg command to run on the remote side'), _('CMD')),
87 ('', 'insecure', None,
87 ('', 'insecure', None,
88 _('do not verify server certificate (ignoring web.cacerts config)')),
88 _('do not verify server certificate (ignoring web.cacerts config)')),
89 ]
89 ]
90
90
91 walkopts = [
91 walkopts = [
92 ('I', 'include', [],
92 ('I', 'include', [],
93 _('include names matching the given patterns'), _('PATTERN')),
93 _('include names matching the given patterns'), _('PATTERN')),
94 ('X', 'exclude', [],
94 ('X', 'exclude', [],
95 _('exclude names matching the given patterns'), _('PATTERN')),
95 _('exclude names matching the given patterns'), _('PATTERN')),
96 ]
96 ]
97
97
98 commitopts = [
98 commitopts = [
99 ('m', 'message', '',
99 ('m', 'message', '',
100 _('use text as commit message'), _('TEXT')),
100 _('use text as commit message'), _('TEXT')),
101 ('l', 'logfile', '',
101 ('l', 'logfile', '',
102 _('read commit message from file'), _('FILE')),
102 _('read commit message from file'), _('FILE')),
103 ]
103 ]
104
104
105 commitopts2 = [
105 commitopts2 = [
106 ('d', 'date', '',
106 ('d', 'date', '',
107 _('record the specified date as commit date'), _('DATE')),
107 _('record the specified date as commit date'), _('DATE')),
108 ('u', 'user', '',
108 ('u', 'user', '',
109 _('record the specified user as committer'), _('USER')),
109 _('record the specified user as committer'), _('USER')),
110 ]
110 ]
111
111
112 # hidden for now
112 # hidden for now
113 formatteropts = [
113 formatteropts = [
114 ('T', 'template', '',
114 ('T', 'template', '',
115 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
115 _('display with template (EXPERIMENTAL)'), _('TEMPLATE')),
116 ]
116 ]
117
117
118 templateopts = [
118 templateopts = [
119 ('', 'style', '',
119 ('', 'style', '',
120 _('display using template map file (DEPRECATED)'), _('STYLE')),
120 _('display using template map file (DEPRECATED)'), _('STYLE')),
121 ('T', 'template', '',
121 ('T', 'template', '',
122 _('display with template'), _('TEMPLATE')),
122 _('display with template'), _('TEMPLATE')),
123 ]
123 ]
124
124
125 logopts = [
125 logopts = [
126 ('p', 'patch', None, _('show patch')),
126 ('p', 'patch', None, _('show patch')),
127 ('g', 'git', None, _('use git extended diff format')),
127 ('g', 'git', None, _('use git extended diff format')),
128 ('l', 'limit', '',
128 ('l', 'limit', '',
129 _('limit number of changes displayed'), _('NUM')),
129 _('limit number of changes displayed'), _('NUM')),
130 ('M', 'no-merges', None, _('do not show merges')),
130 ('M', 'no-merges', None, _('do not show merges')),
131 ('', 'stat', None, _('output diffstat-style summary of changes')),
131 ('', 'stat', None, _('output diffstat-style summary of changes')),
132 ('G', 'graph', None, _("show the revision DAG")),
132 ('G', 'graph', None, _("show the revision DAG")),
133 ] + templateopts
133 ] + templateopts
134
134
135 diffopts = [
135 diffopts = [
136 ('a', 'text', None, _('treat all files as text')),
136 ('a', 'text', None, _('treat all files as text')),
137 ('g', 'git', None, _('use git extended diff format')),
137 ('g', 'git', None, _('use git extended diff format')),
138 ('', 'nodates', None, _('omit dates from diff headers'))
138 ('', 'nodates', None, _('omit dates from diff headers'))
139 ]
139 ]
140
140
141 diffwsopts = [
141 diffwsopts = [
142 ('w', 'ignore-all-space', None,
142 ('w', 'ignore-all-space', None,
143 _('ignore white space when comparing lines')),
143 _('ignore white space when comparing lines')),
144 ('b', 'ignore-space-change', None,
144 ('b', 'ignore-space-change', None,
145 _('ignore changes in the amount of white space')),
145 _('ignore changes in the amount of white space')),
146 ('B', 'ignore-blank-lines', None,
146 ('B', 'ignore-blank-lines', None,
147 _('ignore changes whose lines are all blank')),
147 _('ignore changes whose lines are all blank')),
148 ]
148 ]
149
149
150 diffopts2 = [
150 diffopts2 = [
151 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
151 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
152 ('p', 'show-function', None, _('show which function each change is in')),
152 ('p', 'show-function', None, _('show which function each change is in')),
153 ('', 'reverse', None, _('produce a diff that undoes the changes')),
153 ('', 'reverse', None, _('produce a diff that undoes the changes')),
154 ] + diffwsopts + [
154 ] + diffwsopts + [
155 ('U', 'unified', '',
155 ('U', 'unified', '',
156 _('number of lines of context to show'), _('NUM')),
156 _('number of lines of context to show'), _('NUM')),
157 ('', 'stat', None, _('output diffstat-style summary of changes')),
157 ('', 'stat', None, _('output diffstat-style summary of changes')),
158 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
158 ('', 'root', '', _('produce diffs relative to subdirectory'), _('DIR')),
159 ]
159 ]
160
160
161 mergetoolopts = [
161 mergetoolopts = [
162 ('t', 'tool', '', _('specify merge tool')),
162 ('t', 'tool', '', _('specify merge tool')),
163 ]
163 ]
164
164
165 similarityopts = [
165 similarityopts = [
166 ('s', 'similarity', '',
166 ('s', 'similarity', '',
167 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
167 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
168 ]
168 ]
169
169
170 subrepoopts = [
170 subrepoopts = [
171 ('S', 'subrepos', None,
171 ('S', 'subrepos', None,
172 _('recurse into subrepositories'))
172 _('recurse into subrepositories'))
173 ]
173 ]
174
174
175 # Commands start here, listed alphabetically
175 # Commands start here, listed alphabetically
176
176
177 @command('^add',
177 @command('^add',
178 walkopts + subrepoopts + dryrunopts,
178 walkopts + subrepoopts + dryrunopts,
179 _('[OPTION]... [FILE]...'),
179 _('[OPTION]... [FILE]...'),
180 inferrepo=True)
180 inferrepo=True)
181 def add(ui, repo, *pats, **opts):
181 def add(ui, repo, *pats, **opts):
182 """add the specified files on the next commit
182 """add the specified files on the next commit
183
183
184 Schedule files to be version controlled and added to the
184 Schedule files to be version controlled and added to the
185 repository.
185 repository.
186
186
187 The files will be added to the repository at the next commit. To
187 The files will be added to the repository at the next commit. To
188 undo an add before that, see :hg:`forget`.
188 undo an add before that, see :hg:`forget`.
189
189
190 If no names are given, add all files to the repository.
190 If no names are given, add all files to the repository.
191
191
192 .. container:: verbose
192 .. container:: verbose
193
193
194 An example showing how new (unknown) files are added
194 An example showing how new (unknown) files are added
195 automatically by :hg:`add`::
195 automatically by :hg:`add`::
196
196
197 $ ls
197 $ ls
198 foo.c
198 foo.c
199 $ hg status
199 $ hg status
200 ? foo.c
200 ? foo.c
201 $ hg add
201 $ hg add
202 adding foo.c
202 adding foo.c
203 $ hg status
203 $ hg status
204 A foo.c
204 A foo.c
205
205
206 Returns 0 if all files are successfully added.
206 Returns 0 if all files are successfully added.
207 """
207 """
208
208
209 m = scmutil.match(repo[None], pats, opts)
209 m = scmutil.match(repo[None], pats, opts)
210 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
210 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
211 return rejected and 1 or 0
211 return rejected and 1 or 0
212
212
213 @command('addremove',
213 @command('addremove',
214 similarityopts + subrepoopts + walkopts + dryrunopts,
214 similarityopts + subrepoopts + walkopts + dryrunopts,
215 _('[OPTION]... [FILE]...'),
215 _('[OPTION]... [FILE]...'),
216 inferrepo=True)
216 inferrepo=True)
217 def addremove(ui, repo, *pats, **opts):
217 def addremove(ui, repo, *pats, **opts):
218 """add all new files, delete all missing files
218 """add all new files, delete all missing files
219
219
220 Add all new files and remove all missing files from the
220 Add all new files and remove all missing files from the
221 repository.
221 repository.
222
222
223 New files are ignored if they match any of the patterns in
223 New files are ignored if they match any of the patterns in
224 ``.hgignore``. As with add, these changes take effect at the next
224 ``.hgignore``. As with add, these changes take effect at the next
225 commit.
225 commit.
226
226
227 Use the -s/--similarity option to detect renamed files. This
227 Use the -s/--similarity option to detect renamed files. This
228 option takes a percentage between 0 (disabled) and 100 (files must
228 option takes a percentage between 0 (disabled) and 100 (files must
229 be identical) as its parameter. With a parameter greater than 0,
229 be identical) as its parameter. With a parameter greater than 0,
230 this compares every removed file with every added file and records
230 this compares every removed file with every added file and records
231 those similar enough as renames. Detecting renamed files this way
231 those similar enough as renames. Detecting renamed files this way
232 can be expensive. After using this option, :hg:`status -C` can be
232 can be expensive. After using this option, :hg:`status -C` can be
233 used to check which files were identified as moved or renamed. If
233 used to check which files were identified as moved or renamed. If
234 not specified, -s/--similarity defaults to 100 and only renames of
234 not specified, -s/--similarity defaults to 100 and only renames of
235 identical files are detected.
235 identical files are detected.
236
236
237 Returns 0 if all files are successfully added.
237 Returns 0 if all files are successfully added.
238 """
238 """
239 try:
239 try:
240 sim = float(opts.get('similarity') or 100)
240 sim = float(opts.get('similarity') or 100)
241 except ValueError:
241 except ValueError:
242 raise error.Abort(_('similarity must be a number'))
242 raise error.Abort(_('similarity must be a number'))
243 if sim < 0 or sim > 100:
243 if sim < 0 or sim > 100:
244 raise error.Abort(_('similarity must be between 0 and 100'))
244 raise error.Abort(_('similarity must be between 0 and 100'))
245 matcher = scmutil.match(repo[None], pats, opts)
245 matcher = scmutil.match(repo[None], pats, opts)
246 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
246 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
247
247
248 @command('^annotate|blame',
248 @command('^annotate|blame',
249 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
249 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
250 ('', 'follow', None,
250 ('', 'follow', None,
251 _('follow copies/renames and list the filename (DEPRECATED)')),
251 _('follow copies/renames and list the filename (DEPRECATED)')),
252 ('', 'no-follow', None, _("don't follow copies and renames")),
252 ('', 'no-follow', None, _("don't follow copies and renames")),
253 ('a', 'text', None, _('treat all files as text')),
253 ('a', 'text', None, _('treat all files as text')),
254 ('u', 'user', None, _('list the author (long with -v)')),
254 ('u', 'user', None, _('list the author (long with -v)')),
255 ('f', 'file', None, _('list the filename')),
255 ('f', 'file', None, _('list the filename')),
256 ('d', 'date', None, _('list the date (short with -q)')),
256 ('d', 'date', None, _('list the date (short with -q)')),
257 ('n', 'number', None, _('list the revision number (default)')),
257 ('n', 'number', None, _('list the revision number (default)')),
258 ('c', 'changeset', None, _('list the changeset')),
258 ('c', 'changeset', None, _('list the changeset')),
259 ('l', 'line-number', None, _('show line number at the first appearance'))
259 ('l', 'line-number', None, _('show line number at the first appearance'))
260 ] + diffwsopts + walkopts + formatteropts,
260 ] + diffwsopts + walkopts + formatteropts,
261 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
261 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
262 inferrepo=True)
262 inferrepo=True)
263 def annotate(ui, repo, *pats, **opts):
263 def annotate(ui, repo, *pats, **opts):
264 """show changeset information by line for each file
264 """show changeset information by line for each file
265
265
266 List changes in files, showing the revision id responsible for
266 List changes in files, showing the revision id responsible for
267 each line
267 each line
268
268
269 This command is useful for discovering when a change was made and
269 This command is useful for discovering when a change was made and
270 by whom.
270 by whom.
271
271
272 Without the -a/--text option, annotate will avoid processing files
272 Without the -a/--text option, annotate will avoid processing files
273 it detects as binary. With -a, annotate will annotate the file
273 it detects as binary. With -a, annotate will annotate the file
274 anyway, although the results will probably be neither useful
274 anyway, although the results will probably be neither useful
275 nor desirable.
275 nor desirable.
276
276
277 Returns 0 on success.
277 Returns 0 on success.
278 """
278 """
279 if not pats:
279 if not pats:
280 raise error.Abort(_('at least one filename or pattern is required'))
280 raise error.Abort(_('at least one filename or pattern is required'))
281
281
282 if opts.get('follow'):
282 if opts.get('follow'):
283 # --follow is deprecated and now just an alias for -f/--file
283 # --follow is deprecated and now just an alias for -f/--file
284 # to mimic the behavior of Mercurial before version 1.5
284 # to mimic the behavior of Mercurial before version 1.5
285 opts['file'] = True
285 opts['file'] = True
286
286
287 ctx = scmutil.revsingle(repo, opts.get('rev'))
287 ctx = scmutil.revsingle(repo, opts.get('rev'))
288
288
289 fm = ui.formatter('annotate', opts)
289 fm = ui.formatter('annotate', opts)
290 if ui.quiet:
290 if ui.quiet:
291 datefunc = util.shortdate
291 datefunc = util.shortdate
292 else:
292 else:
293 datefunc = util.datestr
293 datefunc = util.datestr
294 if ctx.rev() is None:
294 if ctx.rev() is None:
295 def hexfn(node):
295 def hexfn(node):
296 if node is None:
296 if node is None:
297 return None
297 return None
298 else:
298 else:
299 return fm.hexfunc(node)
299 return fm.hexfunc(node)
300 if opts.get('changeset'):
300 if opts.get('changeset'):
301 # omit "+" suffix which is appended to node hex
301 # omit "+" suffix which is appended to node hex
302 def formatrev(rev):
302 def formatrev(rev):
303 if rev is None:
303 if rev is None:
304 return '%d' % ctx.p1().rev()
304 return '%d' % ctx.p1().rev()
305 else:
305 else:
306 return '%d' % rev
306 return '%d' % rev
307 else:
307 else:
308 def formatrev(rev):
308 def formatrev(rev):
309 if rev is None:
309 if rev is None:
310 return '%d+' % ctx.p1().rev()
310 return '%d+' % ctx.p1().rev()
311 else:
311 else:
312 return '%d ' % rev
312 return '%d ' % rev
313 def formathex(hex):
313 def formathex(hex):
314 if hex is None:
314 if hex is None:
315 return '%s+' % fm.hexfunc(ctx.p1().node())
315 return '%s+' % fm.hexfunc(ctx.p1().node())
316 else:
316 else:
317 return '%s ' % hex
317 return '%s ' % hex
318 else:
318 else:
319 hexfn = fm.hexfunc
319 hexfn = fm.hexfunc
320 formatrev = formathex = str
320 formatrev = formathex = str
321
321
322 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
322 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
323 ('number', ' ', lambda x: x[0].rev(), formatrev),
323 ('number', ' ', lambda x: x[0].rev(), formatrev),
324 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
324 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
325 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
325 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
326 ('file', ' ', lambda x: x[0].path(), str),
326 ('file', ' ', lambda x: x[0].path(), str),
327 ('line_number', ':', lambda x: x[1], str),
327 ('line_number', ':', lambda x: x[1], str),
328 ]
328 ]
329 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
329 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
330
330
331 if (not opts.get('user') and not opts.get('changeset')
331 if (not opts.get('user') and not opts.get('changeset')
332 and not opts.get('date') and not opts.get('file')):
332 and not opts.get('date') and not opts.get('file')):
333 opts['number'] = True
333 opts['number'] = True
334
334
335 linenumber = opts.get('line_number') is not None
335 linenumber = opts.get('line_number') is not None
336 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
336 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
337 raise error.Abort(_('at least one of -n/-c is required for -l'))
337 raise error.Abort(_('at least one of -n/-c is required for -l'))
338
338
339 if fm:
339 if fm:
340 def makefunc(get, fmt):
340 def makefunc(get, fmt):
341 return get
341 return get
342 else:
342 else:
343 def makefunc(get, fmt):
343 def makefunc(get, fmt):
344 return lambda x: fmt(get(x))
344 return lambda x: fmt(get(x))
345 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
345 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
346 if opts.get(op)]
346 if opts.get(op)]
347 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
347 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
348 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
348 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
349 if opts.get(op))
349 if opts.get(op))
350
350
351 def bad(x, y):
351 def bad(x, y):
352 raise error.Abort("%s: %s" % (x, y))
352 raise error.Abort("%s: %s" % (x, y))
353
353
354 m = scmutil.match(ctx, pats, opts, badfn=bad)
354 m = scmutil.match(ctx, pats, opts, badfn=bad)
355
355
356 follow = not opts.get('no_follow')
356 follow = not opts.get('no_follow')
357 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
357 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
358 whitespace=True)
358 whitespace=True)
359 for abs in ctx.walk(m):
359 for abs in ctx.walk(m):
360 fctx = ctx[abs]
360 fctx = ctx[abs]
361 if not opts.get('text') and util.binary(fctx.data()):
361 if not opts.get('text') and util.binary(fctx.data()):
362 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
362 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
363 continue
363 continue
364
364
365 lines = fctx.annotate(follow=follow, linenumber=linenumber,
365 lines = fctx.annotate(follow=follow, linenumber=linenumber,
366 diffopts=diffopts)
366 diffopts=diffopts)
367 formats = []
367 formats = []
368 pieces = []
368 pieces = []
369
369
370 for f, sep in funcmap:
370 for f, sep in funcmap:
371 l = [f(n) for n, dummy in lines]
371 l = [f(n) for n, dummy in lines]
372 if l:
372 if l:
373 if fm:
373 if fm:
374 formats.append(['%s' for x in l])
374 formats.append(['%s' for x in l])
375 else:
375 else:
376 sizes = [encoding.colwidth(x) for x in l]
376 sizes = [encoding.colwidth(x) for x in l]
377 ml = max(sizes)
377 ml = max(sizes)
378 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
378 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
379 pieces.append(l)
379 pieces.append(l)
380
380
381 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
381 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
382 fm.startitem()
382 fm.startitem()
383 fm.write(fields, "".join(f), *p)
383 fm.write(fields, "".join(f), *p)
384 fm.write('line', ": %s", l[1])
384 fm.write('line', ": %s", l[1])
385
385
386 if lines and not lines[-1][1].endswith('\n'):
386 if lines and not lines[-1][1].endswith('\n'):
387 fm.plain('\n')
387 fm.plain('\n')
388
388
389 fm.end()
389 fm.end()
390
390
391 @command('archive',
391 @command('archive',
392 [('', 'no-decode', None, _('do not pass files through decoders')),
392 [('', 'no-decode', None, _('do not pass files through decoders')),
393 ('p', 'prefix', '', _('directory prefix for files in archive'),
393 ('p', 'prefix', '', _('directory prefix for files in archive'),
394 _('PREFIX')),
394 _('PREFIX')),
395 ('r', 'rev', '', _('revision to distribute'), _('REV')),
395 ('r', 'rev', '', _('revision to distribute'), _('REV')),
396 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
396 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
397 ] + subrepoopts + walkopts,
397 ] + subrepoopts + walkopts,
398 _('[OPTION]... DEST'))
398 _('[OPTION]... DEST'))
399 def archive(ui, repo, dest, **opts):
399 def archive(ui, repo, dest, **opts):
400 '''create an unversioned archive of a repository revision
400 '''create an unversioned archive of a repository revision
401
401
402 By default, the revision used is the parent of the working
402 By default, the revision used is the parent of the working
403 directory; use -r/--rev to specify a different revision.
403 directory; use -r/--rev to specify a different revision.
404
404
405 The archive type is automatically detected based on file
405 The archive type is automatically detected based on file
406 extension (or override using -t/--type).
406 extension (or override using -t/--type).
407
407
408 .. container:: verbose
408 .. container:: verbose
409
409
410 Examples:
410 Examples:
411
411
412 - create a zip file containing the 1.0 release::
412 - create a zip file containing the 1.0 release::
413
413
414 hg archive -r 1.0 project-1.0.zip
414 hg archive -r 1.0 project-1.0.zip
415
415
416 - create a tarball excluding .hg files::
416 - create a tarball excluding .hg files::
417
417
418 hg archive project.tar.gz -X ".hg*"
418 hg archive project.tar.gz -X ".hg*"
419
419
420 Valid types are:
420 Valid types are:
421
421
422 :``files``: a directory full of files (default)
422 :``files``: a directory full of files (default)
423 :``tar``: tar archive, uncompressed
423 :``tar``: tar archive, uncompressed
424 :``tbz2``: tar archive, compressed using bzip2
424 :``tbz2``: tar archive, compressed using bzip2
425 :``tgz``: tar archive, compressed using gzip
425 :``tgz``: tar archive, compressed using gzip
426 :``uzip``: zip archive, uncompressed
426 :``uzip``: zip archive, uncompressed
427 :``zip``: zip archive, compressed using deflate
427 :``zip``: zip archive, compressed using deflate
428
428
429 The exact name of the destination archive or directory is given
429 The exact name of the destination archive or directory is given
430 using a format string; see :hg:`help export` for details.
430 using a format string; see :hg:`help export` for details.
431
431
432 Each member added to an archive file has a directory prefix
432 Each member added to an archive file has a directory prefix
433 prepended. Use -p/--prefix to specify a format string for the
433 prepended. Use -p/--prefix to specify a format string for the
434 prefix. The default is the basename of the archive, with suffixes
434 prefix. The default is the basename of the archive, with suffixes
435 removed.
435 removed.
436
436
437 Returns 0 on success.
437 Returns 0 on success.
438 '''
438 '''
439
439
440 ctx = scmutil.revsingle(repo, opts.get('rev'))
440 ctx = scmutil.revsingle(repo, opts.get('rev'))
441 if not ctx:
441 if not ctx:
442 raise error.Abort(_('no working directory: please specify a revision'))
442 raise error.Abort(_('no working directory: please specify a revision'))
443 node = ctx.node()
443 node = ctx.node()
444 dest = cmdutil.makefilename(repo, dest, node)
444 dest = cmdutil.makefilename(repo, dest, node)
445 if os.path.realpath(dest) == repo.root:
445 if os.path.realpath(dest) == repo.root:
446 raise error.Abort(_('repository root cannot be destination'))
446 raise error.Abort(_('repository root cannot be destination'))
447
447
448 kind = opts.get('type') or archival.guesskind(dest) or 'files'
448 kind = opts.get('type') or archival.guesskind(dest) or 'files'
449 prefix = opts.get('prefix')
449 prefix = opts.get('prefix')
450
450
451 if dest == '-':
451 if dest == '-':
452 if kind == 'files':
452 if kind == 'files':
453 raise error.Abort(_('cannot archive plain files to stdout'))
453 raise error.Abort(_('cannot archive plain files to stdout'))
454 dest = cmdutil.makefileobj(repo, dest)
454 dest = cmdutil.makefileobj(repo, dest)
455 if not prefix:
455 if not prefix:
456 prefix = os.path.basename(repo.root) + '-%h'
456 prefix = os.path.basename(repo.root) + '-%h'
457
457
458 prefix = cmdutil.makefilename(repo, prefix, node)
458 prefix = cmdutil.makefilename(repo, prefix, node)
459 matchfn = scmutil.match(ctx, [], opts)
459 matchfn = scmutil.match(ctx, [], opts)
460 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
460 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
461 matchfn, prefix, subrepos=opts.get('subrepos'))
461 matchfn, prefix, subrepos=opts.get('subrepos'))
462
462
463 @command('backout',
463 @command('backout',
464 [('', 'merge', None, _('merge with old dirstate parent after backout')),
464 [('', 'merge', None, _('merge with old dirstate parent after backout')),
465 ('', 'commit', None, _('commit if no conflicts were encountered')),
465 ('', 'commit', None, _('commit if no conflicts were encountered')),
466 ('', 'parent', '',
466 ('', 'parent', '',
467 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
467 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
468 ('r', 'rev', '', _('revision to backout'), _('REV')),
468 ('r', 'rev', '', _('revision to backout'), _('REV')),
469 ('e', 'edit', False, _('invoke editor on commit messages')),
469 ('e', 'edit', False, _('invoke editor on commit messages')),
470 ] + mergetoolopts + walkopts + commitopts + commitopts2,
470 ] + mergetoolopts + walkopts + commitopts + commitopts2,
471 _('[OPTION]... [-r] REV'))
471 _('[OPTION]... [-r] REV'))
472 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
472 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
473 '''reverse effect of earlier changeset
473 '''reverse effect of earlier changeset
474
474
475 Prepare a new changeset with the effect of REV undone in the
475 Prepare a new changeset with the effect of REV undone in the
476 current working directory.
476 current working directory.
477
477
478 If REV is the parent of the working directory, then this new changeset
478 If REV is the parent of the working directory, then this new changeset
479 is committed automatically. Otherwise, hg needs to merge the
479 is committed automatically. Otherwise, hg needs to merge the
480 changes and the merged result is left uncommitted.
480 changes and the merged result is left uncommitted.
481
481
482 .. note::
482 .. note::
483
483
484 backout cannot be used to fix either an unwanted or
484 backout cannot be used to fix either an unwanted or
485 incorrect merge.
485 incorrect merge.
486
486
487 .. container:: verbose
487 .. container:: verbose
488
488
489 By default, the pending changeset will have one parent,
489 By default, the pending changeset will have one parent,
490 maintaining a linear history. With --merge, the pending
490 maintaining a linear history. With --merge, the pending
491 changeset will instead have two parents: the old parent of the
491 changeset will instead have two parents: the old parent of the
492 working directory and a new child of REV that simply undoes REV.
492 working directory and a new child of REV that simply undoes REV.
493
493
494 Before version 1.7, the behavior without --merge was equivalent
494 Before version 1.7, the behavior without --merge was equivalent
495 to specifying --merge followed by :hg:`update --clean .` to
495 to specifying --merge followed by :hg:`update --clean .` to
496 cancel the merge and leave the child of REV as a head to be
496 cancel the merge and leave the child of REV as a head to be
497 merged separately.
497 merged separately.
498
498
499 See :hg:`help dates` for a list of formats valid for -d/--date.
499 See :hg:`help dates` for a list of formats valid for -d/--date.
500
500
501 See :hg:`help revert` for a way to restore files to the state
501 See :hg:`help revert` for a way to restore files to the state
502 of another revision.
502 of another revision.
503
503
504 Returns 0 on success, 1 if nothing to backout or there are unresolved
504 Returns 0 on success, 1 if nothing to backout or there are unresolved
505 files.
505 files.
506 '''
506 '''
507 if rev and node:
507 if rev and node:
508 raise error.Abort(_("please specify just one revision"))
508 raise error.Abort(_("please specify just one revision"))
509
509
510 if not rev:
510 if not rev:
511 rev = node
511 rev = node
512
512
513 if not rev:
513 if not rev:
514 raise error.Abort(_("please specify a revision to backout"))
514 raise error.Abort(_("please specify a revision to backout"))
515
515
516 date = opts.get('date')
516 date = opts.get('date')
517 if date:
517 if date:
518 opts['date'] = util.parsedate(date)
518 opts['date'] = util.parsedate(date)
519
519
520 cmdutil.checkunfinished(repo)
520 cmdutil.checkunfinished(repo)
521 cmdutil.bailifchanged(repo)
521 cmdutil.bailifchanged(repo)
522 node = scmutil.revsingle(repo, rev).node()
522 node = scmutil.revsingle(repo, rev).node()
523
523
524 op1, op2 = repo.dirstate.parents()
524 op1, op2 = repo.dirstate.parents()
525 if not repo.changelog.isancestor(node, op1):
525 if not repo.changelog.isancestor(node, op1):
526 raise error.Abort(_('cannot backout change that is not an ancestor'))
526 raise error.Abort(_('cannot backout change that is not an ancestor'))
527
527
528 p1, p2 = repo.changelog.parents(node)
528 p1, p2 = repo.changelog.parents(node)
529 if p1 == nullid:
529 if p1 == nullid:
530 raise error.Abort(_('cannot backout a change with no parents'))
530 raise error.Abort(_('cannot backout a change with no parents'))
531 if p2 != nullid:
531 if p2 != nullid:
532 if not opts.get('parent'):
532 if not opts.get('parent'):
533 raise error.Abort(_('cannot backout a merge changeset'))
533 raise error.Abort(_('cannot backout a merge changeset'))
534 p = repo.lookup(opts['parent'])
534 p = repo.lookup(opts['parent'])
535 if p not in (p1, p2):
535 if p not in (p1, p2):
536 raise error.Abort(_('%s is not a parent of %s') %
536 raise error.Abort(_('%s is not a parent of %s') %
537 (short(p), short(node)))
537 (short(p), short(node)))
538 parent = p
538 parent = p
539 else:
539 else:
540 if opts.get('parent'):
540 if opts.get('parent'):
541 raise error.Abort(_('cannot use --parent on non-merge changeset'))
541 raise error.Abort(_('cannot use --parent on non-merge changeset'))
542 parent = p1
542 parent = p1
543
543
544 # the backout should appear on the same branch
544 # the backout should appear on the same branch
545 wlock = repo.wlock()
545 wlock = repo.wlock()
546 try:
546 try:
547 branch = repo.dirstate.branch()
547 branch = repo.dirstate.branch()
548 bheads = repo.branchheads(branch)
548 bheads = repo.branchheads(branch)
549 rctx = scmutil.revsingle(repo, hex(parent))
549 rctx = scmutil.revsingle(repo, hex(parent))
550 if not opts.get('merge') and op1 != node:
550 if not opts.get('merge') and op1 != node:
551 dsguard = cmdutil.dirstateguard(repo, 'backout')
551 dsguard = cmdutil.dirstateguard(repo, 'backout')
552 try:
552 try:
553 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
553 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
554 'backout')
554 'backout')
555 stats = mergemod.update(repo, parent, True, True, False,
555 stats = mergemod.update(repo, parent, True, True, False,
556 node, False)
556 node, False)
557 repo.setparents(op1, op2)
557 repo.setparents(op1, op2)
558 dsguard.close()
558 dsguard.close()
559 hg._showstats(repo, stats)
559 hg._showstats(repo, stats)
560 if stats[3]:
560 if stats[3]:
561 repo.ui.status(_("use 'hg resolve' to retry unresolved "
561 repo.ui.status(_("use 'hg resolve' to retry unresolved "
562 "file merges\n"))
562 "file merges\n"))
563 return 1
563 return 1
564 elif not commit:
564 elif not commit:
565 msg = _("changeset %s backed out, "
565 msg = _("changeset %s backed out, "
566 "don't forget to commit.\n")
566 "don't forget to commit.\n")
567 ui.status(msg % short(node))
567 ui.status(msg % short(node))
568 return 0
568 return 0
569 finally:
569 finally:
570 ui.setconfig('ui', 'forcemerge', '', '')
570 ui.setconfig('ui', 'forcemerge', '', '')
571 lockmod.release(dsguard)
571 lockmod.release(dsguard)
572 else:
572 else:
573 hg.clean(repo, node, show_stats=False)
573 hg.clean(repo, node, show_stats=False)
574 repo.dirstate.setbranch(branch)
574 repo.dirstate.setbranch(branch)
575 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
575 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
576
576
577
577
578 def commitfunc(ui, repo, message, match, opts):
578 def commitfunc(ui, repo, message, match, opts):
579 editform = 'backout'
579 editform = 'backout'
580 e = cmdutil.getcommiteditor(editform=editform, **opts)
580 e = cmdutil.getcommiteditor(editform=editform, **opts)
581 if not message:
581 if not message:
582 # we don't translate commit messages
582 # we don't translate commit messages
583 message = "Backed out changeset %s" % short(node)
583 message = "Backed out changeset %s" % short(node)
584 e = cmdutil.getcommiteditor(edit=True, editform=editform)
584 e = cmdutil.getcommiteditor(edit=True, editform=editform)
585 return repo.commit(message, opts.get('user'), opts.get('date'),
585 return repo.commit(message, opts.get('user'), opts.get('date'),
586 match, editor=e)
586 match, editor=e)
587 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
587 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
588 if not newnode:
588 if not newnode:
589 ui.status(_("nothing changed\n"))
589 ui.status(_("nothing changed\n"))
590 return 1
590 return 1
591 cmdutil.commitstatus(repo, newnode, branch, bheads)
591 cmdutil.commitstatus(repo, newnode, branch, bheads)
592
592
593 def nice(node):
593 def nice(node):
594 return '%d:%s' % (repo.changelog.rev(node), short(node))
594 return '%d:%s' % (repo.changelog.rev(node), short(node))
595 ui.status(_('changeset %s backs out changeset %s\n') %
595 ui.status(_('changeset %s backs out changeset %s\n') %
596 (nice(repo.changelog.tip()), nice(node)))
596 (nice(repo.changelog.tip()), nice(node)))
597 if opts.get('merge') and op1 != node:
597 if opts.get('merge') and op1 != node:
598 hg.clean(repo, op1, show_stats=False)
598 hg.clean(repo, op1, show_stats=False)
599 ui.status(_('merging with changeset %s\n')
599 ui.status(_('merging with changeset %s\n')
600 % nice(repo.changelog.tip()))
600 % nice(repo.changelog.tip()))
601 try:
601 try:
602 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
602 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
603 'backout')
603 'backout')
604 return hg.merge(repo, hex(repo.changelog.tip()))
604 return hg.merge(repo, hex(repo.changelog.tip()))
605 finally:
605 finally:
606 ui.setconfig('ui', 'forcemerge', '', '')
606 ui.setconfig('ui', 'forcemerge', '', '')
607 finally:
607 finally:
608 wlock.release()
608 wlock.release()
609 return 0
609 return 0
610
610
611 @command('bisect',
611 @command('bisect',
612 [('r', 'reset', False, _('reset bisect state')),
612 [('r', 'reset', False, _('reset bisect state')),
613 ('g', 'good', False, _('mark changeset good')),
613 ('g', 'good', False, _('mark changeset good')),
614 ('b', 'bad', False, _('mark changeset bad')),
614 ('b', 'bad', False, _('mark changeset bad')),
615 ('s', 'skip', False, _('skip testing changeset')),
615 ('s', 'skip', False, _('skip testing changeset')),
616 ('e', 'extend', False, _('extend the bisect range')),
616 ('e', 'extend', False, _('extend the bisect range')),
617 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
617 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
618 ('U', 'noupdate', False, _('do not update to target'))],
618 ('U', 'noupdate', False, _('do not update to target'))],
619 _("[-gbsr] [-U] [-c CMD] [REV]"))
619 _("[-gbsr] [-U] [-c CMD] [REV]"))
620 def bisect(ui, repo, rev=None, extra=None, command=None,
620 def bisect(ui, repo, rev=None, extra=None, command=None,
621 reset=None, good=None, bad=None, skip=None, extend=None,
621 reset=None, good=None, bad=None, skip=None, extend=None,
622 noupdate=None):
622 noupdate=None):
623 """subdivision search of changesets
623 """subdivision search of changesets
624
624
625 This command helps to find changesets which introduce problems. To
625 This command helps to find changesets which introduce problems. To
626 use, mark the earliest changeset you know exhibits the problem as
626 use, mark the earliest changeset you know exhibits the problem as
627 bad, then mark the latest changeset which is free from the problem
627 bad, then mark the latest changeset which is free from the problem
628 as good. Bisect will update your working directory to a revision
628 as good. Bisect will update your working directory to a revision
629 for testing (unless the -U/--noupdate option is specified). Once
629 for testing (unless the -U/--noupdate option is specified). Once
630 you have performed tests, mark the working directory as good or
630 you have performed tests, mark the working directory as good or
631 bad, and bisect will either update to another candidate changeset
631 bad, and bisect will either update to another candidate changeset
632 or announce that it has found the bad revision.
632 or announce that it has found the bad revision.
633
633
634 As a shortcut, you can also use the revision argument to mark a
634 As a shortcut, you can also use the revision argument to mark a
635 revision as good or bad without checking it out first.
635 revision as good or bad without checking it out first.
636
636
637 If you supply a command, it will be used for automatic bisection.
637 If you supply a command, it will be used for automatic bisection.
638 The environment variable HG_NODE will contain the ID of the
638 The environment variable HG_NODE will contain the ID of the
639 changeset being tested. The exit status of the command will be
639 changeset being tested. The exit status of the command will be
640 used to mark revisions as good or bad: status 0 means good, 125
640 used to mark revisions as good or bad: status 0 means good, 125
641 means to skip the revision, 127 (command not found) will abort the
641 means to skip the revision, 127 (command not found) will abort the
642 bisection, and any other non-zero exit status means the revision
642 bisection, and any other non-zero exit status means the revision
643 is bad.
643 is bad.
644
644
645 .. container:: verbose
645 .. container:: verbose
646
646
647 Some examples:
647 Some examples:
648
648
649 - start a bisection with known bad revision 34, and good revision 12::
649 - start a bisection with known bad revision 34, and good revision 12::
650
650
651 hg bisect --bad 34
651 hg bisect --bad 34
652 hg bisect --good 12
652 hg bisect --good 12
653
653
654 - advance the current bisection by marking current revision as good or
654 - advance the current bisection by marking current revision as good or
655 bad::
655 bad::
656
656
657 hg bisect --good
657 hg bisect --good
658 hg bisect --bad
658 hg bisect --bad
659
659
660 - mark the current revision, or a known revision, to be skipped (e.g. if
660 - mark the current revision, or a known revision, to be skipped (e.g. if
661 that revision is not usable because of another issue)::
661 that revision is not usable because of another issue)::
662
662
663 hg bisect --skip
663 hg bisect --skip
664 hg bisect --skip 23
664 hg bisect --skip 23
665
665
666 - skip all revisions that do not touch directories ``foo`` or ``bar``::
666 - skip all revisions that do not touch directories ``foo`` or ``bar``::
667
667
668 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
668 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
669
669
670 - forget the current bisection::
670 - forget the current bisection::
671
671
672 hg bisect --reset
672 hg bisect --reset
673
673
674 - use 'make && make tests' to automatically find the first broken
674 - use 'make && make tests' to automatically find the first broken
675 revision::
675 revision::
676
676
677 hg bisect --reset
677 hg bisect --reset
678 hg bisect --bad 34
678 hg bisect --bad 34
679 hg bisect --good 12
679 hg bisect --good 12
680 hg bisect --command "make && make tests"
680 hg bisect --command "make && make tests"
681
681
682 - see all changesets whose states are already known in the current
682 - see all changesets whose states are already known in the current
683 bisection::
683 bisection::
684
684
685 hg log -r "bisect(pruned)"
685 hg log -r "bisect(pruned)"
686
686
687 - see the changeset currently being bisected (especially useful
687 - see the changeset currently being bisected (especially useful
688 if running with -U/--noupdate)::
688 if running with -U/--noupdate)::
689
689
690 hg log -r "bisect(current)"
690 hg log -r "bisect(current)"
691
691
692 - see all changesets that took part in the current bisection::
692 - see all changesets that took part in the current bisection::
693
693
694 hg log -r "bisect(range)"
694 hg log -r "bisect(range)"
695
695
696 - you can even get a nice graph::
696 - you can even get a nice graph::
697
697
698 hg log --graph -r "bisect(range)"
698 hg log --graph -r "bisect(range)"
699
699
700 See :hg:`help revsets` for more about the `bisect()` keyword.
700 See :hg:`help revsets` for more about the `bisect()` keyword.
701
701
702 Returns 0 on success.
702 Returns 0 on success.
703 """
703 """
704 def extendbisectrange(nodes, good):
704 def extendbisectrange(nodes, good):
705 # bisect is incomplete when it ends on a merge node and
705 # bisect is incomplete when it ends on a merge node and
706 # one of the parent was not checked.
706 # one of the parent was not checked.
707 parents = repo[nodes[0]].parents()
707 parents = repo[nodes[0]].parents()
708 if len(parents) > 1:
708 if len(parents) > 1:
709 if good:
709 if good:
710 side = state['bad']
710 side = state['bad']
711 else:
711 else:
712 side = state['good']
712 side = state['good']
713 num = len(set(i.node() for i in parents) & set(side))
713 num = len(set(i.node() for i in parents) & set(side))
714 if num == 1:
714 if num == 1:
715 return parents[0].ancestor(parents[1])
715 return parents[0].ancestor(parents[1])
716 return None
716 return None
717
717
718 def print_result(nodes, good):
718 def print_result(nodes, good):
719 displayer = cmdutil.show_changeset(ui, repo, {})
719 displayer = cmdutil.show_changeset(ui, repo, {})
720 if len(nodes) == 1:
720 if len(nodes) == 1:
721 # narrowed it down to a single revision
721 # narrowed it down to a single revision
722 if good:
722 if good:
723 ui.write(_("The first good revision is:\n"))
723 ui.write(_("The first good revision is:\n"))
724 else:
724 else:
725 ui.write(_("The first bad revision is:\n"))
725 ui.write(_("The first bad revision is:\n"))
726 displayer.show(repo[nodes[0]])
726 displayer.show(repo[nodes[0]])
727 extendnode = extendbisectrange(nodes, good)
727 extendnode = extendbisectrange(nodes, good)
728 if extendnode is not None:
728 if extendnode is not None:
729 ui.write(_('Not all ancestors of this changeset have been'
729 ui.write(_('Not all ancestors of this changeset have been'
730 ' checked.\nUse bisect --extend to continue the '
730 ' checked.\nUse bisect --extend to continue the '
731 'bisection from\nthe common ancestor, %s.\n')
731 'bisection from\nthe common ancestor, %s.\n')
732 % extendnode)
732 % extendnode)
733 else:
733 else:
734 # multiple possible revisions
734 # multiple possible revisions
735 if good:
735 if good:
736 ui.write(_("Due to skipped revisions, the first "
736 ui.write(_("Due to skipped revisions, the first "
737 "good revision could be any of:\n"))
737 "good revision could be any of:\n"))
738 else:
738 else:
739 ui.write(_("Due to skipped revisions, the first "
739 ui.write(_("Due to skipped revisions, the first "
740 "bad revision could be any of:\n"))
740 "bad revision could be any of:\n"))
741 for n in nodes:
741 for n in nodes:
742 displayer.show(repo[n])
742 displayer.show(repo[n])
743 displayer.close()
743 displayer.close()
744
744
745 def check_state(state, interactive=True):
745 def check_state(state, interactive=True):
746 if not state['good'] or not state['bad']:
746 if not state['good'] or not state['bad']:
747 if (good or bad or skip or reset) and interactive:
747 if (good or bad or skip or reset) and interactive:
748 return
748 return
749 if not state['good']:
749 if not state['good']:
750 raise error.Abort(_('cannot bisect (no known good revisions)'))
750 raise error.Abort(_('cannot bisect (no known good revisions)'))
751 else:
751 else:
752 raise error.Abort(_('cannot bisect (no known bad revisions)'))
752 raise error.Abort(_('cannot bisect (no known bad revisions)'))
753 return True
753 return True
754
754
755 # backward compatibility
755 # backward compatibility
756 if rev in "good bad reset init".split():
756 if rev in "good bad reset init".split():
757 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
757 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
758 cmd, rev, extra = rev, extra, None
758 cmd, rev, extra = rev, extra, None
759 if cmd == "good":
759 if cmd == "good":
760 good = True
760 good = True
761 elif cmd == "bad":
761 elif cmd == "bad":
762 bad = True
762 bad = True
763 else:
763 else:
764 reset = True
764 reset = True
765 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
765 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
766 raise error.Abort(_('incompatible arguments'))
766 raise error.Abort(_('incompatible arguments'))
767
767
768 cmdutil.checkunfinished(repo)
768 cmdutil.checkunfinished(repo)
769
769
770 if reset:
770 if reset:
771 p = repo.join("bisect.state")
771 p = repo.join("bisect.state")
772 if os.path.exists(p):
772 if os.path.exists(p):
773 os.unlink(p)
773 os.unlink(p)
774 return
774 return
775
775
776 state = hbisect.load_state(repo)
776 state = hbisect.load_state(repo)
777
777
778 if command:
778 if command:
779 changesets = 1
779 changesets = 1
780 if noupdate:
780 if noupdate:
781 try:
781 try:
782 node = state['current'][0]
782 node = state['current'][0]
783 except LookupError:
783 except LookupError:
784 raise error.Abort(_('current bisect revision is unknown - '
784 raise error.Abort(_('current bisect revision is unknown - '
785 'start a new bisect to fix'))
785 'start a new bisect to fix'))
786 else:
786 else:
787 node, p2 = repo.dirstate.parents()
787 node, p2 = repo.dirstate.parents()
788 if p2 != nullid:
788 if p2 != nullid:
789 raise error.Abort(_('current bisect revision is a merge'))
789 raise error.Abort(_('current bisect revision is a merge'))
790 try:
790 try:
791 while changesets:
791 while changesets:
792 # update state
792 # update state
793 state['current'] = [node]
793 state['current'] = [node]
794 hbisect.save_state(repo, state)
794 hbisect.save_state(repo, state)
795 status = ui.system(command, environ={'HG_NODE': hex(node)})
795 status = ui.system(command, environ={'HG_NODE': hex(node)})
796 if status == 125:
796 if status == 125:
797 transition = "skip"
797 transition = "skip"
798 elif status == 0:
798 elif status == 0:
799 transition = "good"
799 transition = "good"
800 # status < 0 means process was killed
800 # status < 0 means process was killed
801 elif status == 127:
801 elif status == 127:
802 raise error.Abort(_("failed to execute %s") % command)
802 raise error.Abort(_("failed to execute %s") % command)
803 elif status < 0:
803 elif status < 0:
804 raise error.Abort(_("%s killed") % command)
804 raise error.Abort(_("%s killed") % command)
805 else:
805 else:
806 transition = "bad"
806 transition = "bad"
807 ctx = scmutil.revsingle(repo, rev, node)
807 ctx = scmutil.revsingle(repo, rev, node)
808 rev = None # clear for future iterations
808 rev = None # clear for future iterations
809 state[transition].append(ctx.node())
809 state[transition].append(ctx.node())
810 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
810 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
811 check_state(state, interactive=False)
811 check_state(state, interactive=False)
812 # bisect
812 # bisect
813 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
813 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
814 # update to next check
814 # update to next check
815 node = nodes[0]
815 node = nodes[0]
816 if not noupdate:
816 if not noupdate:
817 cmdutil.bailifchanged(repo)
817 cmdutil.bailifchanged(repo)
818 hg.clean(repo, node, show_stats=False)
818 hg.clean(repo, node, show_stats=False)
819 finally:
819 finally:
820 state['current'] = [node]
820 state['current'] = [node]
821 hbisect.save_state(repo, state)
821 hbisect.save_state(repo, state)
822 print_result(nodes, bgood)
822 print_result(nodes, bgood)
823 return
823 return
824
824
825 # update state
825 # update state
826
826
827 if rev:
827 if rev:
828 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
828 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
829 else:
829 else:
830 nodes = [repo.lookup('.')]
830 nodes = [repo.lookup('.')]
831
831
832 if good or bad or skip:
832 if good or bad or skip:
833 if good:
833 if good:
834 state['good'] += nodes
834 state['good'] += nodes
835 elif bad:
835 elif bad:
836 state['bad'] += nodes
836 state['bad'] += nodes
837 elif skip:
837 elif skip:
838 state['skip'] += nodes
838 state['skip'] += nodes
839 hbisect.save_state(repo, state)
839 hbisect.save_state(repo, state)
840
840
841 if not check_state(state):
841 if not check_state(state):
842 return
842 return
843
843
844 # actually bisect
844 # actually bisect
845 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
845 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
846 if extend:
846 if extend:
847 if not changesets:
847 if not changesets:
848 extendnode = extendbisectrange(nodes, good)
848 extendnode = extendbisectrange(nodes, good)
849 if extendnode is not None:
849 if extendnode is not None:
850 ui.write(_("Extending search to changeset %d:%s\n")
850 ui.write(_("Extending search to changeset %d:%s\n")
851 % (extendnode.rev(), extendnode))
851 % (extendnode.rev(), extendnode))
852 state['current'] = [extendnode.node()]
852 state['current'] = [extendnode.node()]
853 hbisect.save_state(repo, state)
853 hbisect.save_state(repo, state)
854 if noupdate:
854 if noupdate:
855 return
855 return
856 cmdutil.bailifchanged(repo)
856 cmdutil.bailifchanged(repo)
857 return hg.clean(repo, extendnode.node())
857 return hg.clean(repo, extendnode.node())
858 raise error.Abort(_("nothing to extend"))
858 raise error.Abort(_("nothing to extend"))
859
859
860 if changesets == 0:
860 if changesets == 0:
861 print_result(nodes, good)
861 print_result(nodes, good)
862 else:
862 else:
863 assert len(nodes) == 1 # only a single node can be tested next
863 assert len(nodes) == 1 # only a single node can be tested next
864 node = nodes[0]
864 node = nodes[0]
865 # compute the approximate number of remaining tests
865 # compute the approximate number of remaining tests
866 tests, size = 0, 2
866 tests, size = 0, 2
867 while size <= changesets:
867 while size <= changesets:
868 tests, size = tests + 1, size * 2
868 tests, size = tests + 1, size * 2
869 rev = repo.changelog.rev(node)
869 rev = repo.changelog.rev(node)
870 ui.write(_("Testing changeset %d:%s "
870 ui.write(_("Testing changeset %d:%s "
871 "(%d changesets remaining, ~%d tests)\n")
871 "(%d changesets remaining, ~%d tests)\n")
872 % (rev, short(node), changesets, tests))
872 % (rev, short(node), changesets, tests))
873 state['current'] = [node]
873 state['current'] = [node]
874 hbisect.save_state(repo, state)
874 hbisect.save_state(repo, state)
875 if not noupdate:
875 if not noupdate:
876 cmdutil.bailifchanged(repo)
876 cmdutil.bailifchanged(repo)
877 return hg.clean(repo, node)
877 return hg.clean(repo, node)
878
878
879 @command('bookmarks|bookmark',
879 @command('bookmarks|bookmark',
880 [('f', 'force', False, _('force')),
880 [('f', 'force', False, _('force')),
881 ('r', 'rev', '', _('revision'), _('REV')),
881 ('r', 'rev', '', _('revision'), _('REV')),
882 ('d', 'delete', False, _('delete a given bookmark')),
882 ('d', 'delete', False, _('delete a given bookmark')),
883 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
883 ('m', 'rename', '', _('rename a given bookmark'), _('OLD')),
884 ('i', 'inactive', False, _('mark a bookmark inactive')),
884 ('i', 'inactive', False, _('mark a bookmark inactive')),
885 ] + formatteropts,
885 ] + formatteropts,
886 _('hg bookmarks [OPTIONS]... [NAME]...'))
886 _('hg bookmarks [OPTIONS]... [NAME]...'))
887 def bookmark(ui, repo, *names, **opts):
887 def bookmark(ui, repo, *names, **opts):
888 '''create a new bookmark or list existing bookmarks
888 '''create a new bookmark or list existing bookmarks
889
889
890 Bookmarks are labels on changesets to help track lines of development.
890 Bookmarks are labels on changesets to help track lines of development.
891 Bookmarks are unversioned and can be moved, renamed and deleted.
891 Bookmarks are unversioned and can be moved, renamed and deleted.
892 Deleting or moving a bookmark has no effect on the associated changesets.
892 Deleting or moving a bookmark has no effect on the associated changesets.
893
893
894 Creating or updating to a bookmark causes it to be marked as 'active'.
894 Creating or updating to a bookmark causes it to be marked as 'active'.
895 The active bookmark is indicated with a '*'.
895 The active bookmark is indicated with a '*'.
896 When a commit is made, the active bookmark will advance to the new commit.
896 When a commit is made, the active bookmark will advance to the new commit.
897 A plain :hg:`update` will also advance an active bookmark, if possible.
897 A plain :hg:`update` will also advance an active bookmark, if possible.
898 Updating away from a bookmark will cause it to be deactivated.
898 Updating away from a bookmark will cause it to be deactivated.
899
899
900 Bookmarks can be pushed and pulled between repositories (see
900 Bookmarks can be pushed and pulled between repositories (see
901 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
901 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
902 diverged, a new 'divergent bookmark' of the form 'name@path' will
902 diverged, a new 'divergent bookmark' of the form 'name@path' will
903 be created. Using :hg:`merge` will resolve the divergence.
903 be created. Using :hg:`merge` will resolve the divergence.
904
904
905 A bookmark named '@' has the special property that :hg:`clone` will
905 A bookmark named '@' has the special property that :hg:`clone` will
906 check it out by default if it exists.
906 check it out by default if it exists.
907
907
908 .. container:: verbose
908 .. container:: verbose
909
909
910 Examples:
910 Examples:
911
911
912 - create an active bookmark for a new line of development::
912 - create an active bookmark for a new line of development::
913
913
914 hg book new-feature
914 hg book new-feature
915
915
916 - create an inactive bookmark as a place marker::
916 - create an inactive bookmark as a place marker::
917
917
918 hg book -i reviewed
918 hg book -i reviewed
919
919
920 - create an inactive bookmark on another changeset::
920 - create an inactive bookmark on another changeset::
921
921
922 hg book -r .^ tested
922 hg book -r .^ tested
923
923
924 - rename bookmark turkey to dinner::
924 - rename bookmark turkey to dinner::
925
925
926 hg book -m turkey dinner
926 hg book -m turkey dinner
927
927
928 - move the '@' bookmark from another branch::
928 - move the '@' bookmark from another branch::
929
929
930 hg book -f @
930 hg book -f @
931 '''
931 '''
932 force = opts.get('force')
932 force = opts.get('force')
933 rev = opts.get('rev')
933 rev = opts.get('rev')
934 delete = opts.get('delete')
934 delete = opts.get('delete')
935 rename = opts.get('rename')
935 rename = opts.get('rename')
936 inactive = opts.get('inactive')
936 inactive = opts.get('inactive')
937
937
938 def checkformat(mark):
938 def checkformat(mark):
939 mark = mark.strip()
939 mark = mark.strip()
940 if not mark:
940 if not mark:
941 raise error.Abort(_("bookmark names cannot consist entirely of "
941 raise error.Abort(_("bookmark names cannot consist entirely of "
942 "whitespace"))
942 "whitespace"))
943 scmutil.checknewlabel(repo, mark, 'bookmark')
943 scmutil.checknewlabel(repo, mark, 'bookmark')
944 return mark
944 return mark
945
945
946 def checkconflict(repo, mark, cur, force=False, target=None):
946 def checkconflict(repo, mark, cur, force=False, target=None):
947 if mark in marks and not force:
947 if mark in marks and not force:
948 if target:
948 if target:
949 if marks[mark] == target and target == cur:
949 if marks[mark] == target and target == cur:
950 # re-activating a bookmark
950 # re-activating a bookmark
951 return
951 return
952 anc = repo.changelog.ancestors([repo[target].rev()])
952 anc = repo.changelog.ancestors([repo[target].rev()])
953 bmctx = repo[marks[mark]]
953 bmctx = repo[marks[mark]]
954 divs = [repo[b].node() for b in marks
954 divs = [repo[b].node() for b in marks
955 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
955 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
956
956
957 # allow resolving a single divergent bookmark even if moving
957 # allow resolving a single divergent bookmark even if moving
958 # the bookmark across branches when a revision is specified
958 # the bookmark across branches when a revision is specified
959 # that contains a divergent bookmark
959 # that contains a divergent bookmark
960 if bmctx.rev() not in anc and target in divs:
960 if bmctx.rev() not in anc and target in divs:
961 bookmarks.deletedivergent(repo, [target], mark)
961 bookmarks.deletedivergent(repo, [target], mark)
962 return
962 return
963
963
964 deletefrom = [b for b in divs
964 deletefrom = [b for b in divs
965 if repo[b].rev() in anc or b == target]
965 if repo[b].rev() in anc or b == target]
966 bookmarks.deletedivergent(repo, deletefrom, mark)
966 bookmarks.deletedivergent(repo, deletefrom, mark)
967 if bookmarks.validdest(repo, bmctx, repo[target]):
967 if bookmarks.validdest(repo, bmctx, repo[target]):
968 ui.status(_("moving bookmark '%s' forward from %s\n") %
968 ui.status(_("moving bookmark '%s' forward from %s\n") %
969 (mark, short(bmctx.node())))
969 (mark, short(bmctx.node())))
970 return
970 return
971 raise error.Abort(_("bookmark '%s' already exists "
971 raise error.Abort(_("bookmark '%s' already exists "
972 "(use -f to force)") % mark)
972 "(use -f to force)") % mark)
973 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
973 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
974 and not force):
974 and not force):
975 raise error.Abort(
975 raise error.Abort(
976 _("a bookmark cannot have the name of an existing branch"))
976 _("a bookmark cannot have the name of an existing branch"))
977
977
978 if delete and rename:
978 if delete and rename:
979 raise error.Abort(_("--delete and --rename are incompatible"))
979 raise error.Abort(_("--delete and --rename are incompatible"))
980 if delete and rev:
980 if delete and rev:
981 raise error.Abort(_("--rev is incompatible with --delete"))
981 raise error.Abort(_("--rev is incompatible with --delete"))
982 if rename and rev:
982 if rename and rev:
983 raise error.Abort(_("--rev is incompatible with --rename"))
983 raise error.Abort(_("--rev is incompatible with --rename"))
984 if not names and (delete or rev):
984 if not names and (delete or rev):
985 raise error.Abort(_("bookmark name required"))
985 raise error.Abort(_("bookmark name required"))
986
986
987 if delete or rename or names or inactive:
987 if delete or rename or names or inactive:
988 wlock = lock = tr = None
988 wlock = lock = tr = None
989 try:
989 try:
990 wlock = repo.wlock()
990 wlock = repo.wlock()
991 lock = repo.lock()
991 lock = repo.lock()
992 cur = repo.changectx('.').node()
992 cur = repo.changectx('.').node()
993 marks = repo._bookmarks
993 marks = repo._bookmarks
994 if delete:
994 if delete:
995 tr = repo.transaction('bookmark')
995 tr = repo.transaction('bookmark')
996 for mark in names:
996 for mark in names:
997 if mark not in marks:
997 if mark not in marks:
998 raise error.Abort(_("bookmark '%s' does not exist") %
998 raise error.Abort(_("bookmark '%s' does not exist") %
999 mark)
999 mark)
1000 if mark == repo._activebookmark:
1000 if mark == repo._activebookmark:
1001 bookmarks.deactivate(repo)
1001 bookmarks.deactivate(repo)
1002 del marks[mark]
1002 del marks[mark]
1003
1003
1004 elif rename:
1004 elif rename:
1005 tr = repo.transaction('bookmark')
1005 tr = repo.transaction('bookmark')
1006 if not names:
1006 if not names:
1007 raise error.Abort(_("new bookmark name required"))
1007 raise error.Abort(_("new bookmark name required"))
1008 elif len(names) > 1:
1008 elif len(names) > 1:
1009 raise error.Abort(_("only one new bookmark name allowed"))
1009 raise error.Abort(_("only one new bookmark name allowed"))
1010 mark = checkformat(names[0])
1010 mark = checkformat(names[0])
1011 if rename not in marks:
1011 if rename not in marks:
1012 raise error.Abort(_("bookmark '%s' does not exist")
1012 raise error.Abort(_("bookmark '%s' does not exist")
1013 % rename)
1013 % rename)
1014 checkconflict(repo, mark, cur, force)
1014 checkconflict(repo, mark, cur, force)
1015 marks[mark] = marks[rename]
1015 marks[mark] = marks[rename]
1016 if repo._activebookmark == rename and not inactive:
1016 if repo._activebookmark == rename and not inactive:
1017 bookmarks.activate(repo, mark)
1017 bookmarks.activate(repo, mark)
1018 del marks[rename]
1018 del marks[rename]
1019 elif names:
1019 elif names:
1020 tr = repo.transaction('bookmark')
1020 tr = repo.transaction('bookmark')
1021 newact = None
1021 newact = None
1022 for mark in names:
1022 for mark in names:
1023 mark = checkformat(mark)
1023 mark = checkformat(mark)
1024 if newact is None:
1024 if newact is None:
1025 newact = mark
1025 newact = mark
1026 if inactive and mark == repo._activebookmark:
1026 if inactive and mark == repo._activebookmark:
1027 bookmarks.deactivate(repo)
1027 bookmarks.deactivate(repo)
1028 return
1028 return
1029 tgt = cur
1029 tgt = cur
1030 if rev:
1030 if rev:
1031 tgt = scmutil.revsingle(repo, rev).node()
1031 tgt = scmutil.revsingle(repo, rev).node()
1032 checkconflict(repo, mark, cur, force, tgt)
1032 checkconflict(repo, mark, cur, force, tgt)
1033 marks[mark] = tgt
1033 marks[mark] = tgt
1034 if not inactive and cur == marks[newact] and not rev:
1034 if not inactive and cur == marks[newact] and not rev:
1035 bookmarks.activate(repo, newact)
1035 bookmarks.activate(repo, newact)
1036 elif cur != tgt and newact == repo._activebookmark:
1036 elif cur != tgt and newact == repo._activebookmark:
1037 bookmarks.deactivate(repo)
1037 bookmarks.deactivate(repo)
1038 elif inactive:
1038 elif inactive:
1039 if len(marks) == 0:
1039 if len(marks) == 0:
1040 ui.status(_("no bookmarks set\n"))
1040 ui.status(_("no bookmarks set\n"))
1041 elif not repo._activebookmark:
1041 elif not repo._activebookmark:
1042 ui.status(_("no active bookmark\n"))
1042 ui.status(_("no active bookmark\n"))
1043 else:
1043 else:
1044 bookmarks.deactivate(repo)
1044 bookmarks.deactivate(repo)
1045 if tr is not None:
1045 if tr is not None:
1046 marks.recordchange(tr)
1046 marks.recordchange(tr)
1047 tr.close()
1047 tr.close()
1048 finally:
1048 finally:
1049 lockmod.release(tr, lock, wlock)
1049 lockmod.release(tr, lock, wlock)
1050 else: # show bookmarks
1050 else: # show bookmarks
1051 fm = ui.formatter('bookmarks', opts)
1051 fm = ui.formatter('bookmarks', opts)
1052 hexfn = fm.hexfunc
1052 hexfn = fm.hexfunc
1053 marks = repo._bookmarks
1053 marks = repo._bookmarks
1054 if len(marks) == 0 and not fm:
1054 if len(marks) == 0 and not fm:
1055 ui.status(_("no bookmarks set\n"))
1055 ui.status(_("no bookmarks set\n"))
1056 for bmark, n in sorted(marks.iteritems()):
1056 for bmark, n in sorted(marks.iteritems()):
1057 active = repo._activebookmark
1057 active = repo._activebookmark
1058 if bmark == active:
1058 if bmark == active:
1059 prefix, label = '*', activebookmarklabel
1059 prefix, label = '*', activebookmarklabel
1060 else:
1060 else:
1061 prefix, label = ' ', ''
1061 prefix, label = ' ', ''
1062
1062
1063 fm.startitem()
1063 fm.startitem()
1064 if not ui.quiet:
1064 if not ui.quiet:
1065 fm.plain(' %s ' % prefix, label=label)
1065 fm.plain(' %s ' % prefix, label=label)
1066 fm.write('bookmark', '%s', bmark, label=label)
1066 fm.write('bookmark', '%s', bmark, label=label)
1067 pad = " " * (25 - encoding.colwidth(bmark))
1067 pad = " " * (25 - encoding.colwidth(bmark))
1068 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1068 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1069 repo.changelog.rev(n), hexfn(n), label=label)
1069 repo.changelog.rev(n), hexfn(n), label=label)
1070 fm.data(active=(bmark == active))
1070 fm.data(active=(bmark == active))
1071 fm.plain('\n')
1071 fm.plain('\n')
1072 fm.end()
1072 fm.end()
1073
1073
1074 @command('branch',
1074 @command('branch',
1075 [('f', 'force', None,
1075 [('f', 'force', None,
1076 _('set branch name even if it shadows an existing branch')),
1076 _('set branch name even if it shadows an existing branch')),
1077 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1077 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1078 _('[-fC] [NAME]'))
1078 _('[-fC] [NAME]'))
1079 def branch(ui, repo, label=None, **opts):
1079 def branch(ui, repo, label=None, **opts):
1080 """set or show the current branch name
1080 """set or show the current branch name
1081
1081
1082 .. note::
1082 .. note::
1083
1083
1084 Branch names are permanent and global. Use :hg:`bookmark` to create a
1084 Branch names are permanent and global. Use :hg:`bookmark` to create a
1085 light-weight bookmark instead. See :hg:`help glossary` for more
1085 light-weight bookmark instead. See :hg:`help glossary` for more
1086 information about named branches and bookmarks.
1086 information about named branches and bookmarks.
1087
1087
1088 With no argument, show the current branch name. With one argument,
1088 With no argument, show the current branch name. With one argument,
1089 set the working directory branch name (the branch will not exist
1089 set the working directory branch name (the branch will not exist
1090 in the repository until the next commit). Standard practice
1090 in the repository until the next commit). Standard practice
1091 recommends that primary development take place on the 'default'
1091 recommends that primary development take place on the 'default'
1092 branch.
1092 branch.
1093
1093
1094 Unless -f/--force is specified, branch will not let you set a
1094 Unless -f/--force is specified, branch will not let you set a
1095 branch name that already exists.
1095 branch name that already exists.
1096
1096
1097 Use -C/--clean to reset the working directory branch to that of
1097 Use -C/--clean to reset the working directory branch to that of
1098 the parent of the working directory, negating a previous branch
1098 the parent of the working directory, negating a previous branch
1099 change.
1099 change.
1100
1100
1101 Use the command :hg:`update` to switch to an existing branch. Use
1101 Use the command :hg:`update` to switch to an existing branch. Use
1102 :hg:`commit --close-branch` to mark this branch head as closed.
1102 :hg:`commit --close-branch` to mark this branch head as closed.
1103 When all heads of the branch are closed, the branch will be
1103 When all heads of the branch are closed, the branch will be
1104 considered closed.
1104 considered closed.
1105
1105
1106 Returns 0 on success.
1106 Returns 0 on success.
1107 """
1107 """
1108 if label:
1108 if label:
1109 label = label.strip()
1109 label = label.strip()
1110
1110
1111 if not opts.get('clean') and not label:
1111 if not opts.get('clean') and not label:
1112 ui.write("%s\n" % repo.dirstate.branch())
1112 ui.write("%s\n" % repo.dirstate.branch())
1113 return
1113 return
1114
1114
1115 wlock = repo.wlock()
1115 wlock = repo.wlock()
1116 try:
1116 try:
1117 if opts.get('clean'):
1117 if opts.get('clean'):
1118 label = repo[None].p1().branch()
1118 label = repo[None].p1().branch()
1119 repo.dirstate.setbranch(label)
1119 repo.dirstate.setbranch(label)
1120 ui.status(_('reset working directory to branch %s\n') % label)
1120 ui.status(_('reset working directory to branch %s\n') % label)
1121 elif label:
1121 elif label:
1122 if not opts.get('force') and label in repo.branchmap():
1122 if not opts.get('force') and label in repo.branchmap():
1123 if label not in [p.branch() for p in repo.parents()]:
1123 if label not in [p.branch() for p in repo.parents()]:
1124 raise error.Abort(_('a branch of the same name already'
1124 raise error.Abort(_('a branch of the same name already'
1125 ' exists'),
1125 ' exists'),
1126 # i18n: "it" refers to an existing branch
1126 # i18n: "it" refers to an existing branch
1127 hint=_("use 'hg update' to switch to it"))
1127 hint=_("use 'hg update' to switch to it"))
1128 scmutil.checknewlabel(repo, label, 'branch')
1128 scmutil.checknewlabel(repo, label, 'branch')
1129 repo.dirstate.setbranch(label)
1129 repo.dirstate.setbranch(label)
1130 ui.status(_('marked working directory as branch %s\n') % label)
1130 ui.status(_('marked working directory as branch %s\n') % label)
1131
1131
1132 # find any open named branches aside from default
1132 # find any open named branches aside from default
1133 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1133 others = [n for n, h, t, c in repo.branchmap().iterbranches()
1134 if n != "default" and not c]
1134 if n != "default" and not c]
1135 if not others:
1135 if not others:
1136 ui.status(_('(branches are permanent and global, '
1136 ui.status(_('(branches are permanent and global, '
1137 'did you want a bookmark?)\n'))
1137 'did you want a bookmark?)\n'))
1138 finally:
1138 finally:
1139 wlock.release()
1139 wlock.release()
1140
1140
1141 @command('branches',
1141 @command('branches',
1142 [('a', 'active', False,
1142 [('a', 'active', False,
1143 _('show only branches that have unmerged heads (DEPRECATED)')),
1143 _('show only branches that have unmerged heads (DEPRECATED)')),
1144 ('c', 'closed', False, _('show normal and closed branches')),
1144 ('c', 'closed', False, _('show normal and closed branches')),
1145 ] + formatteropts,
1145 ] + formatteropts,
1146 _('[-ac]'))
1146 _('[-ac]'))
1147 def branches(ui, repo, active=False, closed=False, **opts):
1147 def branches(ui, repo, active=False, closed=False, **opts):
1148 """list repository named branches
1148 """list repository named branches
1149
1149
1150 List the repository's named branches, indicating which ones are
1150 List the repository's named branches, indicating which ones are
1151 inactive. If -c/--closed is specified, also list branches which have
1151 inactive. If -c/--closed is specified, also list branches which have
1152 been marked closed (see :hg:`commit --close-branch`).
1152 been marked closed (see :hg:`commit --close-branch`).
1153
1153
1154 Use the command :hg:`update` to switch to an existing branch.
1154 Use the command :hg:`update` to switch to an existing branch.
1155
1155
1156 Returns 0.
1156 Returns 0.
1157 """
1157 """
1158
1158
1159 fm = ui.formatter('branches', opts)
1159 fm = ui.formatter('branches', opts)
1160 hexfunc = fm.hexfunc
1160 hexfunc = fm.hexfunc
1161
1161
1162 allheads = set(repo.heads())
1162 allheads = set(repo.heads())
1163 branches = []
1163 branches = []
1164 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1164 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1165 isactive = not isclosed and bool(set(heads) & allheads)
1165 isactive = not isclosed and bool(set(heads) & allheads)
1166 branches.append((tag, repo[tip], isactive, not isclosed))
1166 branches.append((tag, repo[tip], isactive, not isclosed))
1167 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1167 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1168 reverse=True)
1168 reverse=True)
1169
1169
1170 for tag, ctx, isactive, isopen in branches:
1170 for tag, ctx, isactive, isopen in branches:
1171 if active and not isactive:
1171 if active and not isactive:
1172 continue
1172 continue
1173 if isactive:
1173 if isactive:
1174 label = 'branches.active'
1174 label = 'branches.active'
1175 notice = ''
1175 notice = ''
1176 elif not isopen:
1176 elif not isopen:
1177 if not closed:
1177 if not closed:
1178 continue
1178 continue
1179 label = 'branches.closed'
1179 label = 'branches.closed'
1180 notice = _(' (closed)')
1180 notice = _(' (closed)')
1181 else:
1181 else:
1182 label = 'branches.inactive'
1182 label = 'branches.inactive'
1183 notice = _(' (inactive)')
1183 notice = _(' (inactive)')
1184 current = (tag == repo.dirstate.branch())
1184 current = (tag == repo.dirstate.branch())
1185 if current:
1185 if current:
1186 label = 'branches.current'
1186 label = 'branches.current'
1187
1187
1188 fm.startitem()
1188 fm.startitem()
1189 fm.write('branch', '%s', tag, label=label)
1189 fm.write('branch', '%s', tag, label=label)
1190 rev = ctx.rev()
1190 rev = ctx.rev()
1191 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1191 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1192 fmt = ' ' * padsize + ' %d:%s'
1192 fmt = ' ' * padsize + ' %d:%s'
1193 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1193 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1194 label='log.changeset changeset.%s' % ctx.phasestr())
1194 label='log.changeset changeset.%s' % ctx.phasestr())
1195 fm.data(active=isactive, closed=not isopen, current=current)
1195 fm.data(active=isactive, closed=not isopen, current=current)
1196 if not ui.quiet:
1196 if not ui.quiet:
1197 fm.plain(notice)
1197 fm.plain(notice)
1198 fm.plain('\n')
1198 fm.plain('\n')
1199 fm.end()
1199 fm.end()
1200
1200
1201 @command('bundle',
1201 @command('bundle',
1202 [('f', 'force', None, _('run even when the destination is unrelated')),
1202 [('f', 'force', None, _('run even when the destination is unrelated')),
1203 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1203 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1204 _('REV')),
1204 _('REV')),
1205 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1205 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1206 _('BRANCH')),
1206 _('BRANCH')),
1207 ('', 'base', [],
1207 ('', 'base', [],
1208 _('a base changeset assumed to be available at the destination'),
1208 _('a base changeset assumed to be available at the destination'),
1209 _('REV')),
1209 _('REV')),
1210 ('a', 'all', None, _('bundle all changesets in the repository')),
1210 ('a', 'all', None, _('bundle all changesets in the repository')),
1211 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1211 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1212 ] + remoteopts,
1212 ] + remoteopts,
1213 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1213 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1214 def bundle(ui, repo, fname, dest=None, **opts):
1214 def bundle(ui, repo, fname, dest=None, **opts):
1215 """create a changegroup file
1215 """create a changegroup file
1216
1216
1217 Generate a compressed changegroup file collecting changesets not
1217 Generate a compressed changegroup file collecting changesets not
1218 known to be in another repository.
1218 known to be in another repository.
1219
1219
1220 If you omit the destination repository, then hg assumes the
1220 If you omit the destination repository, then hg assumes the
1221 destination will have all the nodes you specify with --base
1221 destination will have all the nodes you specify with --base
1222 parameters. To create a bundle containing all changesets, use
1222 parameters. To create a bundle containing all changesets, use
1223 -a/--all (or --base null).
1223 -a/--all (or --base null).
1224
1224
1225 You can change bundle format with the -t/--type option. You can
1225 You can change bundle format with the -t/--type option. You can
1226 specify a compression, a bundle version or both using a dash
1226 specify a compression, a bundle version or both using a dash
1227 (comp-version). The available compression methods are: none, bzip2,
1227 (comp-version). The available compression methods are: none, bzip2,
1228 and gzip (by default, bundles are compressed using bzip2). The
1228 and gzip (by default, bundles are compressed using bzip2). The
1229 available format are: v1, v2 (default to most suitable).
1229 available format are: v1, v2 (default to most suitable).
1230
1230
1231 The bundle file can then be transferred using conventional means
1231 The bundle file can then be transferred using conventional means
1232 and applied to another repository with the unbundle or pull
1232 and applied to another repository with the unbundle or pull
1233 command. This is useful when direct push and pull are not
1233 command. This is useful when direct push and pull are not
1234 available or when exporting an entire repository is undesirable.
1234 available or when exporting an entire repository is undesirable.
1235
1235
1236 Applying bundles preserves all changeset contents including
1236 Applying bundles preserves all changeset contents including
1237 permissions, copy/rename information, and revision history.
1237 permissions, copy/rename information, and revision history.
1238
1238
1239 Returns 0 on success, 1 if no changes found.
1239 Returns 0 on success, 1 if no changes found.
1240 """
1240 """
1241 revs = None
1241 revs = None
1242 if 'rev' in opts:
1242 if 'rev' in opts:
1243 revs = scmutil.revrange(repo, opts['rev'])
1243 revs = scmutil.revrange(repo, opts['rev'])
1244
1244
1245 bundletype = opts.get('type', 'bzip2').lower()
1245 bundletype = opts.get('type', 'bzip2').lower()
1246 try:
1246 try:
1247 bcompression, cgversion, params = exchange.parsebundlespec(
1247 bcompression, cgversion, params = exchange.parsebundlespec(
1248 repo, bundletype, strict=False)
1248 repo, bundletype, strict=False)
1249 except error.UnsupportedBundleSpecification as e:
1249 except error.UnsupportedBundleSpecification as e:
1250 raise error.Abort(str(e),
1250 raise error.Abort(str(e),
1251 hint=_('see "hg help bundle" for supported '
1251 hint=_('see "hg help bundle" for supported '
1252 'values for --type'))
1252 'values for --type'))
1253
1253
1254 # Packed bundles are a pseudo bundle format for now.
1254 # Packed bundles are a pseudo bundle format for now.
1255 if cgversion == 's1':
1255 if cgversion == 's1':
1256 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1256 raise error.Abort(_('packed bundles cannot be produced by "hg bundle"'),
1257 hint=_('use "hg debugcreatestreamclonebundle"'))
1257 hint=_('use "hg debugcreatestreamclonebundle"'))
1258
1258
1259 if opts.get('all'):
1259 if opts.get('all'):
1260 base = ['null']
1260 base = ['null']
1261 else:
1261 else:
1262 base = scmutil.revrange(repo, opts.get('base'))
1262 base = scmutil.revrange(repo, opts.get('base'))
1263 # TODO: get desired bundlecaps from command line.
1263 # TODO: get desired bundlecaps from command line.
1264 bundlecaps = None
1264 bundlecaps = None
1265 if base:
1265 if base:
1266 if dest:
1266 if dest:
1267 raise error.Abort(_("--base is incompatible with specifying "
1267 raise error.Abort(_("--base is incompatible with specifying "
1268 "a destination"))
1268 "a destination"))
1269 common = [repo.lookup(rev) for rev in base]
1269 common = [repo.lookup(rev) for rev in base]
1270 heads = revs and map(repo.lookup, revs) or revs
1270 heads = revs and map(repo.lookup, revs) or revs
1271 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1271 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1272 common=common, bundlecaps=bundlecaps,
1272 common=common, bundlecaps=bundlecaps,
1273 version=cgversion)
1273 version=cgversion)
1274 outgoing = None
1274 outgoing = None
1275 else:
1275 else:
1276 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1276 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1277 dest, branches = hg.parseurl(dest, opts.get('branch'))
1277 dest, branches = hg.parseurl(dest, opts.get('branch'))
1278 other = hg.peer(repo, opts, dest)
1278 other = hg.peer(repo, opts, dest)
1279 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1279 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1280 heads = revs and map(repo.lookup, revs) or revs
1280 heads = revs and map(repo.lookup, revs) or revs
1281 outgoing = discovery.findcommonoutgoing(repo, other,
1281 outgoing = discovery.findcommonoutgoing(repo, other,
1282 onlyheads=heads,
1282 onlyheads=heads,
1283 force=opts.get('force'),
1283 force=opts.get('force'),
1284 portable=True)
1284 portable=True)
1285 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1285 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1286 bundlecaps, version=cgversion)
1286 bundlecaps, version=cgversion)
1287 if not cg:
1287 if not cg:
1288 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1288 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1289 return 1
1289 return 1
1290
1290
1291 if cgversion == '01': #bundle1
1291 if cgversion == '01': #bundle1
1292 if bcompression is None:
1292 if bcompression is None:
1293 bcompression = 'UN'
1293 bcompression = 'UN'
1294 bversion = 'HG10' + bcompression
1294 bversion = 'HG10' + bcompression
1295 bcompression = None
1295 bcompression = None
1296 else:
1296 else:
1297 assert cgversion == '02'
1297 assert cgversion == '02'
1298 bversion = 'HG20'
1298 bversion = 'HG20'
1299
1299
1300
1300
1301 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1301 changegroup.writebundle(ui, cg, fname, bversion, compression=bcompression)
1302
1302
1303 @command('cat',
1303 @command('cat',
1304 [('o', 'output', '',
1304 [('o', 'output', '',
1305 _('print output to file with formatted name'), _('FORMAT')),
1305 _('print output to file with formatted name'), _('FORMAT')),
1306 ('r', 'rev', '', _('print the given revision'), _('REV')),
1306 ('r', 'rev', '', _('print the given revision'), _('REV')),
1307 ('', 'decode', None, _('apply any matching decode filter')),
1307 ('', 'decode', None, _('apply any matching decode filter')),
1308 ] + walkopts,
1308 ] + walkopts,
1309 _('[OPTION]... FILE...'),
1309 _('[OPTION]... FILE...'),
1310 inferrepo=True)
1310 inferrepo=True)
1311 def cat(ui, repo, file1, *pats, **opts):
1311 def cat(ui, repo, file1, *pats, **opts):
1312 """output the current or given revision of files
1312 """output the current or given revision of files
1313
1313
1314 Print the specified files as they were at the given revision. If
1314 Print the specified files as they were at the given revision. If
1315 no revision is given, the parent of the working directory is used.
1315 no revision is given, the parent of the working directory is used.
1316
1316
1317 Output may be to a file, in which case the name of the file is
1317 Output may be to a file, in which case the name of the file is
1318 given using a format string. The formatting rules as follows:
1318 given using a format string. The formatting rules as follows:
1319
1319
1320 :``%%``: literal "%" character
1320 :``%%``: literal "%" character
1321 :``%s``: basename of file being printed
1321 :``%s``: basename of file being printed
1322 :``%d``: dirname of file being printed, or '.' if in repository root
1322 :``%d``: dirname of file being printed, or '.' if in repository root
1323 :``%p``: root-relative path name of file being printed
1323 :``%p``: root-relative path name of file being printed
1324 :``%H``: changeset hash (40 hexadecimal digits)
1324 :``%H``: changeset hash (40 hexadecimal digits)
1325 :``%R``: changeset revision number
1325 :``%R``: changeset revision number
1326 :``%h``: short-form changeset hash (12 hexadecimal digits)
1326 :``%h``: short-form changeset hash (12 hexadecimal digits)
1327 :``%r``: zero-padded changeset revision number
1327 :``%r``: zero-padded changeset revision number
1328 :``%b``: basename of the exporting repository
1328 :``%b``: basename of the exporting repository
1329
1329
1330 Returns 0 on success.
1330 Returns 0 on success.
1331 """
1331 """
1332 ctx = scmutil.revsingle(repo, opts.get('rev'))
1332 ctx = scmutil.revsingle(repo, opts.get('rev'))
1333 m = scmutil.match(ctx, (file1,) + pats, opts)
1333 m = scmutil.match(ctx, (file1,) + pats, opts)
1334
1334
1335 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1335 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1336
1336
1337 @command('^clone',
1337 @command('^clone',
1338 [('U', 'noupdate', None, _('the clone will include an empty working '
1338 [('U', 'noupdate', None, _('the clone will include an empty working '
1339 'directory (only a repository)')),
1339 'directory (only a repository)')),
1340 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1340 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1341 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1341 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1342 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1342 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1343 ('', 'pull', None, _('use pull protocol to copy metadata')),
1343 ('', 'pull', None, _('use pull protocol to copy metadata')),
1344 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1344 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1345 ] + remoteopts,
1345 ] + remoteopts,
1346 _('[OPTION]... SOURCE [DEST]'),
1346 _('[OPTION]... SOURCE [DEST]'),
1347 norepo=True)
1347 norepo=True)
1348 def clone(ui, source, dest=None, **opts):
1348 def clone(ui, source, dest=None, **opts):
1349 """make a copy of an existing repository
1349 """make a copy of an existing repository
1350
1350
1351 Create a copy of an existing repository in a new directory.
1351 Create a copy of an existing repository in a new directory.
1352
1352
1353 If no destination directory name is specified, it defaults to the
1353 If no destination directory name is specified, it defaults to the
1354 basename of the source.
1354 basename of the source.
1355
1355
1356 The location of the source is added to the new repository's
1356 The location of the source is added to the new repository's
1357 ``.hg/hgrc`` file, as the default to be used for future pulls.
1357 ``.hg/hgrc`` file, as the default to be used for future pulls.
1358
1358
1359 Only local paths and ``ssh://`` URLs are supported as
1359 Only local paths and ``ssh://`` URLs are supported as
1360 destinations. For ``ssh://`` destinations, no working directory or
1360 destinations. For ``ssh://`` destinations, no working directory or
1361 ``.hg/hgrc`` will be created on the remote side.
1361 ``.hg/hgrc`` will be created on the remote side.
1362
1362
1363 To pull only a subset of changesets, specify one or more revisions
1363 To pull only a subset of changesets, specify one or more revisions
1364 identifiers with -r/--rev or branches with -b/--branch. The
1364 identifiers with -r/--rev or branches with -b/--branch. The
1365 resulting clone will contain only the specified changesets and
1365 resulting clone will contain only the specified changesets and
1366 their ancestors. These options (or 'clone src#rev dest') imply
1366 their ancestors. These options (or 'clone src#rev dest') imply
1367 --pull, even for local source repositories. Note that specifying a
1367 --pull, even for local source repositories. Note that specifying a
1368 tag will include the tagged changeset but not the changeset
1368 tag will include the tagged changeset but not the changeset
1369 containing the tag.
1369 containing the tag.
1370
1370
1371 If the source repository has a bookmark called '@' set, that
1371 If the source repository has a bookmark called '@' set, that
1372 revision will be checked out in the new repository by default.
1372 revision will be checked out in the new repository by default.
1373
1373
1374 To check out a particular version, use -u/--update, or
1374 To check out a particular version, use -u/--update, or
1375 -U/--noupdate to create a clone with no working directory.
1375 -U/--noupdate to create a clone with no working directory.
1376
1376
1377 .. container:: verbose
1377 .. container:: verbose
1378
1378
1379 For efficiency, hardlinks are used for cloning whenever the
1379 For efficiency, hardlinks are used for cloning whenever the
1380 source and destination are on the same filesystem (note this
1380 source and destination are on the same filesystem (note this
1381 applies only to the repository data, not to the working
1381 applies only to the repository data, not to the working
1382 directory). Some filesystems, such as AFS, implement hardlinking
1382 directory). Some filesystems, such as AFS, implement hardlinking
1383 incorrectly, but do not report errors. In these cases, use the
1383 incorrectly, but do not report errors. In these cases, use the
1384 --pull option to avoid hardlinking.
1384 --pull option to avoid hardlinking.
1385
1385
1386 In some cases, you can clone repositories and the working
1386 In some cases, you can clone repositories and the working
1387 directory using full hardlinks with ::
1387 directory using full hardlinks with ::
1388
1388
1389 $ cp -al REPO REPOCLONE
1389 $ cp -al REPO REPOCLONE
1390
1390
1391 This is the fastest way to clone, but it is not always safe. The
1391 This is the fastest way to clone, but it is not always safe. The
1392 operation is not atomic (making sure REPO is not modified during
1392 operation is not atomic (making sure REPO is not modified during
1393 the operation is up to you) and you have to make sure your
1393 the operation is up to you) and you have to make sure your
1394 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1394 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1395 so). Also, this is not compatible with certain extensions that
1395 so). Also, this is not compatible with certain extensions that
1396 place their metadata under the .hg directory, such as mq.
1396 place their metadata under the .hg directory, such as mq.
1397
1397
1398 Mercurial will update the working directory to the first applicable
1398 Mercurial will update the working directory to the first applicable
1399 revision from this list:
1399 revision from this list:
1400
1400
1401 a) null if -U or the source repository has no changesets
1401 a) null if -U or the source repository has no changesets
1402 b) if -u . and the source repository is local, the first parent of
1402 b) if -u . and the source repository is local, the first parent of
1403 the source repository's working directory
1403 the source repository's working directory
1404 c) the changeset specified with -u (if a branch name, this means the
1404 c) the changeset specified with -u (if a branch name, this means the
1405 latest head of that branch)
1405 latest head of that branch)
1406 d) the changeset specified with -r
1406 d) the changeset specified with -r
1407 e) the tipmost head specified with -b
1407 e) the tipmost head specified with -b
1408 f) the tipmost head specified with the url#branch source syntax
1408 f) the tipmost head specified with the url#branch source syntax
1409 g) the revision marked with the '@' bookmark, if present
1409 g) the revision marked with the '@' bookmark, if present
1410 h) the tipmost head of the default branch
1410 h) the tipmost head of the default branch
1411 i) tip
1411 i) tip
1412
1412
1413 Examples:
1413 Examples:
1414
1414
1415 - clone a remote repository to a new directory named hg/::
1415 - clone a remote repository to a new directory named hg/::
1416
1416
1417 hg clone http://selenic.com/hg
1417 hg clone http://selenic.com/hg
1418
1418
1419 - create a lightweight local clone::
1419 - create a lightweight local clone::
1420
1420
1421 hg clone project/ project-feature/
1421 hg clone project/ project-feature/
1422
1422
1423 - clone from an absolute path on an ssh server (note double-slash)::
1423 - clone from an absolute path on an ssh server (note double-slash)::
1424
1424
1425 hg clone ssh://user@server//home/projects/alpha/
1425 hg clone ssh://user@server//home/projects/alpha/
1426
1426
1427 - do a high-speed clone over a LAN while checking out a
1427 - do a high-speed clone over a LAN while checking out a
1428 specified version::
1428 specified version::
1429
1429
1430 hg clone --uncompressed http://server/repo -u 1.5
1430 hg clone --uncompressed http://server/repo -u 1.5
1431
1431
1432 - create a repository without changesets after a particular revision::
1432 - create a repository without changesets after a particular revision::
1433
1433
1434 hg clone -r 04e544 experimental/ good/
1434 hg clone -r 04e544 experimental/ good/
1435
1435
1436 - clone (and track) a particular named branch::
1436 - clone (and track) a particular named branch::
1437
1437
1438 hg clone http://selenic.com/hg#stable
1438 hg clone http://selenic.com/hg#stable
1439
1439
1440 See :hg:`help urls` for details on specifying URLs.
1440 See :hg:`help urls` for details on specifying URLs.
1441
1441
1442 Returns 0 on success.
1442 Returns 0 on success.
1443 """
1443 """
1444 if opts.get('noupdate') and opts.get('updaterev'):
1444 if opts.get('noupdate') and opts.get('updaterev'):
1445 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1445 raise error.Abort(_("cannot specify both --noupdate and --updaterev"))
1446
1446
1447 r = hg.clone(ui, opts, source, dest,
1447 r = hg.clone(ui, opts, source, dest,
1448 pull=opts.get('pull'),
1448 pull=opts.get('pull'),
1449 stream=opts.get('uncompressed'),
1449 stream=opts.get('uncompressed'),
1450 rev=opts.get('rev'),
1450 rev=opts.get('rev'),
1451 update=opts.get('updaterev') or not opts.get('noupdate'),
1451 update=opts.get('updaterev') or not opts.get('noupdate'),
1452 branch=opts.get('branch'),
1452 branch=opts.get('branch'),
1453 shareopts=opts.get('shareopts'))
1453 shareopts=opts.get('shareopts'))
1454
1454
1455 return r is None
1455 return r is None
1456
1456
1457 @command('^commit|ci',
1457 @command('^commit|ci',
1458 [('A', 'addremove', None,
1458 [('A', 'addremove', None,
1459 _('mark new/missing files as added/removed before committing')),
1459 _('mark new/missing files as added/removed before committing')),
1460 ('', 'close-branch', None,
1460 ('', 'close-branch', None,
1461 _('mark a branch head as closed')),
1461 _('mark a branch head as closed')),
1462 ('', 'amend', None, _('amend the parent of the working directory')),
1462 ('', 'amend', None, _('amend the parent of the working directory')),
1463 ('s', 'secret', None, _('use the secret phase for committing')),
1463 ('s', 'secret', None, _('use the secret phase for committing')),
1464 ('e', 'edit', None, _('invoke editor on commit messages')),
1464 ('e', 'edit', None, _('invoke editor on commit messages')),
1465 ('i', 'interactive', None, _('use interactive mode')),
1465 ('i', 'interactive', None, _('use interactive mode')),
1466 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1466 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1467 _('[OPTION]... [FILE]...'),
1467 _('[OPTION]... [FILE]...'),
1468 inferrepo=True)
1468 inferrepo=True)
1469 def commit(ui, repo, *pats, **opts):
1469 def commit(ui, repo, *pats, **opts):
1470 """commit the specified files or all outstanding changes
1470 """commit the specified files or all outstanding changes
1471
1471
1472 Commit changes to the given files into the repository. Unlike a
1472 Commit changes to the given files into the repository. Unlike a
1473 centralized SCM, this operation is a local operation. See
1473 centralized SCM, this operation is a local operation. See
1474 :hg:`push` for a way to actively distribute your changes.
1474 :hg:`push` for a way to actively distribute your changes.
1475
1475
1476 If a list of files is omitted, all changes reported by :hg:`status`
1476 If a list of files is omitted, all changes reported by :hg:`status`
1477 will be committed.
1477 will be committed.
1478
1478
1479 If you are committing the result of a merge, do not provide any
1479 If you are committing the result of a merge, do not provide any
1480 filenames or -I/-X filters.
1480 filenames or -I/-X filters.
1481
1481
1482 If no commit message is specified, Mercurial starts your
1482 If no commit message is specified, Mercurial starts your
1483 configured editor where you can enter a message. In case your
1483 configured editor where you can enter a message. In case your
1484 commit fails, you will find a backup of your message in
1484 commit fails, you will find a backup of your message in
1485 ``.hg/last-message.txt``.
1485 ``.hg/last-message.txt``.
1486
1486
1487 The --close-branch flag can be used to mark the current branch
1487 The --close-branch flag can be used to mark the current branch
1488 head closed. When all heads of a branch are closed, the branch
1488 head closed. When all heads of a branch are closed, the branch
1489 will be considered closed and no longer listed.
1489 will be considered closed and no longer listed.
1490
1490
1491 The --amend flag can be used to amend the parent of the
1491 The --amend flag can be used to amend the parent of the
1492 working directory with a new commit that contains the changes
1492 working directory with a new commit that contains the changes
1493 in the parent in addition to those currently reported by :hg:`status`,
1493 in the parent in addition to those currently reported by :hg:`status`,
1494 if there are any. The old commit is stored in a backup bundle in
1494 if there are any. The old commit is stored in a backup bundle in
1495 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1495 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1496 on how to restore it).
1496 on how to restore it).
1497
1497
1498 Message, user and date are taken from the amended commit unless
1498 Message, user and date are taken from the amended commit unless
1499 specified. When a message isn't specified on the command line,
1499 specified. When a message isn't specified on the command line,
1500 the editor will open with the message of the amended commit.
1500 the editor will open with the message of the amended commit.
1501
1501
1502 It is not possible to amend public changesets (see :hg:`help phases`)
1502 It is not possible to amend public changesets (see :hg:`help phases`)
1503 or changesets that have children.
1503 or changesets that have children.
1504
1504
1505 See :hg:`help dates` for a list of formats valid for -d/--date.
1505 See :hg:`help dates` for a list of formats valid for -d/--date.
1506
1506
1507 Returns 0 on success, 1 if nothing changed.
1507 Returns 0 on success, 1 if nothing changed.
1508 """
1508 """
1509 if opts.get('interactive'):
1509 if opts.get('interactive'):
1510 opts.pop('interactive')
1510 opts.pop('interactive')
1511 cmdutil.dorecord(ui, repo, commit, None, False,
1511 cmdutil.dorecord(ui, repo, commit, None, False,
1512 cmdutil.recordfilter, *pats, **opts)
1512 cmdutil.recordfilter, *pats, **opts)
1513 return
1513 return
1514
1514
1515 if opts.get('subrepos'):
1515 if opts.get('subrepos'):
1516 if opts.get('amend'):
1516 if opts.get('amend'):
1517 raise error.Abort(_('cannot amend with --subrepos'))
1517 raise error.Abort(_('cannot amend with --subrepos'))
1518 # Let --subrepos on the command line override config setting.
1518 # Let --subrepos on the command line override config setting.
1519 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1519 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1520
1520
1521 cmdutil.checkunfinished(repo, commit=True)
1521 cmdutil.checkunfinished(repo, commit=True)
1522
1522
1523 branch = repo[None].branch()
1523 branch = repo[None].branch()
1524 bheads = repo.branchheads(branch)
1524 bheads = repo.branchheads(branch)
1525
1525
1526 extra = {}
1526 extra = {}
1527 if opts.get('close_branch'):
1527 if opts.get('close_branch'):
1528 extra['close'] = 1
1528 extra['close'] = 1
1529
1529
1530 if not bheads:
1530 if not bheads:
1531 raise error.Abort(_('can only close branch heads'))
1531 raise error.Abort(_('can only close branch heads'))
1532 elif opts.get('amend'):
1532 elif opts.get('amend'):
1533 if repo.parents()[0].p1().branch() != branch and \
1533 if repo.parents()[0].p1().branch() != branch and \
1534 repo.parents()[0].p2().branch() != branch:
1534 repo.parents()[0].p2().branch() != branch:
1535 raise error.Abort(_('can only close branch heads'))
1535 raise error.Abort(_('can only close branch heads'))
1536
1536
1537 if opts.get('amend'):
1537 if opts.get('amend'):
1538 if ui.configbool('ui', 'commitsubrepos'):
1538 if ui.configbool('ui', 'commitsubrepos'):
1539 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1539 raise error.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1540
1540
1541 old = repo['.']
1541 old = repo['.']
1542 if not old.mutable():
1542 if not old.mutable():
1543 raise error.Abort(_('cannot amend public changesets'))
1543 raise error.Abort(_('cannot amend public changesets'))
1544 if len(repo[None].parents()) > 1:
1544 if len(repo[None].parents()) > 1:
1545 raise error.Abort(_('cannot amend while merging'))
1545 raise error.Abort(_('cannot amend while merging'))
1546 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1546 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1547 if not allowunstable and old.children():
1547 if not allowunstable and old.children():
1548 raise error.Abort(_('cannot amend changeset with children'))
1548 raise error.Abort(_('cannot amend changeset with children'))
1549
1549
1550 # commitfunc is used only for temporary amend commit by cmdutil.amend
1550 # commitfunc is used only for temporary amend commit by cmdutil.amend
1551 def commitfunc(ui, repo, message, match, opts):
1551 def commitfunc(ui, repo, message, match, opts):
1552 return repo.commit(message,
1552 return repo.commit(message,
1553 opts.get('user') or old.user(),
1553 opts.get('user') or old.user(),
1554 opts.get('date') or old.date(),
1554 opts.get('date') or old.date(),
1555 match,
1555 match,
1556 extra=extra)
1556 extra=extra)
1557
1557
1558 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1558 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1559 if node == old.node():
1559 if node == old.node():
1560 ui.status(_("nothing changed\n"))
1560 ui.status(_("nothing changed\n"))
1561 return 1
1561 return 1
1562 else:
1562 else:
1563 def commitfunc(ui, repo, message, match, opts):
1563 def commitfunc(ui, repo, message, match, opts):
1564 backup = ui.backupconfig('phases', 'new-commit')
1564 backup = ui.backupconfig('phases', 'new-commit')
1565 baseui = repo.baseui
1565 baseui = repo.baseui
1566 basebackup = baseui.backupconfig('phases', 'new-commit')
1566 basebackup = baseui.backupconfig('phases', 'new-commit')
1567 try:
1567 try:
1568 if opts.get('secret'):
1568 if opts.get('secret'):
1569 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1569 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1570 # Propagate to subrepos
1570 # Propagate to subrepos
1571 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1571 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1572
1572
1573 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1573 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1574 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1574 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1575 return repo.commit(message, opts.get('user'), opts.get('date'),
1575 return repo.commit(message, opts.get('user'), opts.get('date'),
1576 match,
1576 match,
1577 editor=editor,
1577 editor=editor,
1578 extra=extra)
1578 extra=extra)
1579 finally:
1579 finally:
1580 ui.restoreconfig(backup)
1580 ui.restoreconfig(backup)
1581 repo.baseui.restoreconfig(basebackup)
1581 repo.baseui.restoreconfig(basebackup)
1582
1582
1583
1583
1584 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1584 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1585
1585
1586 if not node:
1586 if not node:
1587 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1587 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1588 if stat[3]:
1588 if stat[3]:
1589 ui.status(_("nothing changed (%d missing files, see "
1589 ui.status(_("nothing changed (%d missing files, see "
1590 "'hg status')\n") % len(stat[3]))
1590 "'hg status')\n") % len(stat[3]))
1591 else:
1591 else:
1592 ui.status(_("nothing changed\n"))
1592 ui.status(_("nothing changed\n"))
1593 return 1
1593 return 1
1594
1594
1595 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1595 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1596
1596
1597 @command('config|showconfig|debugconfig',
1597 @command('config|showconfig|debugconfig',
1598 [('u', 'untrusted', None, _('show untrusted configuration options')),
1598 [('u', 'untrusted', None, _('show untrusted configuration options')),
1599 ('e', 'edit', None, _('edit user config')),
1599 ('e', 'edit', None, _('edit user config')),
1600 ('l', 'local', None, _('edit repository config')),
1600 ('l', 'local', None, _('edit repository config')),
1601 ('g', 'global', None, _('edit global config'))],
1601 ('g', 'global', None, _('edit global config'))],
1602 _('[-u] [NAME]...'),
1602 _('[-u] [NAME]...'),
1603 optionalrepo=True)
1603 optionalrepo=True)
1604 def config(ui, repo, *values, **opts):
1604 def config(ui, repo, *values, **opts):
1605 """show combined config settings from all hgrc files
1605 """show combined config settings from all hgrc files
1606
1606
1607 With no arguments, print names and values of all config items.
1607 With no arguments, print names and values of all config items.
1608
1608
1609 With one argument of the form section.name, print just the value
1609 With one argument of the form section.name, print just the value
1610 of that config item.
1610 of that config item.
1611
1611
1612 With multiple arguments, print names and values of all config
1612 With multiple arguments, print names and values of all config
1613 items with matching section names.
1613 items with matching section names.
1614
1614
1615 With --edit, start an editor on the user-level config file. With
1615 With --edit, start an editor on the user-level config file. With
1616 --global, edit the system-wide config file. With --local, edit the
1616 --global, edit the system-wide config file. With --local, edit the
1617 repository-level config file.
1617 repository-level config file.
1618
1618
1619 With --debug, the source (filename and line number) is printed
1619 With --debug, the source (filename and line number) is printed
1620 for each config item.
1620 for each config item.
1621
1621
1622 See :hg:`help config` for more information about config files.
1622 See :hg:`help config` for more information about config files.
1623
1623
1624 Returns 0 on success, 1 if NAME does not exist.
1624 Returns 0 on success, 1 if NAME does not exist.
1625
1625
1626 """
1626 """
1627
1627
1628 if opts.get('edit') or opts.get('local') or opts.get('global'):
1628 if opts.get('edit') or opts.get('local') or opts.get('global'):
1629 if opts.get('local') and opts.get('global'):
1629 if opts.get('local') and opts.get('global'):
1630 raise error.Abort(_("can't use --local and --global together"))
1630 raise error.Abort(_("can't use --local and --global together"))
1631
1631
1632 if opts.get('local'):
1632 if opts.get('local'):
1633 if not repo:
1633 if not repo:
1634 raise error.Abort(_("can't use --local outside a repository"))
1634 raise error.Abort(_("can't use --local outside a repository"))
1635 paths = [repo.join('hgrc')]
1635 paths = [repo.join('hgrc')]
1636 elif opts.get('global'):
1636 elif opts.get('global'):
1637 paths = scmutil.systemrcpath()
1637 paths = scmutil.systemrcpath()
1638 else:
1638 else:
1639 paths = scmutil.userrcpath()
1639 paths = scmutil.userrcpath()
1640
1640
1641 for f in paths:
1641 for f in paths:
1642 if os.path.exists(f):
1642 if os.path.exists(f):
1643 break
1643 break
1644 else:
1644 else:
1645 if opts.get('global'):
1645 if opts.get('global'):
1646 samplehgrc = uimod.samplehgrcs['global']
1646 samplehgrc = uimod.samplehgrcs['global']
1647 elif opts.get('local'):
1647 elif opts.get('local'):
1648 samplehgrc = uimod.samplehgrcs['local']
1648 samplehgrc = uimod.samplehgrcs['local']
1649 else:
1649 else:
1650 samplehgrc = uimod.samplehgrcs['user']
1650 samplehgrc = uimod.samplehgrcs['user']
1651
1651
1652 f = paths[0]
1652 f = paths[0]
1653 fp = open(f, "w")
1653 fp = open(f, "w")
1654 fp.write(samplehgrc)
1654 fp.write(samplehgrc)
1655 fp.close()
1655 fp.close()
1656
1656
1657 editor = ui.geteditor()
1657 editor = ui.geteditor()
1658 ui.system("%s \"%s\"" % (editor, f),
1658 ui.system("%s \"%s\"" % (editor, f),
1659 onerr=error.Abort, errprefix=_("edit failed"))
1659 onerr=error.Abort, errprefix=_("edit failed"))
1660 return
1660 return
1661
1661
1662 for f in scmutil.rcpath():
1662 for f in scmutil.rcpath():
1663 ui.debug('read config from: %s\n' % f)
1663 ui.debug('read config from: %s\n' % f)
1664 untrusted = bool(opts.get('untrusted'))
1664 untrusted = bool(opts.get('untrusted'))
1665 if values:
1665 if values:
1666 sections = [v for v in values if '.' not in v]
1666 sections = [v for v in values if '.' not in v]
1667 items = [v for v in values if '.' in v]
1667 items = [v for v in values if '.' in v]
1668 if len(items) > 1 or items and sections:
1668 if len(items) > 1 or items and sections:
1669 raise error.Abort(_('only one config item permitted'))
1669 raise error.Abort(_('only one config item permitted'))
1670 matched = False
1670 matched = False
1671 for section, name, value in ui.walkconfig(untrusted=untrusted):
1671 for section, name, value in ui.walkconfig(untrusted=untrusted):
1672 value = str(value).replace('\n', '\\n')
1672 value = str(value).replace('\n', '\\n')
1673 sectname = section + '.' + name
1673 sectname = section + '.' + name
1674 if values:
1674 if values:
1675 for v in values:
1675 for v in values:
1676 if v == section:
1676 if v == section:
1677 ui.debug('%s: ' %
1677 ui.debug('%s: ' %
1678 ui.configsource(section, name, untrusted))
1678 ui.configsource(section, name, untrusted))
1679 ui.write('%s=%s\n' % (sectname, value))
1679 ui.write('%s=%s\n' % (sectname, value))
1680 matched = True
1680 matched = True
1681 elif v == sectname:
1681 elif v == sectname:
1682 ui.debug('%s: ' %
1682 ui.debug('%s: ' %
1683 ui.configsource(section, name, untrusted))
1683 ui.configsource(section, name, untrusted))
1684 ui.write(value, '\n')
1684 ui.write(value, '\n')
1685 matched = True
1685 matched = True
1686 else:
1686 else:
1687 ui.debug('%s: ' %
1687 ui.debug('%s: ' %
1688 ui.configsource(section, name, untrusted))
1688 ui.configsource(section, name, untrusted))
1689 ui.write('%s=%s\n' % (sectname, value))
1689 ui.write('%s=%s\n' % (sectname, value))
1690 matched = True
1690 matched = True
1691 if matched:
1691 if matched:
1692 return 0
1692 return 0
1693 return 1
1693 return 1
1694
1694
1695 @command('copy|cp',
1695 @command('copy|cp',
1696 [('A', 'after', None, _('record a copy that has already occurred')),
1696 [('A', 'after', None, _('record a copy that has already occurred')),
1697 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1697 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1698 ] + walkopts + dryrunopts,
1698 ] + walkopts + dryrunopts,
1699 _('[OPTION]... [SOURCE]... DEST'))
1699 _('[OPTION]... [SOURCE]... DEST'))
1700 def copy(ui, repo, *pats, **opts):
1700 def copy(ui, repo, *pats, **opts):
1701 """mark files as copied for the next commit
1701 """mark files as copied for the next commit
1702
1702
1703 Mark dest as having copies of source files. If dest is a
1703 Mark dest as having copies of source files. If dest is a
1704 directory, copies are put in that directory. If dest is a file,
1704 directory, copies are put in that directory. If dest is a file,
1705 the source must be a single file.
1705 the source must be a single file.
1706
1706
1707 By default, this command copies the contents of files as they
1707 By default, this command copies the contents of files as they
1708 exist in the working directory. If invoked with -A/--after, the
1708 exist in the working directory. If invoked with -A/--after, the
1709 operation is recorded, but no copying is performed.
1709 operation is recorded, but no copying is performed.
1710
1710
1711 This command takes effect with the next commit. To undo a copy
1711 This command takes effect with the next commit. To undo a copy
1712 before that, see :hg:`revert`.
1712 before that, see :hg:`revert`.
1713
1713
1714 Returns 0 on success, 1 if errors are encountered.
1714 Returns 0 on success, 1 if errors are encountered.
1715 """
1715 """
1716 wlock = repo.wlock(False)
1716 wlock = repo.wlock(False)
1717 try:
1717 try:
1718 return cmdutil.copy(ui, repo, pats, opts)
1718 return cmdutil.copy(ui, repo, pats, opts)
1719 finally:
1719 finally:
1720 wlock.release()
1720 wlock.release()
1721
1721
1722 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1722 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1723 def debugancestor(ui, repo, *args):
1723 def debugancestor(ui, repo, *args):
1724 """find the ancestor revision of two revisions in a given index"""
1724 """find the ancestor revision of two revisions in a given index"""
1725 if len(args) == 3:
1725 if len(args) == 3:
1726 index, rev1, rev2 = args
1726 index, rev1, rev2 = args
1727 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1727 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1728 lookup = r.lookup
1728 lookup = r.lookup
1729 elif len(args) == 2:
1729 elif len(args) == 2:
1730 if not repo:
1730 if not repo:
1731 raise error.Abort(_("there is no Mercurial repository here "
1731 raise error.Abort(_("there is no Mercurial repository here "
1732 "(.hg not found)"))
1732 "(.hg not found)"))
1733 rev1, rev2 = args
1733 rev1, rev2 = args
1734 r = repo.changelog
1734 r = repo.changelog
1735 lookup = repo.lookup
1735 lookup = repo.lookup
1736 else:
1736 else:
1737 raise error.Abort(_('either two or three arguments required'))
1737 raise error.Abort(_('either two or three arguments required'))
1738 a = r.ancestor(lookup(rev1), lookup(rev2))
1738 a = r.ancestor(lookup(rev1), lookup(rev2))
1739 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1739 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1740
1740
1741 @command('debugbuilddag',
1741 @command('debugbuilddag',
1742 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1742 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1743 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1743 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1744 ('n', 'new-file', None, _('add new file at each rev'))],
1744 ('n', 'new-file', None, _('add new file at each rev'))],
1745 _('[OPTION]... [TEXT]'))
1745 _('[OPTION]... [TEXT]'))
1746 def debugbuilddag(ui, repo, text=None,
1746 def debugbuilddag(ui, repo, text=None,
1747 mergeable_file=False,
1747 mergeable_file=False,
1748 overwritten_file=False,
1748 overwritten_file=False,
1749 new_file=False):
1749 new_file=False):
1750 """builds a repo with a given DAG from scratch in the current empty repo
1750 """builds a repo with a given DAG from scratch in the current empty repo
1751
1751
1752 The description of the DAG is read from stdin if not given on the
1752 The description of the DAG is read from stdin if not given on the
1753 command line.
1753 command line.
1754
1754
1755 Elements:
1755 Elements:
1756
1756
1757 - "+n" is a linear run of n nodes based on the current default parent
1757 - "+n" is a linear run of n nodes based on the current default parent
1758 - "." is a single node based on the current default parent
1758 - "." is a single node based on the current default parent
1759 - "$" resets the default parent to null (implied at the start);
1759 - "$" resets the default parent to null (implied at the start);
1760 otherwise the default parent is always the last node created
1760 otherwise the default parent is always the last node created
1761 - "<p" sets the default parent to the backref p
1761 - "<p" sets the default parent to the backref p
1762 - "*p" is a fork at parent p, which is a backref
1762 - "*p" is a fork at parent p, which is a backref
1763 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1763 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1764 - "/p2" is a merge of the preceding node and p2
1764 - "/p2" is a merge of the preceding node and p2
1765 - ":tag" defines a local tag for the preceding node
1765 - ":tag" defines a local tag for the preceding node
1766 - "@branch" sets the named branch for subsequent nodes
1766 - "@branch" sets the named branch for subsequent nodes
1767 - "#...\\n" is a comment up to the end of the line
1767 - "#...\\n" is a comment up to the end of the line
1768
1768
1769 Whitespace between the above elements is ignored.
1769 Whitespace between the above elements is ignored.
1770
1770
1771 A backref is either
1771 A backref is either
1772
1772
1773 - a number n, which references the node curr-n, where curr is the current
1773 - a number n, which references the node curr-n, where curr is the current
1774 node, or
1774 node, or
1775 - the name of a local tag you placed earlier using ":tag", or
1775 - the name of a local tag you placed earlier using ":tag", or
1776 - empty to denote the default parent.
1776 - empty to denote the default parent.
1777
1777
1778 All string valued-elements are either strictly alphanumeric, or must
1778 All string valued-elements are either strictly alphanumeric, or must
1779 be enclosed in double quotes ("..."), with "\\" as escape character.
1779 be enclosed in double quotes ("..."), with "\\" as escape character.
1780 """
1780 """
1781
1781
1782 if text is None:
1782 if text is None:
1783 ui.status(_("reading DAG from stdin\n"))
1783 ui.status(_("reading DAG from stdin\n"))
1784 text = ui.fin.read()
1784 text = ui.fin.read()
1785
1785
1786 cl = repo.changelog
1786 cl = repo.changelog
1787 if len(cl) > 0:
1787 if len(cl) > 0:
1788 raise error.Abort(_('repository is not empty'))
1788 raise error.Abort(_('repository is not empty'))
1789
1789
1790 # determine number of revs in DAG
1790 # determine number of revs in DAG
1791 total = 0
1791 total = 0
1792 for type, data in dagparser.parsedag(text):
1792 for type, data in dagparser.parsedag(text):
1793 if type == 'n':
1793 if type == 'n':
1794 total += 1
1794 total += 1
1795
1795
1796 if mergeable_file:
1796 if mergeable_file:
1797 linesperrev = 2
1797 linesperrev = 2
1798 # make a file with k lines per rev
1798 # make a file with k lines per rev
1799 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1799 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1800 initialmergedlines.append("")
1800 initialmergedlines.append("")
1801
1801
1802 tags = []
1802 tags = []
1803
1803
1804 lock = tr = None
1804 lock = tr = None
1805 try:
1805 try:
1806 lock = repo.lock()
1806 lock = repo.lock()
1807 tr = repo.transaction("builddag")
1807 tr = repo.transaction("builddag")
1808
1808
1809 at = -1
1809 at = -1
1810 atbranch = 'default'
1810 atbranch = 'default'
1811 nodeids = []
1811 nodeids = []
1812 id = 0
1812 id = 0
1813 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1813 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1814 for type, data in dagparser.parsedag(text):
1814 for type, data in dagparser.parsedag(text):
1815 if type == 'n':
1815 if type == 'n':
1816 ui.note(('node %s\n' % str(data)))
1816 ui.note(('node %s\n' % str(data)))
1817 id, ps = data
1817 id, ps = data
1818
1818
1819 files = []
1819 files = []
1820 fctxs = {}
1820 fctxs = {}
1821
1821
1822 p2 = None
1822 p2 = None
1823 if mergeable_file:
1823 if mergeable_file:
1824 fn = "mf"
1824 fn = "mf"
1825 p1 = repo[ps[0]]
1825 p1 = repo[ps[0]]
1826 if len(ps) > 1:
1826 if len(ps) > 1:
1827 p2 = repo[ps[1]]
1827 p2 = repo[ps[1]]
1828 pa = p1.ancestor(p2)
1828 pa = p1.ancestor(p2)
1829 base, local, other = [x[fn].data() for x in (pa, p1,
1829 base, local, other = [x[fn].data() for x in (pa, p1,
1830 p2)]
1830 p2)]
1831 m3 = simplemerge.Merge3Text(base, local, other)
1831 m3 = simplemerge.Merge3Text(base, local, other)
1832 ml = [l.strip() for l in m3.merge_lines()]
1832 ml = [l.strip() for l in m3.merge_lines()]
1833 ml.append("")
1833 ml.append("")
1834 elif at > 0:
1834 elif at > 0:
1835 ml = p1[fn].data().split("\n")
1835 ml = p1[fn].data().split("\n")
1836 else:
1836 else:
1837 ml = initialmergedlines
1837 ml = initialmergedlines
1838 ml[id * linesperrev] += " r%i" % id
1838 ml[id * linesperrev] += " r%i" % id
1839 mergedtext = "\n".join(ml)
1839 mergedtext = "\n".join(ml)
1840 files.append(fn)
1840 files.append(fn)
1841 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1841 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1842
1842
1843 if overwritten_file:
1843 if overwritten_file:
1844 fn = "of"
1844 fn = "of"
1845 files.append(fn)
1845 files.append(fn)
1846 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1846 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1847
1847
1848 if new_file:
1848 if new_file:
1849 fn = "nf%i" % id
1849 fn = "nf%i" % id
1850 files.append(fn)
1850 files.append(fn)
1851 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1851 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1852 if len(ps) > 1:
1852 if len(ps) > 1:
1853 if not p2:
1853 if not p2:
1854 p2 = repo[ps[1]]
1854 p2 = repo[ps[1]]
1855 for fn in p2:
1855 for fn in p2:
1856 if fn.startswith("nf"):
1856 if fn.startswith("nf"):
1857 files.append(fn)
1857 files.append(fn)
1858 fctxs[fn] = p2[fn]
1858 fctxs[fn] = p2[fn]
1859
1859
1860 def fctxfn(repo, cx, path):
1860 def fctxfn(repo, cx, path):
1861 return fctxs.get(path)
1861 return fctxs.get(path)
1862
1862
1863 if len(ps) == 0 or ps[0] < 0:
1863 if len(ps) == 0 or ps[0] < 0:
1864 pars = [None, None]
1864 pars = [None, None]
1865 elif len(ps) == 1:
1865 elif len(ps) == 1:
1866 pars = [nodeids[ps[0]], None]
1866 pars = [nodeids[ps[0]], None]
1867 else:
1867 else:
1868 pars = [nodeids[p] for p in ps]
1868 pars = [nodeids[p] for p in ps]
1869 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1869 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1870 date=(id, 0),
1870 date=(id, 0),
1871 user="debugbuilddag",
1871 user="debugbuilddag",
1872 extra={'branch': atbranch})
1872 extra={'branch': atbranch})
1873 nodeid = repo.commitctx(cx)
1873 nodeid = repo.commitctx(cx)
1874 nodeids.append(nodeid)
1874 nodeids.append(nodeid)
1875 at = id
1875 at = id
1876 elif type == 'l':
1876 elif type == 'l':
1877 id, name = data
1877 id, name = data
1878 ui.note(('tag %s\n' % name))
1878 ui.note(('tag %s\n' % name))
1879 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1879 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1880 elif type == 'a':
1880 elif type == 'a':
1881 ui.note(('branch %s\n' % data))
1881 ui.note(('branch %s\n' % data))
1882 atbranch = data
1882 atbranch = data
1883 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1883 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1884 tr.close()
1884 tr.close()
1885
1885
1886 if tags:
1886 if tags:
1887 repo.vfs.write("localtags", "".join(tags))
1887 repo.vfs.write("localtags", "".join(tags))
1888 finally:
1888 finally:
1889 ui.progress(_('building'), None)
1889 ui.progress(_('building'), None)
1890 release(tr, lock)
1890 release(tr, lock)
1891
1891
1892 @command('debugbundle',
1892 @command('debugbundle',
1893 [('a', 'all', None, _('show all details'))],
1893 [('a', 'all', None, _('show all details'))],
1894 _('FILE'),
1894 _('FILE'),
1895 norepo=True)
1895 norepo=True)
1896 def debugbundle(ui, bundlepath, all=None, **opts):
1896 def debugbundle(ui, bundlepath, all=None, **opts):
1897 """lists the contents of a bundle"""
1897 """lists the contents of a bundle"""
1898 f = hg.openpath(ui, bundlepath)
1898 f = hg.openpath(ui, bundlepath)
1899 try:
1899 try:
1900 gen = exchange.readbundle(ui, f, bundlepath)
1900 gen = exchange.readbundle(ui, f, bundlepath)
1901 if isinstance(gen, bundle2.unbundle20):
1901 if isinstance(gen, bundle2.unbundle20):
1902 return _debugbundle2(ui, gen, all=all, **opts)
1902 return _debugbundle2(ui, gen, all=all, **opts)
1903 if all:
1903 if all:
1904 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1904 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1905
1905
1906 def showchunks(named):
1906 def showchunks(named):
1907 ui.write("\n%s\n" % named)
1907 ui.write("\n%s\n" % named)
1908 chain = None
1908 chain = None
1909 while True:
1909 while True:
1910 chunkdata = gen.deltachunk(chain)
1910 chunkdata = gen.deltachunk(chain)
1911 if not chunkdata:
1911 if not chunkdata:
1912 break
1912 break
1913 node = chunkdata['node']
1913 node = chunkdata['node']
1914 p1 = chunkdata['p1']
1914 p1 = chunkdata['p1']
1915 p2 = chunkdata['p2']
1915 p2 = chunkdata['p2']
1916 cs = chunkdata['cs']
1916 cs = chunkdata['cs']
1917 deltabase = chunkdata['deltabase']
1917 deltabase = chunkdata['deltabase']
1918 delta = chunkdata['delta']
1918 delta = chunkdata['delta']
1919 ui.write("%s %s %s %s %s %s\n" %
1919 ui.write("%s %s %s %s %s %s\n" %
1920 (hex(node), hex(p1), hex(p2),
1920 (hex(node), hex(p1), hex(p2),
1921 hex(cs), hex(deltabase), len(delta)))
1921 hex(cs), hex(deltabase), len(delta)))
1922 chain = node
1922 chain = node
1923
1923
1924 chunkdata = gen.changelogheader()
1924 chunkdata = gen.changelogheader()
1925 showchunks("changelog")
1925 showchunks("changelog")
1926 chunkdata = gen.manifestheader()
1926 chunkdata = gen.manifestheader()
1927 showchunks("manifest")
1927 showchunks("manifest")
1928 while True:
1928 while True:
1929 chunkdata = gen.filelogheader()
1929 chunkdata = gen.filelogheader()
1930 if not chunkdata:
1930 if not chunkdata:
1931 break
1931 break
1932 fname = chunkdata['filename']
1932 fname = chunkdata['filename']
1933 showchunks(fname)
1933 showchunks(fname)
1934 else:
1934 else:
1935 if isinstance(gen, bundle2.unbundle20):
1935 if isinstance(gen, bundle2.unbundle20):
1936 raise error.Abort(_('use debugbundle2 for this file'))
1936 raise error.Abort(_('use debugbundle2 for this file'))
1937 chunkdata = gen.changelogheader()
1937 chunkdata = gen.changelogheader()
1938 chain = None
1938 chain = None
1939 while True:
1939 while True:
1940 chunkdata = gen.deltachunk(chain)
1940 chunkdata = gen.deltachunk(chain)
1941 if not chunkdata:
1941 if not chunkdata:
1942 break
1942 break
1943 node = chunkdata['node']
1943 node = chunkdata['node']
1944 ui.write("%s\n" % hex(node))
1944 ui.write("%s\n" % hex(node))
1945 chain = node
1945 chain = node
1946 finally:
1946 finally:
1947 f.close()
1947 f.close()
1948
1948
1949 def _debugbundle2(ui, gen, **opts):
1949 def _debugbundle2(ui, gen, **opts):
1950 """lists the contents of a bundle2"""
1950 """lists the contents of a bundle2"""
1951 if not isinstance(gen, bundle2.unbundle20):
1951 if not isinstance(gen, bundle2.unbundle20):
1952 raise error.Abort(_('not a bundle2 file'))
1952 raise error.Abort(_('not a bundle2 file'))
1953 ui.write(('Stream params: %s\n' % repr(gen.params)))
1953 ui.write(('Stream params: %s\n' % repr(gen.params)))
1954 for part in gen.iterparts():
1954 for part in gen.iterparts():
1955 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1955 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1956 if part.type == 'changegroup':
1956 if part.type == 'changegroup':
1957 version = part.params.get('version', '01')
1957 version = part.params.get('version', '01')
1958 cg = changegroup.packermap[version][1](part, 'UN')
1958 cg = changegroup.packermap[version][1](part, 'UN')
1959 chunkdata = cg.changelogheader()
1959 chunkdata = cg.changelogheader()
1960 chain = None
1960 chain = None
1961 while True:
1961 while True:
1962 chunkdata = cg.deltachunk(chain)
1962 chunkdata = cg.deltachunk(chain)
1963 if not chunkdata:
1963 if not chunkdata:
1964 break
1964 break
1965 node = chunkdata['node']
1965 node = chunkdata['node']
1966 ui.write(" %s\n" % hex(node))
1966 ui.write(" %s\n" % hex(node))
1967 chain = node
1967 chain = node
1968
1968
1969 @command('debugcreatestreamclonebundle', [], 'FILE')
1969 @command('debugcreatestreamclonebundle', [], 'FILE')
1970 def debugcreatestreamclonebundle(ui, repo, fname):
1970 def debugcreatestreamclonebundle(ui, repo, fname):
1971 """create a stream clone bundle file
1971 """create a stream clone bundle file
1972
1972
1973 Stream bundles are special bundles that are essentially archives of
1973 Stream bundles are special bundles that are essentially archives of
1974 revlog files. They are commonly used for cloning very quickly.
1974 revlog files. They are commonly used for cloning very quickly.
1975 """
1975 """
1976 requirements, gen = streamclone.generatebundlev1(repo)
1976 requirements, gen = streamclone.generatebundlev1(repo)
1977 changegroup.writechunks(ui, gen, fname)
1977 changegroup.writechunks(ui, gen, fname)
1978
1978
1979 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
1979 ui.write(_('bundle requirements: %s\n') % ', '.join(sorted(requirements)))
1980
1980
1981 @command('debugapplystreamclonebundle', [], 'FILE')
1981 @command('debugapplystreamclonebundle', [], 'FILE')
1982 def debugapplystreamclonebundle(ui, repo, fname):
1982 def debugapplystreamclonebundle(ui, repo, fname):
1983 """apply a stream clone bundle file"""
1983 """apply a stream clone bundle file"""
1984 f = hg.openpath(ui, fname)
1984 f = hg.openpath(ui, fname)
1985 gen = exchange.readbundle(ui, f, fname)
1985 gen = exchange.readbundle(ui, f, fname)
1986 gen.apply(repo)
1986 gen.apply(repo)
1987
1987
1988 @command('debugcheckstate', [], '')
1988 @command('debugcheckstate', [], '')
1989 def debugcheckstate(ui, repo):
1989 def debugcheckstate(ui, repo):
1990 """validate the correctness of the current dirstate"""
1990 """validate the correctness of the current dirstate"""
1991 parent1, parent2 = repo.dirstate.parents()
1991 parent1, parent2 = repo.dirstate.parents()
1992 m1 = repo[parent1].manifest()
1992 m1 = repo[parent1].manifest()
1993 m2 = repo[parent2].manifest()
1993 m2 = repo[parent2].manifest()
1994 errors = 0
1994 errors = 0
1995 for f in repo.dirstate:
1995 for f in repo.dirstate:
1996 state = repo.dirstate[f]
1996 state = repo.dirstate[f]
1997 if state in "nr" and f not in m1:
1997 if state in "nr" and f not in m1:
1998 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1998 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1999 errors += 1
1999 errors += 1
2000 if state in "a" and f in m1:
2000 if state in "a" and f in m1:
2001 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2001 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
2002 errors += 1
2002 errors += 1
2003 if state in "m" and f not in m1 and f not in m2:
2003 if state in "m" and f not in m1 and f not in m2:
2004 ui.warn(_("%s in state %s, but not in either manifest\n") %
2004 ui.warn(_("%s in state %s, but not in either manifest\n") %
2005 (f, state))
2005 (f, state))
2006 errors += 1
2006 errors += 1
2007 for f in m1:
2007 for f in m1:
2008 state = repo.dirstate[f]
2008 state = repo.dirstate[f]
2009 if state not in "nrm":
2009 if state not in "nrm":
2010 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2010 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
2011 errors += 1
2011 errors += 1
2012 if errors:
2012 if errors:
2013 error = _(".hg/dirstate inconsistent with current parent's manifest")
2013 error = _(".hg/dirstate inconsistent with current parent's manifest")
2014 raise error.Abort(error)
2014 raise error.Abort(error)
2015
2015
2016 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2016 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
2017 def debugcommands(ui, cmd='', *args):
2017 def debugcommands(ui, cmd='', *args):
2018 """list all available commands and options"""
2018 """list all available commands and options"""
2019 for cmd, vals in sorted(table.iteritems()):
2019 for cmd, vals in sorted(table.iteritems()):
2020 cmd = cmd.split('|')[0].strip('^')
2020 cmd = cmd.split('|')[0].strip('^')
2021 opts = ', '.join([i[1] for i in vals[1]])
2021 opts = ', '.join([i[1] for i in vals[1]])
2022 ui.write('%s: %s\n' % (cmd, opts))
2022 ui.write('%s: %s\n' % (cmd, opts))
2023
2023
2024 @command('debugcomplete',
2024 @command('debugcomplete',
2025 [('o', 'options', None, _('show the command options'))],
2025 [('o', 'options', None, _('show the command options'))],
2026 _('[-o] CMD'),
2026 _('[-o] CMD'),
2027 norepo=True)
2027 norepo=True)
2028 def debugcomplete(ui, cmd='', **opts):
2028 def debugcomplete(ui, cmd='', **opts):
2029 """returns the completion list associated with the given command"""
2029 """returns the completion list associated with the given command"""
2030
2030
2031 if opts.get('options'):
2031 if opts.get('options'):
2032 options = []
2032 options = []
2033 otables = [globalopts]
2033 otables = [globalopts]
2034 if cmd:
2034 if cmd:
2035 aliases, entry = cmdutil.findcmd(cmd, table, False)
2035 aliases, entry = cmdutil.findcmd(cmd, table, False)
2036 otables.append(entry[1])
2036 otables.append(entry[1])
2037 for t in otables:
2037 for t in otables:
2038 for o in t:
2038 for o in t:
2039 if "(DEPRECATED)" in o[3]:
2039 if "(DEPRECATED)" in o[3]:
2040 continue
2040 continue
2041 if o[0]:
2041 if o[0]:
2042 options.append('-%s' % o[0])
2042 options.append('-%s' % o[0])
2043 options.append('--%s' % o[1])
2043 options.append('--%s' % o[1])
2044 ui.write("%s\n" % "\n".join(options))
2044 ui.write("%s\n" % "\n".join(options))
2045 return
2045 return
2046
2046
2047 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2047 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2048 if ui.verbose:
2048 if ui.verbose:
2049 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2049 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
2050 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2050 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
2051
2051
2052 @command('debugdag',
2052 @command('debugdag',
2053 [('t', 'tags', None, _('use tags as labels')),
2053 [('t', 'tags', None, _('use tags as labels')),
2054 ('b', 'branches', None, _('annotate with branch names')),
2054 ('b', 'branches', None, _('annotate with branch names')),
2055 ('', 'dots', None, _('use dots for runs')),
2055 ('', 'dots', None, _('use dots for runs')),
2056 ('s', 'spaces', None, _('separate elements by spaces'))],
2056 ('s', 'spaces', None, _('separate elements by spaces'))],
2057 _('[OPTION]... [FILE [REV]...]'),
2057 _('[OPTION]... [FILE [REV]...]'),
2058 optionalrepo=True)
2058 optionalrepo=True)
2059 def debugdag(ui, repo, file_=None, *revs, **opts):
2059 def debugdag(ui, repo, file_=None, *revs, **opts):
2060 """format the changelog or an index DAG as a concise textual description
2060 """format the changelog or an index DAG as a concise textual description
2061
2061
2062 If you pass a revlog index, the revlog's DAG is emitted. If you list
2062 If you pass a revlog index, the revlog's DAG is emitted. If you list
2063 revision numbers, they get labeled in the output as rN.
2063 revision numbers, they get labeled in the output as rN.
2064
2064
2065 Otherwise, the changelog DAG of the current repo is emitted.
2065 Otherwise, the changelog DAG of the current repo is emitted.
2066 """
2066 """
2067 spaces = opts.get('spaces')
2067 spaces = opts.get('spaces')
2068 dots = opts.get('dots')
2068 dots = opts.get('dots')
2069 if file_:
2069 if file_:
2070 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2070 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2071 revs = set((int(r) for r in revs))
2071 revs = set((int(r) for r in revs))
2072 def events():
2072 def events():
2073 for r in rlog:
2073 for r in rlog:
2074 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2074 yield 'n', (r, list(p for p in rlog.parentrevs(r)
2075 if p != -1))
2075 if p != -1))
2076 if r in revs:
2076 if r in revs:
2077 yield 'l', (r, "r%i" % r)
2077 yield 'l', (r, "r%i" % r)
2078 elif repo:
2078 elif repo:
2079 cl = repo.changelog
2079 cl = repo.changelog
2080 tags = opts.get('tags')
2080 tags = opts.get('tags')
2081 branches = opts.get('branches')
2081 branches = opts.get('branches')
2082 if tags:
2082 if tags:
2083 labels = {}
2083 labels = {}
2084 for l, n in repo.tags().items():
2084 for l, n in repo.tags().items():
2085 labels.setdefault(cl.rev(n), []).append(l)
2085 labels.setdefault(cl.rev(n), []).append(l)
2086 def events():
2086 def events():
2087 b = "default"
2087 b = "default"
2088 for r in cl:
2088 for r in cl:
2089 if branches:
2089 if branches:
2090 newb = cl.read(cl.node(r))[5]['branch']
2090 newb = cl.read(cl.node(r))[5]['branch']
2091 if newb != b:
2091 if newb != b:
2092 yield 'a', newb
2092 yield 'a', newb
2093 b = newb
2093 b = newb
2094 yield 'n', (r, list(p for p in cl.parentrevs(r)
2094 yield 'n', (r, list(p for p in cl.parentrevs(r)
2095 if p != -1))
2095 if p != -1))
2096 if tags:
2096 if tags:
2097 ls = labels.get(r)
2097 ls = labels.get(r)
2098 if ls:
2098 if ls:
2099 for l in ls:
2099 for l in ls:
2100 yield 'l', (r, l)
2100 yield 'l', (r, l)
2101 else:
2101 else:
2102 raise error.Abort(_('need repo for changelog dag'))
2102 raise error.Abort(_('need repo for changelog dag'))
2103
2103
2104 for line in dagparser.dagtextlines(events(),
2104 for line in dagparser.dagtextlines(events(),
2105 addspaces=spaces,
2105 addspaces=spaces,
2106 wraplabels=True,
2106 wraplabels=True,
2107 wrapannotations=True,
2107 wrapannotations=True,
2108 wrapnonlinear=dots,
2108 wrapnonlinear=dots,
2109 usedots=dots,
2109 usedots=dots,
2110 maxlinewidth=70):
2110 maxlinewidth=70):
2111 ui.write(line)
2111 ui.write(line)
2112 ui.write("\n")
2112 ui.write("\n")
2113
2113
2114 @command('debugdata',
2114 @command('debugdata',
2115 [('c', 'changelog', False, _('open changelog')),
2115 [('c', 'changelog', False, _('open changelog')),
2116 ('m', 'manifest', False, _('open manifest')),
2116 ('m', 'manifest', False, _('open manifest')),
2117 ('', 'dir', False, _('open directory manifest'))],
2117 ('', 'dir', False, _('open directory manifest'))],
2118 _('-c|-m|FILE REV'))
2118 _('-c|-m|FILE REV'))
2119 def debugdata(ui, repo, file_, rev=None, **opts):
2119 def debugdata(ui, repo, file_, rev=None, **opts):
2120 """dump the contents of a data file revision"""
2120 """dump the contents of a data file revision"""
2121 if opts.get('changelog') or opts.get('manifest'):
2121 if opts.get('changelog') or opts.get('manifest'):
2122 file_, rev = None, file_
2122 file_, rev = None, file_
2123 elif rev is None:
2123 elif rev is None:
2124 raise error.CommandError('debugdata', _('invalid arguments'))
2124 raise error.CommandError('debugdata', _('invalid arguments'))
2125 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2125 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2126 try:
2126 try:
2127 ui.write(r.revision(r.lookup(rev)))
2127 ui.write(r.revision(r.lookup(rev)))
2128 except KeyError:
2128 except KeyError:
2129 raise error.Abort(_('invalid revision identifier %s') % rev)
2129 raise error.Abort(_('invalid revision identifier %s') % rev)
2130
2130
2131 @command('debugdate',
2131 @command('debugdate',
2132 [('e', 'extended', None, _('try extended date formats'))],
2132 [('e', 'extended', None, _('try extended date formats'))],
2133 _('[-e] DATE [RANGE]'),
2133 _('[-e] DATE [RANGE]'),
2134 norepo=True, optionalrepo=True)
2134 norepo=True, optionalrepo=True)
2135 def debugdate(ui, date, range=None, **opts):
2135 def debugdate(ui, date, range=None, **opts):
2136 """parse and display a date"""
2136 """parse and display a date"""
2137 if opts["extended"]:
2137 if opts["extended"]:
2138 d = util.parsedate(date, util.extendeddateformats)
2138 d = util.parsedate(date, util.extendeddateformats)
2139 else:
2139 else:
2140 d = util.parsedate(date)
2140 d = util.parsedate(date)
2141 ui.write(("internal: %s %s\n") % d)
2141 ui.write(("internal: %s %s\n") % d)
2142 ui.write(("standard: %s\n") % util.datestr(d))
2142 ui.write(("standard: %s\n") % util.datestr(d))
2143 if range:
2143 if range:
2144 m = util.matchdate(range)
2144 m = util.matchdate(range)
2145 ui.write(("match: %s\n") % m(d[0]))
2145 ui.write(("match: %s\n") % m(d[0]))
2146
2146
2147 @command('debugdiscovery',
2147 @command('debugdiscovery',
2148 [('', 'old', None, _('use old-style discovery')),
2148 [('', 'old', None, _('use old-style discovery')),
2149 ('', 'nonheads', None,
2149 ('', 'nonheads', None,
2150 _('use old-style discovery with non-heads included')),
2150 _('use old-style discovery with non-heads included')),
2151 ] + remoteopts,
2151 ] + remoteopts,
2152 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2152 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2153 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2153 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2154 """runs the changeset discovery protocol in isolation"""
2154 """runs the changeset discovery protocol in isolation"""
2155 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2155 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2156 opts.get('branch'))
2156 opts.get('branch'))
2157 remote = hg.peer(repo, opts, remoteurl)
2157 remote = hg.peer(repo, opts, remoteurl)
2158 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2158 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2159
2159
2160 # make sure tests are repeatable
2160 # make sure tests are repeatable
2161 random.seed(12323)
2161 random.seed(12323)
2162
2162
2163 def doit(localheads, remoteheads, remote=remote):
2163 def doit(localheads, remoteheads, remote=remote):
2164 if opts.get('old'):
2164 if opts.get('old'):
2165 if localheads:
2165 if localheads:
2166 raise error.Abort('cannot use localheads with old style '
2166 raise error.Abort('cannot use localheads with old style '
2167 'discovery')
2167 'discovery')
2168 if not util.safehasattr(remote, 'branches'):
2168 if not util.safehasattr(remote, 'branches'):
2169 # enable in-client legacy support
2169 # enable in-client legacy support
2170 remote = localrepo.locallegacypeer(remote.local())
2170 remote = localrepo.locallegacypeer(remote.local())
2171 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2171 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2172 force=True)
2172 force=True)
2173 common = set(common)
2173 common = set(common)
2174 if not opts.get('nonheads'):
2174 if not opts.get('nonheads'):
2175 ui.write(("unpruned common: %s\n") %
2175 ui.write(("unpruned common: %s\n") %
2176 " ".join(sorted(short(n) for n in common)))
2176 " ".join(sorted(short(n) for n in common)))
2177 dag = dagutil.revlogdag(repo.changelog)
2177 dag = dagutil.revlogdag(repo.changelog)
2178 all = dag.ancestorset(dag.internalizeall(common))
2178 all = dag.ancestorset(dag.internalizeall(common))
2179 common = dag.externalizeall(dag.headsetofconnecteds(all))
2179 common = dag.externalizeall(dag.headsetofconnecteds(all))
2180 else:
2180 else:
2181 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2181 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2182 common = set(common)
2182 common = set(common)
2183 rheads = set(hds)
2183 rheads = set(hds)
2184 lheads = set(repo.heads())
2184 lheads = set(repo.heads())
2185 ui.write(("common heads: %s\n") %
2185 ui.write(("common heads: %s\n") %
2186 " ".join(sorted(short(n) for n in common)))
2186 " ".join(sorted(short(n) for n in common)))
2187 if lheads <= common:
2187 if lheads <= common:
2188 ui.write(("local is subset\n"))
2188 ui.write(("local is subset\n"))
2189 elif rheads <= common:
2189 elif rheads <= common:
2190 ui.write(("remote is subset\n"))
2190 ui.write(("remote is subset\n"))
2191
2191
2192 serverlogs = opts.get('serverlog')
2192 serverlogs = opts.get('serverlog')
2193 if serverlogs:
2193 if serverlogs:
2194 for filename in serverlogs:
2194 for filename in serverlogs:
2195 logfile = open(filename, 'r')
2195 logfile = open(filename, 'r')
2196 try:
2196 try:
2197 line = logfile.readline()
2197 line = logfile.readline()
2198 while line:
2198 while line:
2199 parts = line.strip().split(';')
2199 parts = line.strip().split(';')
2200 op = parts[1]
2200 op = parts[1]
2201 if op == 'cg':
2201 if op == 'cg':
2202 pass
2202 pass
2203 elif op == 'cgss':
2203 elif op == 'cgss':
2204 doit(parts[2].split(' '), parts[3].split(' '))
2204 doit(parts[2].split(' '), parts[3].split(' '))
2205 elif op == 'unb':
2205 elif op == 'unb':
2206 doit(parts[3].split(' '), parts[2].split(' '))
2206 doit(parts[3].split(' '), parts[2].split(' '))
2207 line = logfile.readline()
2207 line = logfile.readline()
2208 finally:
2208 finally:
2209 logfile.close()
2209 logfile.close()
2210
2210
2211 else:
2211 else:
2212 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2212 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2213 opts.get('remote_head'))
2213 opts.get('remote_head'))
2214 localrevs = opts.get('local_head')
2214 localrevs = opts.get('local_head')
2215 doit(localrevs, remoterevs)
2215 doit(localrevs, remoterevs)
2216
2216
2217 @command('debugextensions', formatteropts, [], norepo=True)
2217 @command('debugextensions', formatteropts, [], norepo=True)
2218 def debugextensions(ui, **opts):
2218 def debugextensions(ui, **opts):
2219 '''show information about active extensions'''
2219 '''show information about active extensions'''
2220 exts = extensions.extensions(ui)
2220 exts = extensions.extensions(ui)
2221 fm = ui.formatter('debugextensions', opts)
2221 fm = ui.formatter('debugextensions', opts)
2222 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2222 for extname, extmod in sorted(exts, key=operator.itemgetter(0)):
2223 extsource = extmod.__file__
2223 extsource = extmod.__file__
2224 exttestedwith = getattr(extmod, 'testedwith', None)
2224 exttestedwith = getattr(extmod, 'testedwith', None)
2225 if exttestedwith is not None:
2225 if exttestedwith is not None:
2226 exttestedwith = exttestedwith.split()
2226 exttestedwith = exttestedwith.split()
2227 extbuglink = getattr(extmod, 'buglink', None)
2227 extbuglink = getattr(extmod, 'buglink', None)
2228
2228
2229 fm.startitem()
2229 fm.startitem()
2230
2230
2231 if ui.quiet or ui.verbose:
2231 if ui.quiet or ui.verbose:
2232 fm.write('name', '%s\n', extname)
2232 fm.write('name', '%s\n', extname)
2233 else:
2233 else:
2234 fm.write('name', '%s', extname)
2234 fm.write('name', '%s', extname)
2235 if not exttestedwith:
2235 if not exttestedwith:
2236 fm.plain(_(' (untested!)\n'))
2236 fm.plain(_(' (untested!)\n'))
2237 else:
2237 else:
2238 if exttestedwith == ['internal'] or \
2238 if exttestedwith == ['internal'] or \
2239 util.version() in exttestedwith:
2239 util.version() in exttestedwith:
2240 fm.plain('\n')
2240 fm.plain('\n')
2241 else:
2241 else:
2242 lasttestedversion = exttestedwith[-1]
2242 lasttestedversion = exttestedwith[-1]
2243 fm.plain(' (%s!)\n' % lasttestedversion)
2243 fm.plain(' (%s!)\n' % lasttestedversion)
2244
2244
2245 fm.condwrite(ui.verbose and extsource, 'source',
2245 fm.condwrite(ui.verbose and extsource, 'source',
2246 _(' location: %s\n'), extsource or "")
2246 _(' location: %s\n'), extsource or "")
2247
2247
2248 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2248 fm.condwrite(ui.verbose and exttestedwith, 'testedwith',
2249 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2249 _(' tested with: %s\n'), ' '.join(exttestedwith or []))
2250
2250
2251 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2251 fm.condwrite(ui.verbose and extbuglink, 'buglink',
2252 _(' bug reporting: %s\n'), extbuglink or "")
2252 _(' bug reporting: %s\n'), extbuglink or "")
2253
2253
2254 fm.end()
2254 fm.end()
2255
2255
2256 @command('debugfileset',
2256 @command('debugfileset',
2257 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2257 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2258 _('[-r REV] FILESPEC'))
2258 _('[-r REV] FILESPEC'))
2259 def debugfileset(ui, repo, expr, **opts):
2259 def debugfileset(ui, repo, expr, **opts):
2260 '''parse and apply a fileset specification'''
2260 '''parse and apply a fileset specification'''
2261 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2261 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2262 if ui.verbose:
2262 if ui.verbose:
2263 tree = fileset.parse(expr)
2263 tree = fileset.parse(expr)
2264 ui.note(fileset.prettyformat(tree), "\n")
2264 ui.note(fileset.prettyformat(tree), "\n")
2265
2265
2266 for f in ctx.getfileset(expr):
2266 for f in ctx.getfileset(expr):
2267 ui.write("%s\n" % f)
2267 ui.write("%s\n" % f)
2268
2268
2269 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2269 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2270 def debugfsinfo(ui, path="."):
2270 def debugfsinfo(ui, path="."):
2271 """show information detected about current filesystem"""
2271 """show information detected about current filesystem"""
2272 util.writefile('.debugfsinfo', '')
2272 util.writefile('.debugfsinfo', '')
2273 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2273 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2274 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2274 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2275 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2275 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2276 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2276 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2277 and 'yes' or 'no'))
2277 and 'yes' or 'no'))
2278 os.unlink('.debugfsinfo')
2278 os.unlink('.debugfsinfo')
2279
2279
2280 @command('debuggetbundle',
2280 @command('debuggetbundle',
2281 [('H', 'head', [], _('id of head node'), _('ID')),
2281 [('H', 'head', [], _('id of head node'), _('ID')),
2282 ('C', 'common', [], _('id of common node'), _('ID')),
2282 ('C', 'common', [], _('id of common node'), _('ID')),
2283 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2283 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2284 _('REPO FILE [-H|-C ID]...'),
2284 _('REPO FILE [-H|-C ID]...'),
2285 norepo=True)
2285 norepo=True)
2286 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2286 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2287 """retrieves a bundle from a repo
2287 """retrieves a bundle from a repo
2288
2288
2289 Every ID must be a full-length hex node id string. Saves the bundle to the
2289 Every ID must be a full-length hex node id string. Saves the bundle to the
2290 given file.
2290 given file.
2291 """
2291 """
2292 repo = hg.peer(ui, opts, repopath)
2292 repo = hg.peer(ui, opts, repopath)
2293 if not repo.capable('getbundle'):
2293 if not repo.capable('getbundle'):
2294 raise error.Abort("getbundle() not supported by target repository")
2294 raise error.Abort("getbundle() not supported by target repository")
2295 args = {}
2295 args = {}
2296 if common:
2296 if common:
2297 args['common'] = [bin(s) for s in common]
2297 args['common'] = [bin(s) for s in common]
2298 if head:
2298 if head:
2299 args['heads'] = [bin(s) for s in head]
2299 args['heads'] = [bin(s) for s in head]
2300 # TODO: get desired bundlecaps from command line.
2300 # TODO: get desired bundlecaps from command line.
2301 args['bundlecaps'] = None
2301 args['bundlecaps'] = None
2302 bundle = repo.getbundle('debug', **args)
2302 bundle = repo.getbundle('debug', **args)
2303
2303
2304 bundletype = opts.get('type', 'bzip2').lower()
2304 bundletype = opts.get('type', 'bzip2').lower()
2305 btypes = {'none': 'HG10UN',
2305 btypes = {'none': 'HG10UN',
2306 'bzip2': 'HG10BZ',
2306 'bzip2': 'HG10BZ',
2307 'gzip': 'HG10GZ',
2307 'gzip': 'HG10GZ',
2308 'bundle2': 'HG20'}
2308 'bundle2': 'HG20'}
2309 bundletype = btypes.get(bundletype)
2309 bundletype = btypes.get(bundletype)
2310 if bundletype not in changegroup.bundletypes:
2310 if bundletype not in changegroup.bundletypes:
2311 raise error.Abort(_('unknown bundle type specified with --type'))
2311 raise error.Abort(_('unknown bundle type specified with --type'))
2312 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2312 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2313
2313
2314 @command('debugignore', [], '')
2314 @command('debugignore', [], '')
2315 def debugignore(ui, repo, *values, **opts):
2315 def debugignore(ui, repo, *values, **opts):
2316 """display the combined ignore pattern"""
2316 """display the combined ignore pattern"""
2317 ignore = repo.dirstate._ignore
2317 ignore = repo.dirstate._ignore
2318 includepat = getattr(ignore, 'includepat', None)
2318 includepat = getattr(ignore, 'includepat', None)
2319 if includepat is not None:
2319 if includepat is not None:
2320 ui.write("%s\n" % includepat)
2320 ui.write("%s\n" % includepat)
2321 else:
2321 else:
2322 raise error.Abort(_("no ignore patterns found"))
2322 raise error.Abort(_("no ignore patterns found"))
2323
2323
2324 @command('debugindex',
2324 @command('debugindex',
2325 [('c', 'changelog', False, _('open changelog')),
2325 [('c', 'changelog', False, _('open changelog')),
2326 ('m', 'manifest', False, _('open manifest')),
2326 ('m', 'manifest', False, _('open manifest')),
2327 ('', 'dir', False, _('open directory manifest')),
2327 ('', 'dir', False, _('open directory manifest')),
2328 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2328 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2329 _('[-f FORMAT] -c|-m|FILE'),
2329 _('[-f FORMAT] -c|-m|FILE'),
2330 optionalrepo=True)
2330 optionalrepo=True)
2331 def debugindex(ui, repo, file_=None, **opts):
2331 def debugindex(ui, repo, file_=None, **opts):
2332 """dump the contents of an index file"""
2332 """dump the contents of an index file"""
2333 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2333 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2334 format = opts.get('format', 0)
2334 format = opts.get('format', 0)
2335 if format not in (0, 1):
2335 if format not in (0, 1):
2336 raise error.Abort(_("unknown format %d") % format)
2336 raise error.Abort(_("unknown format %d") % format)
2337
2337
2338 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2338 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2339 if generaldelta:
2339 if generaldelta:
2340 basehdr = ' delta'
2340 basehdr = ' delta'
2341 else:
2341 else:
2342 basehdr = ' base'
2342 basehdr = ' base'
2343
2343
2344 if ui.debugflag:
2344 if ui.debugflag:
2345 shortfn = hex
2345 shortfn = hex
2346 else:
2346 else:
2347 shortfn = short
2347 shortfn = short
2348
2348
2349 # There might not be anything in r, so have a sane default
2349 # There might not be anything in r, so have a sane default
2350 idlen = 12
2350 idlen = 12
2351 for i in r:
2351 for i in r:
2352 idlen = len(shortfn(r.node(i)))
2352 idlen = len(shortfn(r.node(i)))
2353 break
2353 break
2354
2354
2355 if format == 0:
2355 if format == 0:
2356 ui.write(" rev offset length " + basehdr + " linkrev"
2356 ui.write(" rev offset length " + basehdr + " linkrev"
2357 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2357 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2358 elif format == 1:
2358 elif format == 1:
2359 ui.write(" rev flag offset length"
2359 ui.write(" rev flag offset length"
2360 " size " + basehdr + " link p1 p2"
2360 " size " + basehdr + " link p1 p2"
2361 " %s\n" % "nodeid".rjust(idlen))
2361 " %s\n" % "nodeid".rjust(idlen))
2362
2362
2363 for i in r:
2363 for i in r:
2364 node = r.node(i)
2364 node = r.node(i)
2365 if generaldelta:
2365 if generaldelta:
2366 base = r.deltaparent(i)
2366 base = r.deltaparent(i)
2367 else:
2367 else:
2368 base = r.chainbase(i)
2368 base = r.chainbase(i)
2369 if format == 0:
2369 if format == 0:
2370 try:
2370 try:
2371 pp = r.parents(node)
2371 pp = r.parents(node)
2372 except Exception:
2372 except Exception:
2373 pp = [nullid, nullid]
2373 pp = [nullid, nullid]
2374 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2374 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2375 i, r.start(i), r.length(i), base, r.linkrev(i),
2375 i, r.start(i), r.length(i), base, r.linkrev(i),
2376 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2376 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2377 elif format == 1:
2377 elif format == 1:
2378 pr = r.parentrevs(i)
2378 pr = r.parentrevs(i)
2379 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2379 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2380 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2380 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2381 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2381 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2382
2382
2383 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2383 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2384 def debugindexdot(ui, repo, file_):
2384 def debugindexdot(ui, repo, file_):
2385 """dump an index DAG as a graphviz dot file"""
2385 """dump an index DAG as a graphviz dot file"""
2386 r = None
2386 r = None
2387 if repo:
2387 if repo:
2388 filelog = repo.file(file_)
2388 filelog = repo.file(file_)
2389 if len(filelog):
2389 if len(filelog):
2390 r = filelog
2390 r = filelog
2391 if not r:
2391 if not r:
2392 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2392 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2393 ui.write(("digraph G {\n"))
2393 ui.write(("digraph G {\n"))
2394 for i in r:
2394 for i in r:
2395 node = r.node(i)
2395 node = r.node(i)
2396 pp = r.parents(node)
2396 pp = r.parents(node)
2397 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2397 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2398 if pp[1] != nullid:
2398 if pp[1] != nullid:
2399 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2399 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2400 ui.write("}\n")
2400 ui.write("}\n")
2401
2401
2402 @command('debuginstall', [], '', norepo=True)
2402 @command('debuginstall', [], '', norepo=True)
2403 def debuginstall(ui):
2403 def debuginstall(ui):
2404 '''test Mercurial installation
2404 '''test Mercurial installation
2405
2405
2406 Returns 0 on success.
2406 Returns 0 on success.
2407 '''
2407 '''
2408
2408
2409 def writetemp(contents):
2409 def writetemp(contents):
2410 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2410 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2411 f = os.fdopen(fd, "wb")
2411 f = os.fdopen(fd, "wb")
2412 f.write(contents)
2412 f.write(contents)
2413 f.close()
2413 f.close()
2414 return name
2414 return name
2415
2415
2416 problems = 0
2416 problems = 0
2417
2417
2418 # encoding
2418 # encoding
2419 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2419 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2420 try:
2420 try:
2421 encoding.fromlocal("test")
2421 encoding.fromlocal("test")
2422 except error.Abort as inst:
2422 except error.Abort as inst:
2423 ui.write(" %s\n" % inst)
2423 ui.write(" %s\n" % inst)
2424 ui.write(_(" (check that your locale is properly set)\n"))
2424 ui.write(_(" (check that your locale is properly set)\n"))
2425 problems += 1
2425 problems += 1
2426
2426
2427 # Python
2427 # Python
2428 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2428 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2429 ui.status(_("checking Python version (%s)\n")
2429 ui.status(_("checking Python version (%s)\n")
2430 % ("%s.%s.%s" % sys.version_info[:3]))
2430 % ("%s.%s.%s" % sys.version_info[:3]))
2431 ui.status(_("checking Python lib (%s)...\n")
2431 ui.status(_("checking Python lib (%s)...\n")
2432 % os.path.dirname(os.__file__))
2432 % os.path.dirname(os.__file__))
2433
2433
2434 # compiled modules
2434 # compiled modules
2435 ui.status(_("checking installed modules (%s)...\n")
2435 ui.status(_("checking installed modules (%s)...\n")
2436 % os.path.dirname(__file__))
2436 % os.path.dirname(__file__))
2437 try:
2437 try:
2438 import bdiff, mpatch, base85, osutil
2438 import bdiff, mpatch, base85, osutil
2439 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2439 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2440 except Exception as inst:
2440 except Exception as inst:
2441 ui.write(" %s\n" % inst)
2441 ui.write(" %s\n" % inst)
2442 ui.write(_(" One or more extensions could not be found"))
2442 ui.write(_(" One or more extensions could not be found"))
2443 ui.write(_(" (check that you compiled the extensions)\n"))
2443 ui.write(_(" (check that you compiled the extensions)\n"))
2444 problems += 1
2444 problems += 1
2445
2445
2446 # templates
2446 # templates
2447 import templater
2447 import templater
2448 p = templater.templatepaths()
2448 p = templater.templatepaths()
2449 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2449 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2450 if p:
2450 if p:
2451 m = templater.templatepath("map-cmdline.default")
2451 m = templater.templatepath("map-cmdline.default")
2452 if m:
2452 if m:
2453 # template found, check if it is working
2453 # template found, check if it is working
2454 try:
2454 try:
2455 templater.templater(m)
2455 templater.templater(m)
2456 except Exception as inst:
2456 except Exception as inst:
2457 ui.write(" %s\n" % inst)
2457 ui.write(" %s\n" % inst)
2458 p = None
2458 p = None
2459 else:
2459 else:
2460 ui.write(_(" template 'default' not found\n"))
2460 ui.write(_(" template 'default' not found\n"))
2461 p = None
2461 p = None
2462 else:
2462 else:
2463 ui.write(_(" no template directories found\n"))
2463 ui.write(_(" no template directories found\n"))
2464 if not p:
2464 if not p:
2465 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2465 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2466 problems += 1
2466 problems += 1
2467
2467
2468 # editor
2468 # editor
2469 ui.status(_("checking commit editor...\n"))
2469 ui.status(_("checking commit editor...\n"))
2470 editor = ui.geteditor()
2470 editor = ui.geteditor()
2471 editor = util.expandpath(editor)
2471 editor = util.expandpath(editor)
2472 cmdpath = util.findexe(shlex.split(editor)[0])
2472 cmdpath = util.findexe(shlex.split(editor)[0])
2473 if not cmdpath:
2473 if not cmdpath:
2474 if editor == 'vi':
2474 if editor == 'vi':
2475 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2475 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2476 ui.write(_(" (specify a commit editor in your configuration"
2476 ui.write(_(" (specify a commit editor in your configuration"
2477 " file)\n"))
2477 " file)\n"))
2478 else:
2478 else:
2479 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2479 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2480 ui.write(_(" (specify a commit editor in your configuration"
2480 ui.write(_(" (specify a commit editor in your configuration"
2481 " file)\n"))
2481 " file)\n"))
2482 problems += 1
2482 problems += 1
2483
2483
2484 # check username
2484 # check username
2485 ui.status(_("checking username...\n"))
2485 ui.status(_("checking username...\n"))
2486 try:
2486 try:
2487 ui.username()
2487 ui.username()
2488 except error.Abort as e:
2488 except error.Abort as e:
2489 ui.write(" %s\n" % e)
2489 ui.write(" %s\n" % e)
2490 ui.write(_(" (specify a username in your configuration file)\n"))
2490 ui.write(_(" (specify a username in your configuration file)\n"))
2491 problems += 1
2491 problems += 1
2492
2492
2493 if not problems:
2493 if not problems:
2494 ui.status(_("no problems detected\n"))
2494 ui.status(_("no problems detected\n"))
2495 else:
2495 else:
2496 ui.write(_("%s problems detected,"
2496 ui.write(_("%s problems detected,"
2497 " please check your install!\n") % problems)
2497 " please check your install!\n") % problems)
2498
2498
2499 return problems
2499 return problems
2500
2500
2501 @command('debugknown', [], _('REPO ID...'), norepo=True)
2501 @command('debugknown', [], _('REPO ID...'), norepo=True)
2502 def debugknown(ui, repopath, *ids, **opts):
2502 def debugknown(ui, repopath, *ids, **opts):
2503 """test whether node ids are known to a repo
2503 """test whether node ids are known to a repo
2504
2504
2505 Every ID must be a full-length hex node id string. Returns a list of 0s
2505 Every ID must be a full-length hex node id string. Returns a list of 0s
2506 and 1s indicating unknown/known.
2506 and 1s indicating unknown/known.
2507 """
2507 """
2508 repo = hg.peer(ui, opts, repopath)
2508 repo = hg.peer(ui, opts, repopath)
2509 if not repo.capable('known'):
2509 if not repo.capable('known'):
2510 raise error.Abort("known() not supported by target repository")
2510 raise error.Abort("known() not supported by target repository")
2511 flags = repo.known([bin(s) for s in ids])
2511 flags = repo.known([bin(s) for s in ids])
2512 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2512 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2513
2513
2514 @command('debuglabelcomplete', [], _('LABEL...'))
2514 @command('debuglabelcomplete', [], _('LABEL...'))
2515 def debuglabelcomplete(ui, repo, *args):
2515 def debuglabelcomplete(ui, repo, *args):
2516 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2516 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2517 debugnamecomplete(ui, repo, *args)
2517 debugnamecomplete(ui, repo, *args)
2518
2518
2519 @command('debugmergestate', [], '')
2519 @command('debugmergestate', [], '')
2520 def debugmergestate(ui, repo, *args):
2520 def debugmergestate(ui, repo, *args):
2521 """print merge state
2521 """print merge state
2522
2522
2523 Use --verbose to print out information about whether v1 or v2 merge state
2523 Use --verbose to print out information about whether v1 or v2 merge state
2524 was chosen."""
2524 was chosen."""
2525 def printrecords(version):
2525 def printrecords(version):
2526 ui.write(('* version %s records\n') % version)
2526 ui.write(('* version %s records\n') % version)
2527 if version == 1:
2527 if version == 1:
2528 records = v1records
2528 records = v1records
2529 else:
2529 else:
2530 records = v2records
2530 records = v2records
2531
2531
2532 for rtype, record in records:
2532 for rtype, record in records:
2533 # pretty print some record types
2533 # pretty print some record types
2534 if rtype == 'L':
2534 if rtype == 'L':
2535 ui.write(('local: %s\n') % record)
2535 ui.write(('local: %s\n') % record)
2536 elif rtype == 'O':
2536 elif rtype == 'O':
2537 ui.write(('other: %s\n') % record)
2537 ui.write(('other: %s\n') % record)
2538 elif rtype == 'm':
2538 elif rtype == 'm':
2539 driver, mdstate = record.split('\0', 1)
2539 driver, mdstate = record.split('\0', 1)
2540 ui.write(('merge driver: %s (state "%s")\n')
2540 ui.write(('merge driver: %s (state "%s")\n')
2541 % (driver, mdstate))
2541 % (driver, mdstate))
2542 elif rtype in 'FD':
2542 elif rtype in 'FD':
2543 r = record.split('\0')
2543 r = record.split('\0')
2544 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2544 f, state, hash, lfile, afile, anode, ofile = r[0:7]
2545 if version == 1:
2545 if version == 1:
2546 onode = 'not stored in v1 format'
2546 onode = 'not stored in v1 format'
2547 flags = r[7]
2547 flags = r[7]
2548 else:
2548 else:
2549 onode, flags = r[7:9]
2549 onode, flags = r[7:9]
2550 ui.write(('file: %s (state "%s", hash %s)\n')
2550 ui.write(('file: %s (state "%s", hash %s)\n')
2551 % (f, state, hash))
2551 % (f, state, hash))
2552 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2552 ui.write((' local path: %s (flags "%s")\n') % (lfile, flags))
2553 ui.write((' ancestor path: %s (node %s)\n') % (afile, anode))
2553 ui.write((' ancestor path: %s (node %s)\n') % (afile, anode))
2554 ui.write((' other path: %s (node %s)\n') % (ofile, onode))
2554 ui.write((' other path: %s (node %s)\n') % (ofile, onode))
2555 else:
2555 else:
2556 ui.write(('unrecognized entry: %s\t%s\n')
2556 ui.write(('unrecognized entry: %s\t%s\n')
2557 % (rtype, record.replace('\0', '\t')))
2557 % (rtype, record.replace('\0', '\t')))
2558
2558
2559 ms = mergemod.mergestate(repo)
2559 ms = mergemod.mergestate(repo)
2560
2560
2561 # sort so that reasonable information is on top
2561 # sort so that reasonable information is on top
2562 v1records = ms._readrecordsv1()
2562 v1records = ms._readrecordsv1()
2563 v2records = ms._readrecordsv2()
2563 v2records = ms._readrecordsv2()
2564 order = 'LOm'
2564 order = 'LOm'
2565 def key(r):
2565 def key(r):
2566 idx = order.find(r[0])
2566 idx = order.find(r[0])
2567 if idx == -1:
2567 if idx == -1:
2568 return (1, r[1])
2568 return (1, r[1])
2569 else:
2569 else:
2570 return (0, idx)
2570 return (0, idx)
2571 v1records.sort(key=key)
2571 v1records.sort(key=key)
2572 v2records.sort(key=key)
2572 v2records.sort(key=key)
2573
2573
2574 if not v1records and not v2records:
2574 if not v1records and not v2records:
2575 ui.write(('no merge state found\n'))
2575 ui.write(('no merge state found\n'))
2576 elif not v2records:
2576 elif not v2records:
2577 ui.note(('no version 2 merge state\n'))
2577 ui.note(('no version 2 merge state\n'))
2578 printrecords(1)
2578 printrecords(1)
2579 elif ms._v1v2match(v1records, v2records):
2579 elif ms._v1v2match(v1records, v2records):
2580 ui.note(('v1 and v2 states match: using v2\n'))
2580 ui.note(('v1 and v2 states match: using v2\n'))
2581 printrecords(2)
2581 printrecords(2)
2582 else:
2582 else:
2583 ui.note(('v1 and v2 states mismatch: using v1\n'))
2583 ui.note(('v1 and v2 states mismatch: using v1\n'))
2584 printrecords(1)
2584 printrecords(1)
2585 if ui.verbose:
2585 if ui.verbose:
2586 printrecords(2)
2586 printrecords(2)
2587
2587
2588 @command('debugnamecomplete', [], _('NAME...'))
2588 @command('debugnamecomplete', [], _('NAME...'))
2589 def debugnamecomplete(ui, repo, *args):
2589 def debugnamecomplete(ui, repo, *args):
2590 '''complete "names" - tags, open branch names, bookmark names'''
2590 '''complete "names" - tags, open branch names, bookmark names'''
2591
2591
2592 names = set()
2592 names = set()
2593 # since we previously only listed open branches, we will handle that
2593 # since we previously only listed open branches, we will handle that
2594 # specially (after this for loop)
2594 # specially (after this for loop)
2595 for name, ns in repo.names.iteritems():
2595 for name, ns in repo.names.iteritems():
2596 if name != 'branches':
2596 if name != 'branches':
2597 names.update(ns.listnames(repo))
2597 names.update(ns.listnames(repo))
2598 names.update(tag for (tag, heads, tip, closed)
2598 names.update(tag for (tag, heads, tip, closed)
2599 in repo.branchmap().iterbranches() if not closed)
2599 in repo.branchmap().iterbranches() if not closed)
2600 completions = set()
2600 completions = set()
2601 if not args:
2601 if not args:
2602 args = ['']
2602 args = ['']
2603 for a in args:
2603 for a in args:
2604 completions.update(n for n in names if n.startswith(a))
2604 completions.update(n for n in names if n.startswith(a))
2605 ui.write('\n'.join(sorted(completions)))
2605 ui.write('\n'.join(sorted(completions)))
2606 ui.write('\n')
2606 ui.write('\n')
2607
2607
2608 @command('debuglocks',
2608 @command('debuglocks',
2609 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2609 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2610 ('W', 'force-wlock', None,
2610 ('W', 'force-wlock', None,
2611 _('free the working state lock (DANGEROUS)'))],
2611 _('free the working state lock (DANGEROUS)'))],
2612 _('[OPTION]...'))
2612 _('[OPTION]...'))
2613 def debuglocks(ui, repo, **opts):
2613 def debuglocks(ui, repo, **opts):
2614 """show or modify state of locks
2614 """show or modify state of locks
2615
2615
2616 By default, this command will show which locks are held. This
2616 By default, this command will show which locks are held. This
2617 includes the user and process holding the lock, the amount of time
2617 includes the user and process holding the lock, the amount of time
2618 the lock has been held, and the machine name where the process is
2618 the lock has been held, and the machine name where the process is
2619 running if it's not local.
2619 running if it's not local.
2620
2620
2621 Locks protect the integrity of Mercurial's data, so should be
2621 Locks protect the integrity of Mercurial's data, so should be
2622 treated with care. System crashes or other interruptions may cause
2622 treated with care. System crashes or other interruptions may cause
2623 locks to not be properly released, though Mercurial will usually
2623 locks to not be properly released, though Mercurial will usually
2624 detect and remove such stale locks automatically.
2624 detect and remove such stale locks automatically.
2625
2625
2626 However, detecting stale locks may not always be possible (for
2626 However, detecting stale locks may not always be possible (for
2627 instance, on a shared filesystem). Removing locks may also be
2627 instance, on a shared filesystem). Removing locks may also be
2628 blocked by filesystem permissions.
2628 blocked by filesystem permissions.
2629
2629
2630 Returns 0 if no locks are held.
2630 Returns 0 if no locks are held.
2631
2631
2632 """
2632 """
2633
2633
2634 if opts.get('force_lock'):
2634 if opts.get('force_lock'):
2635 repo.svfs.unlink('lock')
2635 repo.svfs.unlink('lock')
2636 if opts.get('force_wlock'):
2636 if opts.get('force_wlock'):
2637 repo.vfs.unlink('wlock')
2637 repo.vfs.unlink('wlock')
2638 if opts.get('force_lock') or opts.get('force_lock'):
2638 if opts.get('force_lock') or opts.get('force_lock'):
2639 return 0
2639 return 0
2640
2640
2641 now = time.time()
2641 now = time.time()
2642 held = 0
2642 held = 0
2643
2643
2644 def report(vfs, name, method):
2644 def report(vfs, name, method):
2645 # this causes stale locks to get reaped for more accurate reporting
2645 # this causes stale locks to get reaped for more accurate reporting
2646 try:
2646 try:
2647 l = method(False)
2647 l = method(False)
2648 except error.LockHeld:
2648 except error.LockHeld:
2649 l = None
2649 l = None
2650
2650
2651 if l:
2651 if l:
2652 l.release()
2652 l.release()
2653 else:
2653 else:
2654 try:
2654 try:
2655 stat = vfs.lstat(name)
2655 stat = vfs.lstat(name)
2656 age = now - stat.st_mtime
2656 age = now - stat.st_mtime
2657 user = util.username(stat.st_uid)
2657 user = util.username(stat.st_uid)
2658 locker = vfs.readlock(name)
2658 locker = vfs.readlock(name)
2659 if ":" in locker:
2659 if ":" in locker:
2660 host, pid = locker.split(':')
2660 host, pid = locker.split(':')
2661 if host == socket.gethostname():
2661 if host == socket.gethostname():
2662 locker = 'user %s, process %s' % (user, pid)
2662 locker = 'user %s, process %s' % (user, pid)
2663 else:
2663 else:
2664 locker = 'user %s, process %s, host %s' \
2664 locker = 'user %s, process %s, host %s' \
2665 % (user, pid, host)
2665 % (user, pid, host)
2666 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2666 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2667 return 1
2667 return 1
2668 except OSError as e:
2668 except OSError as e:
2669 if e.errno != errno.ENOENT:
2669 if e.errno != errno.ENOENT:
2670 raise
2670 raise
2671
2671
2672 ui.write("%-6s free\n" % (name + ":"))
2672 ui.write("%-6s free\n" % (name + ":"))
2673 return 0
2673 return 0
2674
2674
2675 held += report(repo.svfs, "lock", repo.lock)
2675 held += report(repo.svfs, "lock", repo.lock)
2676 held += report(repo.vfs, "wlock", repo.wlock)
2676 held += report(repo.vfs, "wlock", repo.wlock)
2677
2677
2678 return held
2678 return held
2679
2679
2680 @command('debugobsolete',
2680 @command('debugobsolete',
2681 [('', 'flags', 0, _('markers flag')),
2681 [('', 'flags', 0, _('markers flag')),
2682 ('', 'record-parents', False,
2682 ('', 'record-parents', False,
2683 _('record parent information for the precursor')),
2683 _('record parent information for the precursor')),
2684 ('r', 'rev', [], _('display markers relevant to REV')),
2684 ('r', 'rev', [], _('display markers relevant to REV')),
2685 ] + commitopts2,
2685 ] + commitopts2,
2686 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2686 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2687 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2687 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2688 """create arbitrary obsolete marker
2688 """create arbitrary obsolete marker
2689
2689
2690 With no arguments, displays the list of obsolescence markers."""
2690 With no arguments, displays the list of obsolescence markers."""
2691
2691
2692 def parsenodeid(s):
2692 def parsenodeid(s):
2693 try:
2693 try:
2694 # We do not use revsingle/revrange functions here to accept
2694 # We do not use revsingle/revrange functions here to accept
2695 # arbitrary node identifiers, possibly not present in the
2695 # arbitrary node identifiers, possibly not present in the
2696 # local repository.
2696 # local repository.
2697 n = bin(s)
2697 n = bin(s)
2698 if len(n) != len(nullid):
2698 if len(n) != len(nullid):
2699 raise TypeError()
2699 raise TypeError()
2700 return n
2700 return n
2701 except TypeError:
2701 except TypeError:
2702 raise error.Abort('changeset references must be full hexadecimal '
2702 raise error.Abort('changeset references must be full hexadecimal '
2703 'node identifiers')
2703 'node identifiers')
2704
2704
2705 if precursor is not None:
2705 if precursor is not None:
2706 if opts['rev']:
2706 if opts['rev']:
2707 raise error.Abort('cannot select revision when creating marker')
2707 raise error.Abort('cannot select revision when creating marker')
2708 metadata = {}
2708 metadata = {}
2709 metadata['user'] = opts['user'] or ui.username()
2709 metadata['user'] = opts['user'] or ui.username()
2710 succs = tuple(parsenodeid(succ) for succ in successors)
2710 succs = tuple(parsenodeid(succ) for succ in successors)
2711 l = repo.lock()
2711 l = repo.lock()
2712 try:
2712 try:
2713 tr = repo.transaction('debugobsolete')
2713 tr = repo.transaction('debugobsolete')
2714 try:
2714 try:
2715 date = opts.get('date')
2715 date = opts.get('date')
2716 if date:
2716 if date:
2717 date = util.parsedate(date)
2717 date = util.parsedate(date)
2718 else:
2718 else:
2719 date = None
2719 date = None
2720 prec = parsenodeid(precursor)
2720 prec = parsenodeid(precursor)
2721 parents = None
2721 parents = None
2722 if opts['record_parents']:
2722 if opts['record_parents']:
2723 if prec not in repo.unfiltered():
2723 if prec not in repo.unfiltered():
2724 raise error.Abort('cannot used --record-parents on '
2724 raise error.Abort('cannot used --record-parents on '
2725 'unknown changesets')
2725 'unknown changesets')
2726 parents = repo.unfiltered()[prec].parents()
2726 parents = repo.unfiltered()[prec].parents()
2727 parents = tuple(p.node() for p in parents)
2727 parents = tuple(p.node() for p in parents)
2728 repo.obsstore.create(tr, prec, succs, opts['flags'],
2728 repo.obsstore.create(tr, prec, succs, opts['flags'],
2729 parents=parents, date=date,
2729 parents=parents, date=date,
2730 metadata=metadata)
2730 metadata=metadata)
2731 tr.close()
2731 tr.close()
2732 except ValueError as exc:
2732 except ValueError as exc:
2733 raise error.Abort(_('bad obsmarker input: %s') % exc)
2733 raise error.Abort(_('bad obsmarker input: %s') % exc)
2734 finally:
2734 finally:
2735 tr.release()
2735 tr.release()
2736 finally:
2736 finally:
2737 l.release()
2737 l.release()
2738 else:
2738 else:
2739 if opts['rev']:
2739 if opts['rev']:
2740 revs = scmutil.revrange(repo, opts['rev'])
2740 revs = scmutil.revrange(repo, opts['rev'])
2741 nodes = [repo[r].node() for r in revs]
2741 nodes = [repo[r].node() for r in revs]
2742 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2742 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2743 markers.sort(key=lambda x: x._data)
2743 markers.sort(key=lambda x: x._data)
2744 else:
2744 else:
2745 markers = obsolete.getmarkers(repo)
2745 markers = obsolete.getmarkers(repo)
2746
2746
2747 for m in markers:
2747 for m in markers:
2748 cmdutil.showmarker(ui, m)
2748 cmdutil.showmarker(ui, m)
2749
2749
2750 @command('debugpathcomplete',
2750 @command('debugpathcomplete',
2751 [('f', 'full', None, _('complete an entire path')),
2751 [('f', 'full', None, _('complete an entire path')),
2752 ('n', 'normal', None, _('show only normal files')),
2752 ('n', 'normal', None, _('show only normal files')),
2753 ('a', 'added', None, _('show only added files')),
2753 ('a', 'added', None, _('show only added files')),
2754 ('r', 'removed', None, _('show only removed files'))],
2754 ('r', 'removed', None, _('show only removed files'))],
2755 _('FILESPEC...'))
2755 _('FILESPEC...'))
2756 def debugpathcomplete(ui, repo, *specs, **opts):
2756 def debugpathcomplete(ui, repo, *specs, **opts):
2757 '''complete part or all of a tracked path
2757 '''complete part or all of a tracked path
2758
2758
2759 This command supports shells that offer path name completion. It
2759 This command supports shells that offer path name completion. It
2760 currently completes only files already known to the dirstate.
2760 currently completes only files already known to the dirstate.
2761
2761
2762 Completion extends only to the next path segment unless
2762 Completion extends only to the next path segment unless
2763 --full is specified, in which case entire paths are used.'''
2763 --full is specified, in which case entire paths are used.'''
2764
2764
2765 def complete(path, acceptable):
2765 def complete(path, acceptable):
2766 dirstate = repo.dirstate
2766 dirstate = repo.dirstate
2767 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2767 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2768 rootdir = repo.root + os.sep
2768 rootdir = repo.root + os.sep
2769 if spec != repo.root and not spec.startswith(rootdir):
2769 if spec != repo.root and not spec.startswith(rootdir):
2770 return [], []
2770 return [], []
2771 if os.path.isdir(spec):
2771 if os.path.isdir(spec):
2772 spec += '/'
2772 spec += '/'
2773 spec = spec[len(rootdir):]
2773 spec = spec[len(rootdir):]
2774 fixpaths = os.sep != '/'
2774 fixpaths = os.sep != '/'
2775 if fixpaths:
2775 if fixpaths:
2776 spec = spec.replace(os.sep, '/')
2776 spec = spec.replace(os.sep, '/')
2777 speclen = len(spec)
2777 speclen = len(spec)
2778 fullpaths = opts['full']
2778 fullpaths = opts['full']
2779 files, dirs = set(), set()
2779 files, dirs = set(), set()
2780 adddir, addfile = dirs.add, files.add
2780 adddir, addfile = dirs.add, files.add
2781 for f, st in dirstate.iteritems():
2781 for f, st in dirstate.iteritems():
2782 if f.startswith(spec) and st[0] in acceptable:
2782 if f.startswith(spec) and st[0] in acceptable:
2783 if fixpaths:
2783 if fixpaths:
2784 f = f.replace('/', os.sep)
2784 f = f.replace('/', os.sep)
2785 if fullpaths:
2785 if fullpaths:
2786 addfile(f)
2786 addfile(f)
2787 continue
2787 continue
2788 s = f.find(os.sep, speclen)
2788 s = f.find(os.sep, speclen)
2789 if s >= 0:
2789 if s >= 0:
2790 adddir(f[:s])
2790 adddir(f[:s])
2791 else:
2791 else:
2792 addfile(f)
2792 addfile(f)
2793 return files, dirs
2793 return files, dirs
2794
2794
2795 acceptable = ''
2795 acceptable = ''
2796 if opts['normal']:
2796 if opts['normal']:
2797 acceptable += 'nm'
2797 acceptable += 'nm'
2798 if opts['added']:
2798 if opts['added']:
2799 acceptable += 'a'
2799 acceptable += 'a'
2800 if opts['removed']:
2800 if opts['removed']:
2801 acceptable += 'r'
2801 acceptable += 'r'
2802 cwd = repo.getcwd()
2802 cwd = repo.getcwd()
2803 if not specs:
2803 if not specs:
2804 specs = ['.']
2804 specs = ['.']
2805
2805
2806 files, dirs = set(), set()
2806 files, dirs = set(), set()
2807 for spec in specs:
2807 for spec in specs:
2808 f, d = complete(spec, acceptable or 'nmar')
2808 f, d = complete(spec, acceptable or 'nmar')
2809 files.update(f)
2809 files.update(f)
2810 dirs.update(d)
2810 dirs.update(d)
2811 files.update(dirs)
2811 files.update(dirs)
2812 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2812 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2813 ui.write('\n')
2813 ui.write('\n')
2814
2814
2815 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2815 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2816 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2816 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2817 '''access the pushkey key/value protocol
2817 '''access the pushkey key/value protocol
2818
2818
2819 With two args, list the keys in the given namespace.
2819 With two args, list the keys in the given namespace.
2820
2820
2821 With five args, set a key to new if it currently is set to old.
2821 With five args, set a key to new if it currently is set to old.
2822 Reports success or failure.
2822 Reports success or failure.
2823 '''
2823 '''
2824
2824
2825 target = hg.peer(ui, {}, repopath)
2825 target = hg.peer(ui, {}, repopath)
2826 if keyinfo:
2826 if keyinfo:
2827 key, old, new = keyinfo
2827 key, old, new = keyinfo
2828 r = target.pushkey(namespace, key, old, new)
2828 r = target.pushkey(namespace, key, old, new)
2829 ui.status(str(r) + '\n')
2829 ui.status(str(r) + '\n')
2830 return not r
2830 return not r
2831 else:
2831 else:
2832 for k, v in sorted(target.listkeys(namespace).iteritems()):
2832 for k, v in sorted(target.listkeys(namespace).iteritems()):
2833 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2833 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2834 v.encode('string-escape')))
2834 v.encode('string-escape')))
2835
2835
2836 @command('debugpvec', [], _('A B'))
2836 @command('debugpvec', [], _('A B'))
2837 def debugpvec(ui, repo, a, b=None):
2837 def debugpvec(ui, repo, a, b=None):
2838 ca = scmutil.revsingle(repo, a)
2838 ca = scmutil.revsingle(repo, a)
2839 cb = scmutil.revsingle(repo, b)
2839 cb = scmutil.revsingle(repo, b)
2840 pa = pvec.ctxpvec(ca)
2840 pa = pvec.ctxpvec(ca)
2841 pb = pvec.ctxpvec(cb)
2841 pb = pvec.ctxpvec(cb)
2842 if pa == pb:
2842 if pa == pb:
2843 rel = "="
2843 rel = "="
2844 elif pa > pb:
2844 elif pa > pb:
2845 rel = ">"
2845 rel = ">"
2846 elif pa < pb:
2846 elif pa < pb:
2847 rel = "<"
2847 rel = "<"
2848 elif pa | pb:
2848 elif pa | pb:
2849 rel = "|"
2849 rel = "|"
2850 ui.write(_("a: %s\n") % pa)
2850 ui.write(_("a: %s\n") % pa)
2851 ui.write(_("b: %s\n") % pb)
2851 ui.write(_("b: %s\n") % pb)
2852 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2852 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2853 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2853 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2854 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2854 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2855 pa.distance(pb), rel))
2855 pa.distance(pb), rel))
2856
2856
2857 @command('debugrebuilddirstate|debugrebuildstate',
2857 @command('debugrebuilddirstate|debugrebuildstate',
2858 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
2858 [('r', 'rev', '', _('revision to rebuild to'), _('REV')),
2859 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
2859 ('', 'minimal', None, _('only rebuild files that are inconsistent with '
2860 'the working copy parent')),
2860 'the working copy parent')),
2861 ],
2861 ],
2862 _('[-r REV]'))
2862 _('[-r REV]'))
2863 def debugrebuilddirstate(ui, repo, rev, **opts):
2863 def debugrebuilddirstate(ui, repo, rev, **opts):
2864 """rebuild the dirstate as it would look like for the given revision
2864 """rebuild the dirstate as it would look like for the given revision
2865
2865
2866 If no revision is specified the first current parent will be used.
2866 If no revision is specified the first current parent will be used.
2867
2867
2868 The dirstate will be set to the files of the given revision.
2868 The dirstate will be set to the files of the given revision.
2869 The actual working directory content or existing dirstate
2869 The actual working directory content or existing dirstate
2870 information such as adds or removes is not considered.
2870 information such as adds or removes is not considered.
2871
2871
2872 ``minimal`` will only rebuild the dirstate status for files that claim to be
2872 ``minimal`` will only rebuild the dirstate status for files that claim to be
2873 tracked but are not in the parent manifest, or that exist in the parent
2873 tracked but are not in the parent manifest, or that exist in the parent
2874 manifest but are not in the dirstate. It will not change adds, removes, or
2874 manifest but are not in the dirstate. It will not change adds, removes, or
2875 modified files that are in the working copy parent.
2875 modified files that are in the working copy parent.
2876
2876
2877 One use of this command is to make the next :hg:`status` invocation
2877 One use of this command is to make the next :hg:`status` invocation
2878 check the actual file content.
2878 check the actual file content.
2879 """
2879 """
2880 ctx = scmutil.revsingle(repo, rev)
2880 ctx = scmutil.revsingle(repo, rev)
2881 wlock = repo.wlock()
2881 wlock = repo.wlock()
2882 try:
2882 try:
2883 dirstate = repo.dirstate
2883 dirstate = repo.dirstate
2884
2884
2885 # See command doc for what minimal does.
2885 # See command doc for what minimal does.
2886 if opts.get('minimal'):
2886 if opts.get('minimal'):
2887 dirstatefiles = set(dirstate)
2887 dirstatefiles = set(dirstate)
2888 ctxfiles = set(ctx.manifest().keys())
2888 ctxfiles = set(ctx.manifest().keys())
2889 for file in (dirstatefiles | ctxfiles):
2889 for file in (dirstatefiles | ctxfiles):
2890 indirstate = file in dirstatefiles
2890 indirstate = file in dirstatefiles
2891 inctx = file in ctxfiles
2891 inctx = file in ctxfiles
2892
2892
2893 if indirstate and not inctx and dirstate[file] != 'a':
2893 if indirstate and not inctx and dirstate[file] != 'a':
2894 dirstate.drop(file)
2894 dirstate.drop(file)
2895 elif inctx and not indirstate:
2895 elif inctx and not indirstate:
2896 dirstate.normallookup(file)
2896 dirstate.normallookup(file)
2897 else:
2897 else:
2898 dirstate.rebuild(ctx.node(), ctx.manifest())
2898 dirstate.rebuild(ctx.node(), ctx.manifest())
2899 finally:
2899 finally:
2900 wlock.release()
2900 wlock.release()
2901
2901
2902 @command('debugrebuildfncache', [], '')
2902 @command('debugrebuildfncache', [], '')
2903 def debugrebuildfncache(ui, repo):
2903 def debugrebuildfncache(ui, repo):
2904 """rebuild the fncache file"""
2904 """rebuild the fncache file"""
2905 repair.rebuildfncache(ui, repo)
2905 repair.rebuildfncache(ui, repo)
2906
2906
2907 @command('debugrename',
2907 @command('debugrename',
2908 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2908 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2909 _('[-r REV] FILE'))
2909 _('[-r REV] FILE'))
2910 def debugrename(ui, repo, file1, *pats, **opts):
2910 def debugrename(ui, repo, file1, *pats, **opts):
2911 """dump rename information"""
2911 """dump rename information"""
2912
2912
2913 ctx = scmutil.revsingle(repo, opts.get('rev'))
2913 ctx = scmutil.revsingle(repo, opts.get('rev'))
2914 m = scmutil.match(ctx, (file1,) + pats, opts)
2914 m = scmutil.match(ctx, (file1,) + pats, opts)
2915 for abs in ctx.walk(m):
2915 for abs in ctx.walk(m):
2916 fctx = ctx[abs]
2916 fctx = ctx[abs]
2917 o = fctx.filelog().renamed(fctx.filenode())
2917 o = fctx.filelog().renamed(fctx.filenode())
2918 rel = m.rel(abs)
2918 rel = m.rel(abs)
2919 if o:
2919 if o:
2920 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2920 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2921 else:
2921 else:
2922 ui.write(_("%s not renamed\n") % rel)
2922 ui.write(_("%s not renamed\n") % rel)
2923
2923
2924 @command('debugrevlog',
2924 @command('debugrevlog',
2925 [('c', 'changelog', False, _('open changelog')),
2925 [('c', 'changelog', False, _('open changelog')),
2926 ('m', 'manifest', False, _('open manifest')),
2926 ('m', 'manifest', False, _('open manifest')),
2927 ('', 'dir', False, _('open directory manifest')),
2927 ('', 'dir', False, _('open directory manifest')),
2928 ('d', 'dump', False, _('dump index data'))],
2928 ('d', 'dump', False, _('dump index data'))],
2929 _('-c|-m|FILE'),
2929 _('-c|-m|FILE'),
2930 optionalrepo=True)
2930 optionalrepo=True)
2931 def debugrevlog(ui, repo, file_=None, **opts):
2931 def debugrevlog(ui, repo, file_=None, **opts):
2932 """show data and statistics about a revlog"""
2932 """show data and statistics about a revlog"""
2933 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2933 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2934
2934
2935 if opts.get("dump"):
2935 if opts.get("dump"):
2936 numrevs = len(r)
2936 numrevs = len(r)
2937 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2937 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2938 " rawsize totalsize compression heads chainlen\n")
2938 " rawsize totalsize compression heads chainlen\n")
2939 ts = 0
2939 ts = 0
2940 heads = set()
2940 heads = set()
2941
2941
2942 for rev in xrange(numrevs):
2942 for rev in xrange(numrevs):
2943 dbase = r.deltaparent(rev)
2943 dbase = r.deltaparent(rev)
2944 if dbase == -1:
2944 if dbase == -1:
2945 dbase = rev
2945 dbase = rev
2946 cbase = r.chainbase(rev)
2946 cbase = r.chainbase(rev)
2947 clen = r.chainlen(rev)
2947 clen = r.chainlen(rev)
2948 p1, p2 = r.parentrevs(rev)
2948 p1, p2 = r.parentrevs(rev)
2949 rs = r.rawsize(rev)
2949 rs = r.rawsize(rev)
2950 ts = ts + rs
2950 ts = ts + rs
2951 heads -= set(r.parentrevs(rev))
2951 heads -= set(r.parentrevs(rev))
2952 heads.add(rev)
2952 heads.add(rev)
2953 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2953 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2954 "%11d %5d %8d\n" %
2954 "%11d %5d %8d\n" %
2955 (rev, p1, p2, r.start(rev), r.end(rev),
2955 (rev, p1, p2, r.start(rev), r.end(rev),
2956 r.start(dbase), r.start(cbase),
2956 r.start(dbase), r.start(cbase),
2957 r.start(p1), r.start(p2),
2957 r.start(p1), r.start(p2),
2958 rs, ts, ts / r.end(rev), len(heads), clen))
2958 rs, ts, ts / r.end(rev), len(heads), clen))
2959 return 0
2959 return 0
2960
2960
2961 v = r.version
2961 v = r.version
2962 format = v & 0xFFFF
2962 format = v & 0xFFFF
2963 flags = []
2963 flags = []
2964 gdelta = False
2964 gdelta = False
2965 if v & revlog.REVLOGNGINLINEDATA:
2965 if v & revlog.REVLOGNGINLINEDATA:
2966 flags.append('inline')
2966 flags.append('inline')
2967 if v & revlog.REVLOGGENERALDELTA:
2967 if v & revlog.REVLOGGENERALDELTA:
2968 gdelta = True
2968 gdelta = True
2969 flags.append('generaldelta')
2969 flags.append('generaldelta')
2970 if not flags:
2970 if not flags:
2971 flags = ['(none)']
2971 flags = ['(none)']
2972
2972
2973 nummerges = 0
2973 nummerges = 0
2974 numfull = 0
2974 numfull = 0
2975 numprev = 0
2975 numprev = 0
2976 nump1 = 0
2976 nump1 = 0
2977 nump2 = 0
2977 nump2 = 0
2978 numother = 0
2978 numother = 0
2979 nump1prev = 0
2979 nump1prev = 0
2980 nump2prev = 0
2980 nump2prev = 0
2981 chainlengths = []
2981 chainlengths = []
2982
2982
2983 datasize = [None, 0, 0L]
2983 datasize = [None, 0, 0L]
2984 fullsize = [None, 0, 0L]
2984 fullsize = [None, 0, 0L]
2985 deltasize = [None, 0, 0L]
2985 deltasize = [None, 0, 0L]
2986
2986
2987 def addsize(size, l):
2987 def addsize(size, l):
2988 if l[0] is None or size < l[0]:
2988 if l[0] is None or size < l[0]:
2989 l[0] = size
2989 l[0] = size
2990 if size > l[1]:
2990 if size > l[1]:
2991 l[1] = size
2991 l[1] = size
2992 l[2] += size
2992 l[2] += size
2993
2993
2994 numrevs = len(r)
2994 numrevs = len(r)
2995 for rev in xrange(numrevs):
2995 for rev in xrange(numrevs):
2996 p1, p2 = r.parentrevs(rev)
2996 p1, p2 = r.parentrevs(rev)
2997 delta = r.deltaparent(rev)
2997 delta = r.deltaparent(rev)
2998 if format > 0:
2998 if format > 0:
2999 addsize(r.rawsize(rev), datasize)
2999 addsize(r.rawsize(rev), datasize)
3000 if p2 != nullrev:
3000 if p2 != nullrev:
3001 nummerges += 1
3001 nummerges += 1
3002 size = r.length(rev)
3002 size = r.length(rev)
3003 if delta == nullrev:
3003 if delta == nullrev:
3004 chainlengths.append(0)
3004 chainlengths.append(0)
3005 numfull += 1
3005 numfull += 1
3006 addsize(size, fullsize)
3006 addsize(size, fullsize)
3007 else:
3007 else:
3008 chainlengths.append(chainlengths[delta] + 1)
3008 chainlengths.append(chainlengths[delta] + 1)
3009 addsize(size, deltasize)
3009 addsize(size, deltasize)
3010 if delta == rev - 1:
3010 if delta == rev - 1:
3011 numprev += 1
3011 numprev += 1
3012 if delta == p1:
3012 if delta == p1:
3013 nump1prev += 1
3013 nump1prev += 1
3014 elif delta == p2:
3014 elif delta == p2:
3015 nump2prev += 1
3015 nump2prev += 1
3016 elif delta == p1:
3016 elif delta == p1:
3017 nump1 += 1
3017 nump1 += 1
3018 elif delta == p2:
3018 elif delta == p2:
3019 nump2 += 1
3019 nump2 += 1
3020 elif delta != nullrev:
3020 elif delta != nullrev:
3021 numother += 1
3021 numother += 1
3022
3022
3023 # Adjust size min value for empty cases
3023 # Adjust size min value for empty cases
3024 for size in (datasize, fullsize, deltasize):
3024 for size in (datasize, fullsize, deltasize):
3025 if size[0] is None:
3025 if size[0] is None:
3026 size[0] = 0
3026 size[0] = 0
3027
3027
3028 numdeltas = numrevs - numfull
3028 numdeltas = numrevs - numfull
3029 numoprev = numprev - nump1prev - nump2prev
3029 numoprev = numprev - nump1prev - nump2prev
3030 totalrawsize = datasize[2]
3030 totalrawsize = datasize[2]
3031 datasize[2] /= numrevs
3031 datasize[2] /= numrevs
3032 fulltotal = fullsize[2]
3032 fulltotal = fullsize[2]
3033 fullsize[2] /= numfull
3033 fullsize[2] /= numfull
3034 deltatotal = deltasize[2]
3034 deltatotal = deltasize[2]
3035 if numrevs - numfull > 0:
3035 if numrevs - numfull > 0:
3036 deltasize[2] /= numrevs - numfull
3036 deltasize[2] /= numrevs - numfull
3037 totalsize = fulltotal + deltatotal
3037 totalsize = fulltotal + deltatotal
3038 avgchainlen = sum(chainlengths) / numrevs
3038 avgchainlen = sum(chainlengths) / numrevs
3039 maxchainlen = max(chainlengths)
3039 maxchainlen = max(chainlengths)
3040 compratio = totalrawsize / totalsize
3040 compratio = totalrawsize / totalsize
3041
3041
3042 basedfmtstr = '%%%dd\n'
3042 basedfmtstr = '%%%dd\n'
3043 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3043 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
3044
3044
3045 def dfmtstr(max):
3045 def dfmtstr(max):
3046 return basedfmtstr % len(str(max))
3046 return basedfmtstr % len(str(max))
3047 def pcfmtstr(max, padding=0):
3047 def pcfmtstr(max, padding=0):
3048 return basepcfmtstr % (len(str(max)), ' ' * padding)
3048 return basepcfmtstr % (len(str(max)), ' ' * padding)
3049
3049
3050 def pcfmt(value, total):
3050 def pcfmt(value, total):
3051 return (value, 100 * float(value) / total)
3051 return (value, 100 * float(value) / total)
3052
3052
3053 ui.write(('format : %d\n') % format)
3053 ui.write(('format : %d\n') % format)
3054 ui.write(('flags : %s\n') % ', '.join(flags))
3054 ui.write(('flags : %s\n') % ', '.join(flags))
3055
3055
3056 ui.write('\n')
3056 ui.write('\n')
3057 fmt = pcfmtstr(totalsize)
3057 fmt = pcfmtstr(totalsize)
3058 fmt2 = dfmtstr(totalsize)
3058 fmt2 = dfmtstr(totalsize)
3059 ui.write(('revisions : ') + fmt2 % numrevs)
3059 ui.write(('revisions : ') + fmt2 % numrevs)
3060 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3060 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
3061 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3061 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
3062 ui.write(('revisions : ') + fmt2 % numrevs)
3062 ui.write(('revisions : ') + fmt2 % numrevs)
3063 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3063 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
3064 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3064 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
3065 ui.write(('revision size : ') + fmt2 % totalsize)
3065 ui.write(('revision size : ') + fmt2 % totalsize)
3066 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3066 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
3067 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3067 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
3068
3068
3069 ui.write('\n')
3069 ui.write('\n')
3070 fmt = dfmtstr(max(avgchainlen, compratio))
3070 fmt = dfmtstr(max(avgchainlen, compratio))
3071 ui.write(('avg chain length : ') + fmt % avgchainlen)
3071 ui.write(('avg chain length : ') + fmt % avgchainlen)
3072 ui.write(('max chain length : ') + fmt % maxchainlen)
3072 ui.write(('max chain length : ') + fmt % maxchainlen)
3073 ui.write(('compression ratio : ') + fmt % compratio)
3073 ui.write(('compression ratio : ') + fmt % compratio)
3074
3074
3075 if format > 0:
3075 if format > 0:
3076 ui.write('\n')
3076 ui.write('\n')
3077 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3077 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
3078 % tuple(datasize))
3078 % tuple(datasize))
3079 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3079 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
3080 % tuple(fullsize))
3080 % tuple(fullsize))
3081 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3081 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
3082 % tuple(deltasize))
3082 % tuple(deltasize))
3083
3083
3084 if numdeltas > 0:
3084 if numdeltas > 0:
3085 ui.write('\n')
3085 ui.write('\n')
3086 fmt = pcfmtstr(numdeltas)
3086 fmt = pcfmtstr(numdeltas)
3087 fmt2 = pcfmtstr(numdeltas, 4)
3087 fmt2 = pcfmtstr(numdeltas, 4)
3088 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3088 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
3089 if numprev > 0:
3089 if numprev > 0:
3090 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3090 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
3091 numprev))
3091 numprev))
3092 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3092 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
3093 numprev))
3093 numprev))
3094 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3094 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
3095 numprev))
3095 numprev))
3096 if gdelta:
3096 if gdelta:
3097 ui.write(('deltas against p1 : ')
3097 ui.write(('deltas against p1 : ')
3098 + fmt % pcfmt(nump1, numdeltas))
3098 + fmt % pcfmt(nump1, numdeltas))
3099 ui.write(('deltas against p2 : ')
3099 ui.write(('deltas against p2 : ')
3100 + fmt % pcfmt(nump2, numdeltas))
3100 + fmt % pcfmt(nump2, numdeltas))
3101 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3101 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
3102 numdeltas))
3102 numdeltas))
3103
3103
3104 @command('debugrevspec',
3104 @command('debugrevspec',
3105 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3105 [('', 'optimize', None, _('print parsed tree after optimizing'))],
3106 ('REVSPEC'))
3106 ('REVSPEC'))
3107 def debugrevspec(ui, repo, expr, **opts):
3107 def debugrevspec(ui, repo, expr, **opts):
3108 """parse and apply a revision specification
3108 """parse and apply a revision specification
3109
3109
3110 Use --verbose to print the parsed tree before and after aliases
3110 Use --verbose to print the parsed tree before and after aliases
3111 expansion.
3111 expansion.
3112 """
3112 """
3113 if ui.verbose:
3113 if ui.verbose:
3114 tree = revset.parse(expr, lookup=repo.__contains__)
3114 tree = revset.parse(expr, lookup=repo.__contains__)
3115 ui.note(revset.prettyformat(tree), "\n")
3115 ui.note(revset.prettyformat(tree), "\n")
3116 newtree = revset.findaliases(ui, tree)
3116 newtree = revset.findaliases(ui, tree)
3117 if newtree != tree:
3117 if newtree != tree:
3118 ui.note(revset.prettyformat(newtree), "\n")
3118 ui.note(revset.prettyformat(newtree), "\n")
3119 tree = newtree
3119 tree = newtree
3120 newtree = revset.foldconcat(tree)
3120 newtree = revset.foldconcat(tree)
3121 if newtree != tree:
3121 if newtree != tree:
3122 ui.note(revset.prettyformat(newtree), "\n")
3122 ui.note(revset.prettyformat(newtree), "\n")
3123 if opts["optimize"]:
3123 if opts["optimize"]:
3124 weight, optimizedtree = revset.optimize(newtree, True)
3124 weight, optimizedtree = revset.optimize(newtree, True)
3125 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3125 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
3126 func = revset.match(ui, expr, repo)
3126 func = revset.match(ui, expr, repo)
3127 revs = func(repo)
3127 revs = func(repo)
3128 if ui.verbose:
3128 if ui.verbose:
3129 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3129 ui.note("* set:\n", revset.prettyformatset(revs), "\n")
3130 for c in revs:
3130 for c in revs:
3131 ui.write("%s\n" % c)
3131 ui.write("%s\n" % c)
3132
3132
3133 @command('debugsetparents', [], _('REV1 [REV2]'))
3133 @command('debugsetparents', [], _('REV1 [REV2]'))
3134 def debugsetparents(ui, repo, rev1, rev2=None):
3134 def debugsetparents(ui, repo, rev1, rev2=None):
3135 """manually set the parents of the current working directory
3135 """manually set the parents of the current working directory
3136
3136
3137 This is useful for writing repository conversion tools, but should
3137 This is useful for writing repository conversion tools, but should
3138 be used with care. For example, neither the working directory nor the
3138 be used with care. For example, neither the working directory nor the
3139 dirstate is updated, so file status may be incorrect after running this
3139 dirstate is updated, so file status may be incorrect after running this
3140 command.
3140 command.
3141
3141
3142 Returns 0 on success.
3142 Returns 0 on success.
3143 """
3143 """
3144
3144
3145 r1 = scmutil.revsingle(repo, rev1).node()
3145 r1 = scmutil.revsingle(repo, rev1).node()
3146 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3146 r2 = scmutil.revsingle(repo, rev2, 'null').node()
3147
3147
3148 wlock = repo.wlock()
3148 wlock = repo.wlock()
3149 try:
3149 try:
3150 repo.dirstate.beginparentchange()
3150 repo.dirstate.beginparentchange()
3151 repo.setparents(r1, r2)
3151 repo.setparents(r1, r2)
3152 repo.dirstate.endparentchange()
3152 repo.dirstate.endparentchange()
3153 finally:
3153 finally:
3154 wlock.release()
3154 wlock.release()
3155
3155
3156 @command('debugdirstate|debugstate',
3156 @command('debugdirstate|debugstate',
3157 [('', 'nodates', None, _('do not display the saved mtime')),
3157 [('', 'nodates', None, _('do not display the saved mtime')),
3158 ('', 'datesort', None, _('sort by saved mtime'))],
3158 ('', 'datesort', None, _('sort by saved mtime'))],
3159 _('[OPTION]...'))
3159 _('[OPTION]...'))
3160 def debugstate(ui, repo, nodates=None, datesort=None):
3160 def debugstate(ui, repo, nodates=None, datesort=None):
3161 """show the contents of the current dirstate"""
3161 """show the contents of the current dirstate"""
3162 timestr = ""
3162 timestr = ""
3163 if datesort:
3163 if datesort:
3164 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3164 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
3165 else:
3165 else:
3166 keyfunc = None # sort by filename
3166 keyfunc = None # sort by filename
3167 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3167 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
3168 if ent[3] == -1:
3168 if ent[3] == -1:
3169 timestr = 'unset '
3169 timestr = 'unset '
3170 elif nodates:
3170 elif nodates:
3171 timestr = 'set '
3171 timestr = 'set '
3172 else:
3172 else:
3173 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3173 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
3174 time.localtime(ent[3]))
3174 time.localtime(ent[3]))
3175 if ent[1] & 0o20000:
3175 if ent[1] & 0o20000:
3176 mode = 'lnk'
3176 mode = 'lnk'
3177 else:
3177 else:
3178 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3178 mode = '%3o' % (ent[1] & 0o777 & ~util.umask)
3179 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3179 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
3180 for f in repo.dirstate.copies():
3180 for f in repo.dirstate.copies():
3181 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3181 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
3182
3182
3183 @command('debugsub',
3183 @command('debugsub',
3184 [('r', 'rev', '',
3184 [('r', 'rev', '',
3185 _('revision to check'), _('REV'))],
3185 _('revision to check'), _('REV'))],
3186 _('[-r REV] [REV]'))
3186 _('[-r REV] [REV]'))
3187 def debugsub(ui, repo, rev=None):
3187 def debugsub(ui, repo, rev=None):
3188 ctx = scmutil.revsingle(repo, rev, None)
3188 ctx = scmutil.revsingle(repo, rev, None)
3189 for k, v in sorted(ctx.substate.items()):
3189 for k, v in sorted(ctx.substate.items()):
3190 ui.write(('path %s\n') % k)
3190 ui.write(('path %s\n') % k)
3191 ui.write((' source %s\n') % v[0])
3191 ui.write((' source %s\n') % v[0])
3192 ui.write((' revision %s\n') % v[1])
3192 ui.write((' revision %s\n') % v[1])
3193
3193
3194 @command('debugsuccessorssets',
3194 @command('debugsuccessorssets',
3195 [],
3195 [],
3196 _('[REV]'))
3196 _('[REV]'))
3197 def debugsuccessorssets(ui, repo, *revs):
3197 def debugsuccessorssets(ui, repo, *revs):
3198 """show set of successors for revision
3198 """show set of successors for revision
3199
3199
3200 A successors set of changeset A is a consistent group of revisions that
3200 A successors set of changeset A is a consistent group of revisions that
3201 succeed A. It contains non-obsolete changesets only.
3201 succeed A. It contains non-obsolete changesets only.
3202
3202
3203 In most cases a changeset A has a single successors set containing a single
3203 In most cases a changeset A has a single successors set containing a single
3204 successor (changeset A replaced by A').
3204 successor (changeset A replaced by A').
3205
3205
3206 A changeset that is made obsolete with no successors are called "pruned".
3206 A changeset that is made obsolete with no successors are called "pruned".
3207 Such changesets have no successors sets at all.
3207 Such changesets have no successors sets at all.
3208
3208
3209 A changeset that has been "split" will have a successors set containing
3209 A changeset that has been "split" will have a successors set containing
3210 more than one successor.
3210 more than one successor.
3211
3211
3212 A changeset that has been rewritten in multiple different ways is called
3212 A changeset that has been rewritten in multiple different ways is called
3213 "divergent". Such changesets have multiple successor sets (each of which
3213 "divergent". Such changesets have multiple successor sets (each of which
3214 may also be split, i.e. have multiple successors).
3214 may also be split, i.e. have multiple successors).
3215
3215
3216 Results are displayed as follows::
3216 Results are displayed as follows::
3217
3217
3218 <rev1>
3218 <rev1>
3219 <successors-1A>
3219 <successors-1A>
3220 <rev2>
3220 <rev2>
3221 <successors-2A>
3221 <successors-2A>
3222 <successors-2B1> <successors-2B2> <successors-2B3>
3222 <successors-2B1> <successors-2B2> <successors-2B3>
3223
3223
3224 Here rev2 has two possible (i.e. divergent) successors sets. The first
3224 Here rev2 has two possible (i.e. divergent) successors sets. The first
3225 holds one element, whereas the second holds three (i.e. the changeset has
3225 holds one element, whereas the second holds three (i.e. the changeset has
3226 been split).
3226 been split).
3227 """
3227 """
3228 # passed to successorssets caching computation from one call to another
3228 # passed to successorssets caching computation from one call to another
3229 cache = {}
3229 cache = {}
3230 ctx2str = str
3230 ctx2str = str
3231 node2str = short
3231 node2str = short
3232 if ui.debug():
3232 if ui.debug():
3233 def ctx2str(ctx):
3233 def ctx2str(ctx):
3234 return ctx.hex()
3234 return ctx.hex()
3235 node2str = hex
3235 node2str = hex
3236 for rev in scmutil.revrange(repo, revs):
3236 for rev in scmutil.revrange(repo, revs):
3237 ctx = repo[rev]
3237 ctx = repo[rev]
3238 ui.write('%s\n'% ctx2str(ctx))
3238 ui.write('%s\n'% ctx2str(ctx))
3239 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3239 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3240 if succsset:
3240 if succsset:
3241 ui.write(' ')
3241 ui.write(' ')
3242 ui.write(node2str(succsset[0]))
3242 ui.write(node2str(succsset[0]))
3243 for node in succsset[1:]:
3243 for node in succsset[1:]:
3244 ui.write(' ')
3244 ui.write(' ')
3245 ui.write(node2str(node))
3245 ui.write(node2str(node))
3246 ui.write('\n')
3246 ui.write('\n')
3247
3247
3248 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3248 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3249 def debugwalk(ui, repo, *pats, **opts):
3249 def debugwalk(ui, repo, *pats, **opts):
3250 """show how files match on given patterns"""
3250 """show how files match on given patterns"""
3251 m = scmutil.match(repo[None], pats, opts)
3251 m = scmutil.match(repo[None], pats, opts)
3252 items = list(repo.walk(m))
3252 items = list(repo.walk(m))
3253 if not items:
3253 if not items:
3254 return
3254 return
3255 f = lambda fn: fn
3255 f = lambda fn: fn
3256 if ui.configbool('ui', 'slash') and os.sep != '/':
3256 if ui.configbool('ui', 'slash') and os.sep != '/':
3257 f = lambda fn: util.normpath(fn)
3257 f = lambda fn: util.normpath(fn)
3258 fmt = 'f %%-%ds %%-%ds %%s' % (
3258 fmt = 'f %%-%ds %%-%ds %%s' % (
3259 max([len(abs) for abs in items]),
3259 max([len(abs) for abs in items]),
3260 max([len(m.rel(abs)) for abs in items]))
3260 max([len(m.rel(abs)) for abs in items]))
3261 for abs in items:
3261 for abs in items:
3262 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3262 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3263 ui.write("%s\n" % line.rstrip())
3263 ui.write("%s\n" % line.rstrip())
3264
3264
3265 @command('debugwireargs',
3265 @command('debugwireargs',
3266 [('', 'three', '', 'three'),
3266 [('', 'three', '', 'three'),
3267 ('', 'four', '', 'four'),
3267 ('', 'four', '', 'four'),
3268 ('', 'five', '', 'five'),
3268 ('', 'five', '', 'five'),
3269 ] + remoteopts,
3269 ] + remoteopts,
3270 _('REPO [OPTIONS]... [ONE [TWO]]'),
3270 _('REPO [OPTIONS]... [ONE [TWO]]'),
3271 norepo=True)
3271 norepo=True)
3272 def debugwireargs(ui, repopath, *vals, **opts):
3272 def debugwireargs(ui, repopath, *vals, **opts):
3273 repo = hg.peer(ui, opts, repopath)
3273 repo = hg.peer(ui, opts, repopath)
3274 for opt in remoteopts:
3274 for opt in remoteopts:
3275 del opts[opt[1]]
3275 del opts[opt[1]]
3276 args = {}
3276 args = {}
3277 for k, v in opts.iteritems():
3277 for k, v in opts.iteritems():
3278 if v:
3278 if v:
3279 args[k] = v
3279 args[k] = v
3280 # run twice to check that we don't mess up the stream for the next command
3280 # run twice to check that we don't mess up the stream for the next command
3281 res1 = repo.debugwireargs(*vals, **args)
3281 res1 = repo.debugwireargs(*vals, **args)
3282 res2 = repo.debugwireargs(*vals, **args)
3282 res2 = repo.debugwireargs(*vals, **args)
3283 ui.write("%s\n" % res1)
3283 ui.write("%s\n" % res1)
3284 if res1 != res2:
3284 if res1 != res2:
3285 ui.warn("%s\n" % res2)
3285 ui.warn("%s\n" % res2)
3286
3286
3287 @command('^diff',
3287 @command('^diff',
3288 [('r', 'rev', [], _('revision'), _('REV')),
3288 [('r', 'rev', [], _('revision'), _('REV')),
3289 ('c', 'change', '', _('change made by revision'), _('REV'))
3289 ('c', 'change', '', _('change made by revision'), _('REV'))
3290 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3290 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3291 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3291 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3292 inferrepo=True)
3292 inferrepo=True)
3293 def diff(ui, repo, *pats, **opts):
3293 def diff(ui, repo, *pats, **opts):
3294 """diff repository (or selected files)
3294 """diff repository (or selected files)
3295
3295
3296 Show differences between revisions for the specified files.
3296 Show differences between revisions for the specified files.
3297
3297
3298 Differences between files are shown using the unified diff format.
3298 Differences between files are shown using the unified diff format.
3299
3299
3300 .. note::
3300 .. note::
3301
3301
3302 diff may generate unexpected results for merges, as it will
3302 diff may generate unexpected results for merges, as it will
3303 default to comparing against the working directory's first
3303 default to comparing against the working directory's first
3304 parent changeset if no revisions are specified.
3304 parent changeset if no revisions are specified.
3305
3305
3306 When two revision arguments are given, then changes are shown
3306 When two revision arguments are given, then changes are shown
3307 between those revisions. If only one revision is specified then
3307 between those revisions. If only one revision is specified then
3308 that revision is compared to the working directory, and, when no
3308 that revision is compared to the working directory, and, when no
3309 revisions are specified, the working directory files are compared
3309 revisions are specified, the working directory files are compared
3310 to its parent.
3310 to its parent.
3311
3311
3312 Alternatively you can specify -c/--change with a revision to see
3312 Alternatively you can specify -c/--change with a revision to see
3313 the changes in that changeset relative to its first parent.
3313 the changes in that changeset relative to its first parent.
3314
3314
3315 Without the -a/--text option, diff will avoid generating diffs of
3315 Without the -a/--text option, diff will avoid generating diffs of
3316 files it detects as binary. With -a, diff will generate a diff
3316 files it detects as binary. With -a, diff will generate a diff
3317 anyway, probably with undesirable results.
3317 anyway, probably with undesirable results.
3318
3318
3319 Use the -g/--git option to generate diffs in the git extended diff
3319 Use the -g/--git option to generate diffs in the git extended diff
3320 format. For more information, read :hg:`help diffs`.
3320 format. For more information, read :hg:`help diffs`.
3321
3321
3322 .. container:: verbose
3322 .. container:: verbose
3323
3323
3324 Examples:
3324 Examples:
3325
3325
3326 - compare a file in the current working directory to its parent::
3326 - compare a file in the current working directory to its parent::
3327
3327
3328 hg diff foo.c
3328 hg diff foo.c
3329
3329
3330 - compare two historical versions of a directory, with rename info::
3330 - compare two historical versions of a directory, with rename info::
3331
3331
3332 hg diff --git -r 1.0:1.2 lib/
3332 hg diff --git -r 1.0:1.2 lib/
3333
3333
3334 - get change stats relative to the last change on some date::
3334 - get change stats relative to the last change on some date::
3335
3335
3336 hg diff --stat -r "date('may 2')"
3336 hg diff --stat -r "date('may 2')"
3337
3337
3338 - diff all newly-added files that contain a keyword::
3338 - diff all newly-added files that contain a keyword::
3339
3339
3340 hg diff "set:added() and grep(GNU)"
3340 hg diff "set:added() and grep(GNU)"
3341
3341
3342 - compare a revision and its parents::
3342 - compare a revision and its parents::
3343
3343
3344 hg diff -c 9353 # compare against first parent
3344 hg diff -c 9353 # compare against first parent
3345 hg diff -r 9353^:9353 # same using revset syntax
3345 hg diff -r 9353^:9353 # same using revset syntax
3346 hg diff -r 9353^2:9353 # compare against the second parent
3346 hg diff -r 9353^2:9353 # compare against the second parent
3347
3347
3348 Returns 0 on success.
3348 Returns 0 on success.
3349 """
3349 """
3350
3350
3351 revs = opts.get('rev')
3351 revs = opts.get('rev')
3352 change = opts.get('change')
3352 change = opts.get('change')
3353 stat = opts.get('stat')
3353 stat = opts.get('stat')
3354 reverse = opts.get('reverse')
3354 reverse = opts.get('reverse')
3355
3355
3356 if revs and change:
3356 if revs and change:
3357 msg = _('cannot specify --rev and --change at the same time')
3357 msg = _('cannot specify --rev and --change at the same time')
3358 raise error.Abort(msg)
3358 raise error.Abort(msg)
3359 elif change:
3359 elif change:
3360 node2 = scmutil.revsingle(repo, change, None).node()
3360 node2 = scmutil.revsingle(repo, change, None).node()
3361 node1 = repo[node2].p1().node()
3361 node1 = repo[node2].p1().node()
3362 else:
3362 else:
3363 node1, node2 = scmutil.revpair(repo, revs)
3363 node1, node2 = scmutil.revpair(repo, revs)
3364
3364
3365 if reverse:
3365 if reverse:
3366 node1, node2 = node2, node1
3366 node1, node2 = node2, node1
3367
3367
3368 diffopts = patch.diffallopts(ui, opts)
3368 diffopts = patch.diffallopts(ui, opts)
3369 m = scmutil.match(repo[node2], pats, opts)
3369 m = scmutil.match(repo[node2], pats, opts)
3370 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3370 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3371 listsubrepos=opts.get('subrepos'),
3371 listsubrepos=opts.get('subrepos'),
3372 root=opts.get('root'))
3372 root=opts.get('root'))
3373
3373
3374 @command('^export',
3374 @command('^export',
3375 [('o', 'output', '',
3375 [('o', 'output', '',
3376 _('print output to file with formatted name'), _('FORMAT')),
3376 _('print output to file with formatted name'), _('FORMAT')),
3377 ('', 'switch-parent', None, _('diff against the second parent')),
3377 ('', 'switch-parent', None, _('diff against the second parent')),
3378 ('r', 'rev', [], _('revisions to export'), _('REV')),
3378 ('r', 'rev', [], _('revisions to export'), _('REV')),
3379 ] + diffopts,
3379 ] + diffopts,
3380 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3380 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3381 def export(ui, repo, *changesets, **opts):
3381 def export(ui, repo, *changesets, **opts):
3382 """dump the header and diffs for one or more changesets
3382 """dump the header and diffs for one or more changesets
3383
3383
3384 Print the changeset header and diffs for one or more revisions.
3384 Print the changeset header and diffs for one or more revisions.
3385 If no revision is given, the parent of the working directory is used.
3385 If no revision is given, the parent of the working directory is used.
3386
3386
3387 The information shown in the changeset header is: author, date,
3387 The information shown in the changeset header is: author, date,
3388 branch name (if non-default), changeset hash, parent(s) and commit
3388 branch name (if non-default), changeset hash, parent(s) and commit
3389 comment.
3389 comment.
3390
3390
3391 .. note::
3391 .. note::
3392
3392
3393 export may generate unexpected diff output for merge
3393 export may generate unexpected diff output for merge
3394 changesets, as it will compare the merge changeset against its
3394 changesets, as it will compare the merge changeset against its
3395 first parent only.
3395 first parent only.
3396
3396
3397 Output may be to a file, in which case the name of the file is
3397 Output may be to a file, in which case the name of the file is
3398 given using a format string. The formatting rules are as follows:
3398 given using a format string. The formatting rules are as follows:
3399
3399
3400 :``%%``: literal "%" character
3400 :``%%``: literal "%" character
3401 :``%H``: changeset hash (40 hexadecimal digits)
3401 :``%H``: changeset hash (40 hexadecimal digits)
3402 :``%N``: number of patches being generated
3402 :``%N``: number of patches being generated
3403 :``%R``: changeset revision number
3403 :``%R``: changeset revision number
3404 :``%b``: basename of the exporting repository
3404 :``%b``: basename of the exporting repository
3405 :``%h``: short-form changeset hash (12 hexadecimal digits)
3405 :``%h``: short-form changeset hash (12 hexadecimal digits)
3406 :``%m``: first line of the commit message (only alphanumeric characters)
3406 :``%m``: first line of the commit message (only alphanumeric characters)
3407 :``%n``: zero-padded sequence number, starting at 1
3407 :``%n``: zero-padded sequence number, starting at 1
3408 :``%r``: zero-padded changeset revision number
3408 :``%r``: zero-padded changeset revision number
3409
3409
3410 Without the -a/--text option, export will avoid generating diffs
3410 Without the -a/--text option, export will avoid generating diffs
3411 of files it detects as binary. With -a, export will generate a
3411 of files it detects as binary. With -a, export will generate a
3412 diff anyway, probably with undesirable results.
3412 diff anyway, probably with undesirable results.
3413
3413
3414 Use the -g/--git option to generate diffs in the git extended diff
3414 Use the -g/--git option to generate diffs in the git extended diff
3415 format. See :hg:`help diffs` for more information.
3415 format. See :hg:`help diffs` for more information.
3416
3416
3417 With the --switch-parent option, the diff will be against the
3417 With the --switch-parent option, the diff will be against the
3418 second parent. It can be useful to review a merge.
3418 second parent. It can be useful to review a merge.
3419
3419
3420 .. container:: verbose
3420 .. container:: verbose
3421
3421
3422 Examples:
3422 Examples:
3423
3423
3424 - use export and import to transplant a bugfix to the current
3424 - use export and import to transplant a bugfix to the current
3425 branch::
3425 branch::
3426
3426
3427 hg export -r 9353 | hg import -
3427 hg export -r 9353 | hg import -
3428
3428
3429 - export all the changesets between two revisions to a file with
3429 - export all the changesets between two revisions to a file with
3430 rename information::
3430 rename information::
3431
3431
3432 hg export --git -r 123:150 > changes.txt
3432 hg export --git -r 123:150 > changes.txt
3433
3433
3434 - split outgoing changes into a series of patches with
3434 - split outgoing changes into a series of patches with
3435 descriptive names::
3435 descriptive names::
3436
3436
3437 hg export -r "outgoing()" -o "%n-%m.patch"
3437 hg export -r "outgoing()" -o "%n-%m.patch"
3438
3438
3439 Returns 0 on success.
3439 Returns 0 on success.
3440 """
3440 """
3441 changesets += tuple(opts.get('rev', []))
3441 changesets += tuple(opts.get('rev', []))
3442 if not changesets:
3442 if not changesets:
3443 changesets = ['.']
3443 changesets = ['.']
3444 revs = scmutil.revrange(repo, changesets)
3444 revs = scmutil.revrange(repo, changesets)
3445 if not revs:
3445 if not revs:
3446 raise error.Abort(_("export requires at least one changeset"))
3446 raise error.Abort(_("export requires at least one changeset"))
3447 if len(revs) > 1:
3447 if len(revs) > 1:
3448 ui.note(_('exporting patches:\n'))
3448 ui.note(_('exporting patches:\n'))
3449 else:
3449 else:
3450 ui.note(_('exporting patch:\n'))
3450 ui.note(_('exporting patch:\n'))
3451 cmdutil.export(repo, revs, template=opts.get('output'),
3451 cmdutil.export(repo, revs, template=opts.get('output'),
3452 switch_parent=opts.get('switch_parent'),
3452 switch_parent=opts.get('switch_parent'),
3453 opts=patch.diffallopts(ui, opts))
3453 opts=patch.diffallopts(ui, opts))
3454
3454
3455 @command('files',
3455 @command('files',
3456 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3456 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3457 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3457 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3458 ] + walkopts + formatteropts + subrepoopts,
3458 ] + walkopts + formatteropts + subrepoopts,
3459 _('[OPTION]... [PATTERN]...'))
3459 _('[OPTION]... [PATTERN]...'))
3460 def files(ui, repo, *pats, **opts):
3460 def files(ui, repo, *pats, **opts):
3461 """list tracked files
3461 """list tracked files
3462
3462
3463 Print files under Mercurial control in the working directory or
3463 Print files under Mercurial control in the working directory or
3464 specified revision whose names match the given patterns (excluding
3464 specified revision whose names match the given patterns (excluding
3465 removed files).
3465 removed files).
3466
3466
3467 If no patterns are given to match, this command prints the names
3467 If no patterns are given to match, this command prints the names
3468 of all files under Mercurial control in the working directory.
3468 of all files under Mercurial control in the working directory.
3469
3469
3470 .. container:: verbose
3470 .. container:: verbose
3471
3471
3472 Examples:
3472 Examples:
3473
3473
3474 - list all files under the current directory::
3474 - list all files under the current directory::
3475
3475
3476 hg files .
3476 hg files .
3477
3477
3478 - shows sizes and flags for current revision::
3478 - shows sizes and flags for current revision::
3479
3479
3480 hg files -vr .
3480 hg files -vr .
3481
3481
3482 - list all files named README::
3482 - list all files named README::
3483
3483
3484 hg files -I "**/README"
3484 hg files -I "**/README"
3485
3485
3486 - list all binary files::
3486 - list all binary files::
3487
3487
3488 hg files "set:binary()"
3488 hg files "set:binary()"
3489
3489
3490 - find files containing a regular expression::
3490 - find files containing a regular expression::
3491
3491
3492 hg files "set:grep('bob')"
3492 hg files "set:grep('bob')"
3493
3493
3494 - search tracked file contents with xargs and grep::
3494 - search tracked file contents with xargs and grep::
3495
3495
3496 hg files -0 | xargs -0 grep foo
3496 hg files -0 | xargs -0 grep foo
3497
3497
3498 See :hg:`help patterns` and :hg:`help filesets` for more information
3498 See :hg:`help patterns` and :hg:`help filesets` for more information
3499 on specifying file patterns.
3499 on specifying file patterns.
3500
3500
3501 Returns 0 if a match is found, 1 otherwise.
3501 Returns 0 if a match is found, 1 otherwise.
3502
3502
3503 """
3503 """
3504 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3504 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3505
3505
3506 end = '\n'
3506 end = '\n'
3507 if opts.get('print0'):
3507 if opts.get('print0'):
3508 end = '\0'
3508 end = '\0'
3509 fm = ui.formatter('files', opts)
3509 fm = ui.formatter('files', opts)
3510 fmt = '%s' + end
3510 fmt = '%s' + end
3511
3511
3512 m = scmutil.match(ctx, pats, opts)
3512 m = scmutil.match(ctx, pats, opts)
3513 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3513 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3514
3514
3515 fm.end()
3515 fm.end()
3516
3516
3517 return ret
3517 return ret
3518
3518
3519 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3519 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3520 def forget(ui, repo, *pats, **opts):
3520 def forget(ui, repo, *pats, **opts):
3521 """forget the specified files on the next commit
3521 """forget the specified files on the next commit
3522
3522
3523 Mark the specified files so they will no longer be tracked
3523 Mark the specified files so they will no longer be tracked
3524 after the next commit.
3524 after the next commit.
3525
3525
3526 This only removes files from the current branch, not from the
3526 This only removes files from the current branch, not from the
3527 entire project history, and it does not delete them from the
3527 entire project history, and it does not delete them from the
3528 working directory.
3528 working directory.
3529
3529
3530 To delete the file from the working directory, see :hg:`remove`.
3530 To delete the file from the working directory, see :hg:`remove`.
3531
3531
3532 To undo a forget before the next commit, see :hg:`add`.
3532 To undo a forget before the next commit, see :hg:`add`.
3533
3533
3534 .. container:: verbose
3534 .. container:: verbose
3535
3535
3536 Examples:
3536 Examples:
3537
3537
3538 - forget newly-added binary files::
3538 - forget newly-added binary files::
3539
3539
3540 hg forget "set:added() and binary()"
3540 hg forget "set:added() and binary()"
3541
3541
3542 - forget files that would be excluded by .hgignore::
3542 - forget files that would be excluded by .hgignore::
3543
3543
3544 hg forget "set:hgignore()"
3544 hg forget "set:hgignore()"
3545
3545
3546 Returns 0 on success.
3546 Returns 0 on success.
3547 """
3547 """
3548
3548
3549 if not pats:
3549 if not pats:
3550 raise error.Abort(_('no files specified'))
3550 raise error.Abort(_('no files specified'))
3551
3551
3552 m = scmutil.match(repo[None], pats, opts)
3552 m = scmutil.match(repo[None], pats, opts)
3553 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3553 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3554 return rejected and 1 or 0
3554 return rejected and 1 or 0
3555
3555
3556 @command(
3556 @command(
3557 'graft',
3557 'graft',
3558 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3558 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3559 ('c', 'continue', False, _('resume interrupted graft')),
3559 ('c', 'continue', False, _('resume interrupted graft')),
3560 ('e', 'edit', False, _('invoke editor on commit messages')),
3560 ('e', 'edit', False, _('invoke editor on commit messages')),
3561 ('', 'log', None, _('append graft info to log message')),
3561 ('', 'log', None, _('append graft info to log message')),
3562 ('f', 'force', False, _('force graft')),
3562 ('f', 'force', False, _('force graft')),
3563 ('D', 'currentdate', False,
3563 ('D', 'currentdate', False,
3564 _('record the current date as commit date')),
3564 _('record the current date as commit date')),
3565 ('U', 'currentuser', False,
3565 ('U', 'currentuser', False,
3566 _('record the current user as committer'), _('DATE'))]
3566 _('record the current user as committer'), _('DATE'))]
3567 + commitopts2 + mergetoolopts + dryrunopts,
3567 + commitopts2 + mergetoolopts + dryrunopts,
3568 _('[OPTION]... [-r] REV...'))
3568 _('[OPTION]... [-r] REV...'))
3569 def graft(ui, repo, *revs, **opts):
3569 def graft(ui, repo, *revs, **opts):
3570 '''copy changes from other branches onto the current branch
3570 '''copy changes from other branches onto the current branch
3571
3571
3572 This command uses Mercurial's merge logic to copy individual
3572 This command uses Mercurial's merge logic to copy individual
3573 changes from other branches without merging branches in the
3573 changes from other branches without merging branches in the
3574 history graph. This is sometimes known as 'backporting' or
3574 history graph. This is sometimes known as 'backporting' or
3575 'cherry-picking'. By default, graft will copy user, date, and
3575 'cherry-picking'. By default, graft will copy user, date, and
3576 description from the source changesets.
3576 description from the source changesets.
3577
3577
3578 Changesets that are ancestors of the current revision, that have
3578 Changesets that are ancestors of the current revision, that have
3579 already been grafted, or that are merges will be skipped.
3579 already been grafted, or that are merges will be skipped.
3580
3580
3581 If --log is specified, log messages will have a comment appended
3581 If --log is specified, log messages will have a comment appended
3582 of the form::
3582 of the form::
3583
3583
3584 (grafted from CHANGESETHASH)
3584 (grafted from CHANGESETHASH)
3585
3585
3586 If --force is specified, revisions will be grafted even if they
3586 If --force is specified, revisions will be grafted even if they
3587 are already ancestors of or have been grafted to the destination.
3587 are already ancestors of or have been grafted to the destination.
3588 This is useful when the revisions have since been backed out.
3588 This is useful when the revisions have since been backed out.
3589
3589
3590 If a graft merge results in conflicts, the graft process is
3590 If a graft merge results in conflicts, the graft process is
3591 interrupted so that the current merge can be manually resolved.
3591 interrupted so that the current merge can be manually resolved.
3592 Once all conflicts are addressed, the graft process can be
3592 Once all conflicts are addressed, the graft process can be
3593 continued with the -c/--continue option.
3593 continued with the -c/--continue option.
3594
3594
3595 .. note::
3595 .. note::
3596
3596
3597 The -c/--continue option does not reapply earlier options, except
3597 The -c/--continue option does not reapply earlier options, except
3598 for --force.
3598 for --force.
3599
3599
3600 .. container:: verbose
3600 .. container:: verbose
3601
3601
3602 Examples:
3602 Examples:
3603
3603
3604 - copy a single change to the stable branch and edit its description::
3604 - copy a single change to the stable branch and edit its description::
3605
3605
3606 hg update stable
3606 hg update stable
3607 hg graft --edit 9393
3607 hg graft --edit 9393
3608
3608
3609 - graft a range of changesets with one exception, updating dates::
3609 - graft a range of changesets with one exception, updating dates::
3610
3610
3611 hg graft -D "2085::2093 and not 2091"
3611 hg graft -D "2085::2093 and not 2091"
3612
3612
3613 - continue a graft after resolving conflicts::
3613 - continue a graft after resolving conflicts::
3614
3614
3615 hg graft -c
3615 hg graft -c
3616
3616
3617 - show the source of a grafted changeset::
3617 - show the source of a grafted changeset::
3618
3618
3619 hg log --debug -r .
3619 hg log --debug -r .
3620
3620
3621 See :hg:`help revisions` and :hg:`help revsets` for more about
3621 See :hg:`help revisions` and :hg:`help revsets` for more about
3622 specifying revisions.
3622 specifying revisions.
3623
3623
3624 Returns 0 on successful completion.
3624 Returns 0 on successful completion.
3625 '''
3625 '''
3626
3626
3627 revs = list(revs)
3627 revs = list(revs)
3628 revs.extend(opts['rev'])
3628 revs.extend(opts['rev'])
3629
3629
3630 if not opts.get('user') and opts.get('currentuser'):
3630 if not opts.get('user') and opts.get('currentuser'):
3631 opts['user'] = ui.username()
3631 opts['user'] = ui.username()
3632 if not opts.get('date') and opts.get('currentdate'):
3632 if not opts.get('date') and opts.get('currentdate'):
3633 opts['date'] = "%d %d" % util.makedate()
3633 opts['date'] = "%d %d" % util.makedate()
3634
3634
3635 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3635 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3636
3636
3637 cont = False
3637 cont = False
3638 if opts['continue']:
3638 if opts['continue']:
3639 cont = True
3639 cont = True
3640 if revs:
3640 if revs:
3641 raise error.Abort(_("can't specify --continue and revisions"))
3641 raise error.Abort(_("can't specify --continue and revisions"))
3642 # read in unfinished revisions
3642 # read in unfinished revisions
3643 try:
3643 try:
3644 nodes = repo.vfs.read('graftstate').splitlines()
3644 nodes = repo.vfs.read('graftstate').splitlines()
3645 revs = [repo[node].rev() for node in nodes]
3645 revs = [repo[node].rev() for node in nodes]
3646 except IOError as inst:
3646 except IOError as inst:
3647 if inst.errno != errno.ENOENT:
3647 if inst.errno != errno.ENOENT:
3648 raise
3648 raise
3649 raise error.Abort(_("no graft state found, can't continue"))
3649 raise error.Abort(_("no graft state found, can't continue"))
3650 else:
3650 else:
3651 cmdutil.checkunfinished(repo)
3651 cmdutil.checkunfinished(repo)
3652 cmdutil.bailifchanged(repo)
3652 cmdutil.bailifchanged(repo)
3653 if not revs:
3653 if not revs:
3654 raise error.Abort(_('no revisions specified'))
3654 raise error.Abort(_('no revisions specified'))
3655 revs = scmutil.revrange(repo, revs)
3655 revs = scmutil.revrange(repo, revs)
3656
3656
3657 skipped = set()
3657 skipped = set()
3658 # check for merges
3658 # check for merges
3659 for rev in repo.revs('%ld and merge()', revs):
3659 for rev in repo.revs('%ld and merge()', revs):
3660 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3660 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3661 skipped.add(rev)
3661 skipped.add(rev)
3662 revs = [r for r in revs if r not in skipped]
3662 revs = [r for r in revs if r not in skipped]
3663 if not revs:
3663 if not revs:
3664 return -1
3664 return -1
3665
3665
3666 # Don't check in the --continue case, in effect retaining --force across
3666 # Don't check in the --continue case, in effect retaining --force across
3667 # --continues. That's because without --force, any revisions we decided to
3667 # --continues. That's because without --force, any revisions we decided to
3668 # skip would have been filtered out here, so they wouldn't have made their
3668 # skip would have been filtered out here, so they wouldn't have made their
3669 # way to the graftstate. With --force, any revisions we would have otherwise
3669 # way to the graftstate. With --force, any revisions we would have otherwise
3670 # skipped would not have been filtered out, and if they hadn't been applied
3670 # skipped would not have been filtered out, and if they hadn't been applied
3671 # already, they'd have been in the graftstate.
3671 # already, they'd have been in the graftstate.
3672 if not (cont or opts.get('force')):
3672 if not (cont or opts.get('force')):
3673 # check for ancestors of dest branch
3673 # check for ancestors of dest branch
3674 crev = repo['.'].rev()
3674 crev = repo['.'].rev()
3675 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3675 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3676 # Cannot use x.remove(y) on smart set, this has to be a list.
3676 # Cannot use x.remove(y) on smart set, this has to be a list.
3677 # XXX make this lazy in the future
3677 # XXX make this lazy in the future
3678 revs = list(revs)
3678 revs = list(revs)
3679 # don't mutate while iterating, create a copy
3679 # don't mutate while iterating, create a copy
3680 for rev in list(revs):
3680 for rev in list(revs):
3681 if rev in ancestors:
3681 if rev in ancestors:
3682 ui.warn(_('skipping ancestor revision %d:%s\n') %
3682 ui.warn(_('skipping ancestor revision %d:%s\n') %
3683 (rev, repo[rev]))
3683 (rev, repo[rev]))
3684 # XXX remove on list is slow
3684 # XXX remove on list is slow
3685 revs.remove(rev)
3685 revs.remove(rev)
3686 if not revs:
3686 if not revs:
3687 return -1
3687 return -1
3688
3688
3689 # analyze revs for earlier grafts
3689 # analyze revs for earlier grafts
3690 ids = {}
3690 ids = {}
3691 for ctx in repo.set("%ld", revs):
3691 for ctx in repo.set("%ld", revs):
3692 ids[ctx.hex()] = ctx.rev()
3692 ids[ctx.hex()] = ctx.rev()
3693 n = ctx.extra().get('source')
3693 n = ctx.extra().get('source')
3694 if n:
3694 if n:
3695 ids[n] = ctx.rev()
3695 ids[n] = ctx.rev()
3696
3696
3697 # check ancestors for earlier grafts
3697 # check ancestors for earlier grafts
3698 ui.debug('scanning for duplicate grafts\n')
3698 ui.debug('scanning for duplicate grafts\n')
3699
3699
3700 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3700 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3701 ctx = repo[rev]
3701 ctx = repo[rev]
3702 n = ctx.extra().get('source')
3702 n = ctx.extra().get('source')
3703 if n in ids:
3703 if n in ids:
3704 try:
3704 try:
3705 r = repo[n].rev()
3705 r = repo[n].rev()
3706 except error.RepoLookupError:
3706 except error.RepoLookupError:
3707 r = None
3707 r = None
3708 if r in revs:
3708 if r in revs:
3709 ui.warn(_('skipping revision %d:%s '
3709 ui.warn(_('skipping revision %d:%s '
3710 '(already grafted to %d:%s)\n')
3710 '(already grafted to %d:%s)\n')
3711 % (r, repo[r], rev, ctx))
3711 % (r, repo[r], rev, ctx))
3712 revs.remove(r)
3712 revs.remove(r)
3713 elif ids[n] in revs:
3713 elif ids[n] in revs:
3714 if r is None:
3714 if r is None:
3715 ui.warn(_('skipping already grafted revision %d:%s '
3715 ui.warn(_('skipping already grafted revision %d:%s '
3716 '(%d:%s also has unknown origin %s)\n')
3716 '(%d:%s also has unknown origin %s)\n')
3717 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3717 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3718 else:
3718 else:
3719 ui.warn(_('skipping already grafted revision %d:%s '
3719 ui.warn(_('skipping already grafted revision %d:%s '
3720 '(%d:%s also has origin %d:%s)\n')
3720 '(%d:%s also has origin %d:%s)\n')
3721 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3721 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3722 revs.remove(ids[n])
3722 revs.remove(ids[n])
3723 elif ctx.hex() in ids:
3723 elif ctx.hex() in ids:
3724 r = ids[ctx.hex()]
3724 r = ids[ctx.hex()]
3725 ui.warn(_('skipping already grafted revision %d:%s '
3725 ui.warn(_('skipping already grafted revision %d:%s '
3726 '(was grafted from %d:%s)\n') %
3726 '(was grafted from %d:%s)\n') %
3727 (r, repo[r], rev, ctx))
3727 (r, repo[r], rev, ctx))
3728 revs.remove(r)
3728 revs.remove(r)
3729 if not revs:
3729 if not revs:
3730 return -1
3730 return -1
3731
3731
3732 wlock = repo.wlock()
3732 wlock = repo.wlock()
3733 try:
3733 try:
3734 for pos, ctx in enumerate(repo.set("%ld", revs)):
3734 for pos, ctx in enumerate(repo.set("%ld", revs)):
3735 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3735 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3736 ctx.description().split('\n', 1)[0])
3736 ctx.description().split('\n', 1)[0])
3737 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3737 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3738 if names:
3738 if names:
3739 desc += ' (%s)' % ' '.join(names)
3739 desc += ' (%s)' % ' '.join(names)
3740 ui.status(_('grafting %s\n') % desc)
3740 ui.status(_('grafting %s\n') % desc)
3741 if opts.get('dry_run'):
3741 if opts.get('dry_run'):
3742 continue
3742 continue
3743
3743
3744 source = ctx.extra().get('source')
3744 source = ctx.extra().get('source')
3745 extra = {}
3745 extra = {}
3746 if source:
3746 if source:
3747 extra['source'] = source
3747 extra['source'] = source
3748 extra['intermediate-source'] = ctx.hex()
3748 extra['intermediate-source'] = ctx.hex()
3749 else:
3749 else:
3750 extra['source'] = ctx.hex()
3750 extra['source'] = ctx.hex()
3751 user = ctx.user()
3751 user = ctx.user()
3752 if opts.get('user'):
3752 if opts.get('user'):
3753 user = opts['user']
3753 user = opts['user']
3754 date = ctx.date()
3754 date = ctx.date()
3755 if opts.get('date'):
3755 if opts.get('date'):
3756 date = opts['date']
3756 date = opts['date']
3757 message = ctx.description()
3757 message = ctx.description()
3758 if opts.get('log'):
3758 if opts.get('log'):
3759 message += '\n(grafted from %s)' % ctx.hex()
3759 message += '\n(grafted from %s)' % ctx.hex()
3760
3760
3761 # we don't merge the first commit when continuing
3761 # we don't merge the first commit when continuing
3762 if not cont:
3762 if not cont:
3763 # perform the graft merge with p1(rev) as 'ancestor'
3763 # perform the graft merge with p1(rev) as 'ancestor'
3764 try:
3764 try:
3765 # ui.forcemerge is an internal variable, do not document
3765 # ui.forcemerge is an internal variable, do not document
3766 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3766 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3767 'graft')
3767 'graft')
3768 stats = mergemod.graft(repo, ctx, ctx.p1(),
3768 stats = mergemod.graft(repo, ctx, ctx.p1(),
3769 ['local', 'graft'])
3769 ['local', 'graft'])
3770 finally:
3770 finally:
3771 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3771 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3772 # report any conflicts
3772 # report any conflicts
3773 if stats and stats[3] > 0:
3773 if stats and stats[3] > 0:
3774 # write out state for --continue
3774 # write out state for --continue
3775 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3775 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3776 repo.vfs.write('graftstate', ''.join(nodelines))
3776 repo.vfs.write('graftstate', ''.join(nodelines))
3777 raise error.Abort(
3777 raise error.Abort(
3778 _("unresolved conflicts, can't continue"),
3778 _("unresolved conflicts, can't continue"),
3779 hint=_('use hg resolve and hg graft --continue'))
3779 hint=_('use hg resolve and hg graft --continue'))
3780 else:
3780 else:
3781 cont = False
3781 cont = False
3782
3782
3783 # commit
3783 # commit
3784 node = repo.commit(text=message, user=user,
3784 node = repo.commit(text=message, user=user,
3785 date=date, extra=extra, editor=editor)
3785 date=date, extra=extra, editor=editor)
3786 if node is None:
3786 if node is None:
3787 ui.warn(
3787 ui.warn(
3788 _('note: graft of %d:%s created no changes to commit\n') %
3788 _('note: graft of %d:%s created no changes to commit\n') %
3789 (ctx.rev(), ctx))
3789 (ctx.rev(), ctx))
3790 finally:
3790 finally:
3791 wlock.release()
3791 wlock.release()
3792
3792
3793 # remove state when we complete successfully
3793 # remove state when we complete successfully
3794 if not opts.get('dry_run'):
3794 if not opts.get('dry_run'):
3795 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3795 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3796
3796
3797 return 0
3797 return 0
3798
3798
3799 @command('grep',
3799 @command('grep',
3800 [('0', 'print0', None, _('end fields with NUL')),
3800 [('0', 'print0', None, _('end fields with NUL')),
3801 ('', 'all', None, _('print all revisions that match')),
3801 ('', 'all', None, _('print all revisions that match')),
3802 ('a', 'text', None, _('treat all files as text')),
3802 ('a', 'text', None, _('treat all files as text')),
3803 ('f', 'follow', None,
3803 ('f', 'follow', None,
3804 _('follow changeset history,'
3804 _('follow changeset history,'
3805 ' or file history across copies and renames')),
3805 ' or file history across copies and renames')),
3806 ('i', 'ignore-case', None, _('ignore case when matching')),
3806 ('i', 'ignore-case', None, _('ignore case when matching')),
3807 ('l', 'files-with-matches', None,
3807 ('l', 'files-with-matches', None,
3808 _('print only filenames and revisions that match')),
3808 _('print only filenames and revisions that match')),
3809 ('n', 'line-number', None, _('print matching line numbers')),
3809 ('n', 'line-number', None, _('print matching line numbers')),
3810 ('r', 'rev', [],
3810 ('r', 'rev', [],
3811 _('only search files changed within revision range'), _('REV')),
3811 _('only search files changed within revision range'), _('REV')),
3812 ('u', 'user', None, _('list the author (long with -v)')),
3812 ('u', 'user', None, _('list the author (long with -v)')),
3813 ('d', 'date', None, _('list the date (short with -q)')),
3813 ('d', 'date', None, _('list the date (short with -q)')),
3814 ] + walkopts,
3814 ] + walkopts,
3815 _('[OPTION]... PATTERN [FILE]...'),
3815 _('[OPTION]... PATTERN [FILE]...'),
3816 inferrepo=True)
3816 inferrepo=True)
3817 def grep(ui, repo, pattern, *pats, **opts):
3817 def grep(ui, repo, pattern, *pats, **opts):
3818 """search for a pattern in specified files and revisions
3818 """search for a pattern in specified files and revisions
3819
3819
3820 Search revisions of files for a regular expression.
3820 Search revisions of files for a regular expression.
3821
3821
3822 This command behaves differently than Unix grep. It only accepts
3822 This command behaves differently than Unix grep. It only accepts
3823 Python/Perl regexps. It searches repository history, not the
3823 Python/Perl regexps. It searches repository history, not the
3824 working directory. It always prints the revision number in which a
3824 working directory. It always prints the revision number in which a
3825 match appears.
3825 match appears.
3826
3826
3827 By default, grep only prints output for the first revision of a
3827 By default, grep only prints output for the first revision of a
3828 file in which it finds a match. To get it to print every revision
3828 file in which it finds a match. To get it to print every revision
3829 that contains a change in match status ("-" for a match that
3829 that contains a change in match status ("-" for a match that
3830 becomes a non-match, or "+" for a non-match that becomes a match),
3830 becomes a non-match, or "+" for a non-match that becomes a match),
3831 use the --all flag.
3831 use the --all flag.
3832
3832
3833 Returns 0 if a match is found, 1 otherwise.
3833 Returns 0 if a match is found, 1 otherwise.
3834 """
3834 """
3835 reflags = re.M
3835 reflags = re.M
3836 if opts.get('ignore_case'):
3836 if opts.get('ignore_case'):
3837 reflags |= re.I
3837 reflags |= re.I
3838 try:
3838 try:
3839 regexp = util.re.compile(pattern, reflags)
3839 regexp = util.re.compile(pattern, reflags)
3840 except re.error as inst:
3840 except re.error as inst:
3841 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3841 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3842 return 1
3842 return 1
3843 sep, eol = ':', '\n'
3843 sep, eol = ':', '\n'
3844 if opts.get('print0'):
3844 if opts.get('print0'):
3845 sep = eol = '\0'
3845 sep = eol = '\0'
3846
3846
3847 getfile = util.lrucachefunc(repo.file)
3847 getfile = util.lrucachefunc(repo.file)
3848
3848
3849 def matchlines(body):
3849 def matchlines(body):
3850 begin = 0
3850 begin = 0
3851 linenum = 0
3851 linenum = 0
3852 while begin < len(body):
3852 while begin < len(body):
3853 match = regexp.search(body, begin)
3853 match = regexp.search(body, begin)
3854 if not match:
3854 if not match:
3855 break
3855 break
3856 mstart, mend = match.span()
3856 mstart, mend = match.span()
3857 linenum += body.count('\n', begin, mstart) + 1
3857 linenum += body.count('\n', begin, mstart) + 1
3858 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3858 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3859 begin = body.find('\n', mend) + 1 or len(body) + 1
3859 begin = body.find('\n', mend) + 1 or len(body) + 1
3860 lend = begin - 1
3860 lend = begin - 1
3861 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3861 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3862
3862
3863 class linestate(object):
3863 class linestate(object):
3864 def __init__(self, line, linenum, colstart, colend):
3864 def __init__(self, line, linenum, colstart, colend):
3865 self.line = line
3865 self.line = line
3866 self.linenum = linenum
3866 self.linenum = linenum
3867 self.colstart = colstart
3867 self.colstart = colstart
3868 self.colend = colend
3868 self.colend = colend
3869
3869
3870 def __hash__(self):
3870 def __hash__(self):
3871 return hash((self.linenum, self.line))
3871 return hash((self.linenum, self.line))
3872
3872
3873 def __eq__(self, other):
3873 def __eq__(self, other):
3874 return self.line == other.line
3874 return self.line == other.line
3875
3875
3876 def __iter__(self):
3876 def __iter__(self):
3877 yield (self.line[:self.colstart], '')
3877 yield (self.line[:self.colstart], '')
3878 yield (self.line[self.colstart:self.colend], 'grep.match')
3878 yield (self.line[self.colstart:self.colend], 'grep.match')
3879 rest = self.line[self.colend:]
3879 rest = self.line[self.colend:]
3880 while rest != '':
3880 while rest != '':
3881 match = regexp.search(rest)
3881 match = regexp.search(rest)
3882 if not match:
3882 if not match:
3883 yield (rest, '')
3883 yield (rest, '')
3884 break
3884 break
3885 mstart, mend = match.span()
3885 mstart, mend = match.span()
3886 yield (rest[:mstart], '')
3886 yield (rest[:mstart], '')
3887 yield (rest[mstart:mend], 'grep.match')
3887 yield (rest[mstart:mend], 'grep.match')
3888 rest = rest[mend:]
3888 rest = rest[mend:]
3889
3889
3890 matches = {}
3890 matches = {}
3891 copies = {}
3891 copies = {}
3892 def grepbody(fn, rev, body):
3892 def grepbody(fn, rev, body):
3893 matches[rev].setdefault(fn, [])
3893 matches[rev].setdefault(fn, [])
3894 m = matches[rev][fn]
3894 m = matches[rev][fn]
3895 for lnum, cstart, cend, line in matchlines(body):
3895 for lnum, cstart, cend, line in matchlines(body):
3896 s = linestate(line, lnum, cstart, cend)
3896 s = linestate(line, lnum, cstart, cend)
3897 m.append(s)
3897 m.append(s)
3898
3898
3899 def difflinestates(a, b):
3899 def difflinestates(a, b):
3900 sm = difflib.SequenceMatcher(None, a, b)
3900 sm = difflib.SequenceMatcher(None, a, b)
3901 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3901 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3902 if tag == 'insert':
3902 if tag == 'insert':
3903 for i in xrange(blo, bhi):
3903 for i in xrange(blo, bhi):
3904 yield ('+', b[i])
3904 yield ('+', b[i])
3905 elif tag == 'delete':
3905 elif tag == 'delete':
3906 for i in xrange(alo, ahi):
3906 for i in xrange(alo, ahi):
3907 yield ('-', a[i])
3907 yield ('-', a[i])
3908 elif tag == 'replace':
3908 elif tag == 'replace':
3909 for i in xrange(alo, ahi):
3909 for i in xrange(alo, ahi):
3910 yield ('-', a[i])
3910 yield ('-', a[i])
3911 for i in xrange(blo, bhi):
3911 for i in xrange(blo, bhi):
3912 yield ('+', b[i])
3912 yield ('+', b[i])
3913
3913
3914 def display(fn, ctx, pstates, states):
3914 def display(fn, ctx, pstates, states):
3915 rev = ctx.rev()
3915 rev = ctx.rev()
3916 if ui.quiet:
3916 if ui.quiet:
3917 datefunc = util.shortdate
3917 datefunc = util.shortdate
3918 else:
3918 else:
3919 datefunc = util.datestr
3919 datefunc = util.datestr
3920 found = False
3920 found = False
3921 @util.cachefunc
3921 @util.cachefunc
3922 def binary():
3922 def binary():
3923 flog = getfile(fn)
3923 flog = getfile(fn)
3924 return util.binary(flog.read(ctx.filenode(fn)))
3924 return util.binary(flog.read(ctx.filenode(fn)))
3925
3925
3926 if opts.get('all'):
3926 if opts.get('all'):
3927 iter = difflinestates(pstates, states)
3927 iter = difflinestates(pstates, states)
3928 else:
3928 else:
3929 iter = [('', l) for l in states]
3929 iter = [('', l) for l in states]
3930 for change, l in iter:
3930 for change, l in iter:
3931 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3931 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3932
3932
3933 if opts.get('line_number'):
3933 if opts.get('line_number'):
3934 cols.append((str(l.linenum), 'grep.linenumber'))
3934 cols.append((str(l.linenum), 'grep.linenumber'))
3935 if opts.get('all'):
3935 if opts.get('all'):
3936 cols.append((change, 'grep.change'))
3936 cols.append((change, 'grep.change'))
3937 if opts.get('user'):
3937 if opts.get('user'):
3938 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3938 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3939 if opts.get('date'):
3939 if opts.get('date'):
3940 cols.append((datefunc(ctx.date()), 'grep.date'))
3940 cols.append((datefunc(ctx.date()), 'grep.date'))
3941 for col, label in cols[:-1]:
3941 for col, label in cols[:-1]:
3942 ui.write(col, label=label)
3942 ui.write(col, label=label)
3943 ui.write(sep, label='grep.sep')
3943 ui.write(sep, label='grep.sep')
3944 ui.write(cols[-1][0], label=cols[-1][1])
3944 ui.write(cols[-1][0], label=cols[-1][1])
3945 if not opts.get('files_with_matches'):
3945 if not opts.get('files_with_matches'):
3946 ui.write(sep, label='grep.sep')
3946 ui.write(sep, label='grep.sep')
3947 if not opts.get('text') and binary():
3947 if not opts.get('text') and binary():
3948 ui.write(" Binary file matches")
3948 ui.write(" Binary file matches")
3949 else:
3949 else:
3950 for s, label in l:
3950 for s, label in l:
3951 ui.write(s, label=label)
3951 ui.write(s, label=label)
3952 ui.write(eol)
3952 ui.write(eol)
3953 found = True
3953 found = True
3954 if opts.get('files_with_matches'):
3954 if opts.get('files_with_matches'):
3955 break
3955 break
3956 return found
3956 return found
3957
3957
3958 skip = {}
3958 skip = {}
3959 revfiles = {}
3959 revfiles = {}
3960 matchfn = scmutil.match(repo[None], pats, opts)
3960 matchfn = scmutil.match(repo[None], pats, opts)
3961 found = False
3961 found = False
3962 follow = opts.get('follow')
3962 follow = opts.get('follow')
3963
3963
3964 def prep(ctx, fns):
3964 def prep(ctx, fns):
3965 rev = ctx.rev()
3965 rev = ctx.rev()
3966 pctx = ctx.p1()
3966 pctx = ctx.p1()
3967 parent = pctx.rev()
3967 parent = pctx.rev()
3968 matches.setdefault(rev, {})
3968 matches.setdefault(rev, {})
3969 matches.setdefault(parent, {})
3969 matches.setdefault(parent, {})
3970 files = revfiles.setdefault(rev, [])
3970 files = revfiles.setdefault(rev, [])
3971 for fn in fns:
3971 for fn in fns:
3972 flog = getfile(fn)
3972 flog = getfile(fn)
3973 try:
3973 try:
3974 fnode = ctx.filenode(fn)
3974 fnode = ctx.filenode(fn)
3975 except error.LookupError:
3975 except error.LookupError:
3976 continue
3976 continue
3977
3977
3978 copied = flog.renamed(fnode)
3978 copied = flog.renamed(fnode)
3979 copy = follow and copied and copied[0]
3979 copy = follow and copied and copied[0]
3980 if copy:
3980 if copy:
3981 copies.setdefault(rev, {})[fn] = copy
3981 copies.setdefault(rev, {})[fn] = copy
3982 if fn in skip:
3982 if fn in skip:
3983 if copy:
3983 if copy:
3984 skip[copy] = True
3984 skip[copy] = True
3985 continue
3985 continue
3986 files.append(fn)
3986 files.append(fn)
3987
3987
3988 if fn not in matches[rev]:
3988 if fn not in matches[rev]:
3989 grepbody(fn, rev, flog.read(fnode))
3989 grepbody(fn, rev, flog.read(fnode))
3990
3990
3991 pfn = copy or fn
3991 pfn = copy or fn
3992 if pfn not in matches[parent]:
3992 if pfn not in matches[parent]:
3993 try:
3993 try:
3994 fnode = pctx.filenode(pfn)
3994 fnode = pctx.filenode(pfn)
3995 grepbody(pfn, parent, flog.read(fnode))
3995 grepbody(pfn, parent, flog.read(fnode))
3996 except error.LookupError:
3996 except error.LookupError:
3997 pass
3997 pass
3998
3998
3999 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3999 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4000 rev = ctx.rev()
4000 rev = ctx.rev()
4001 parent = ctx.p1().rev()
4001 parent = ctx.p1().rev()
4002 for fn in sorted(revfiles.get(rev, [])):
4002 for fn in sorted(revfiles.get(rev, [])):
4003 states = matches[rev][fn]
4003 states = matches[rev][fn]
4004 copy = copies.get(rev, {}).get(fn)
4004 copy = copies.get(rev, {}).get(fn)
4005 if fn in skip:
4005 if fn in skip:
4006 if copy:
4006 if copy:
4007 skip[copy] = True
4007 skip[copy] = True
4008 continue
4008 continue
4009 pstates = matches.get(parent, {}).get(copy or fn, [])
4009 pstates = matches.get(parent, {}).get(copy or fn, [])
4010 if pstates or states:
4010 if pstates or states:
4011 r = display(fn, ctx, pstates, states)
4011 r = display(fn, ctx, pstates, states)
4012 found = found or r
4012 found = found or r
4013 if r and not opts.get('all'):
4013 if r and not opts.get('all'):
4014 skip[fn] = True
4014 skip[fn] = True
4015 if copy:
4015 if copy:
4016 skip[copy] = True
4016 skip[copy] = True
4017 del matches[rev]
4017 del matches[rev]
4018 del revfiles[rev]
4018 del revfiles[rev]
4019
4019
4020 return not found
4020 return not found
4021
4021
4022 @command('heads',
4022 @command('heads',
4023 [('r', 'rev', '',
4023 [('r', 'rev', '',
4024 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4024 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
4025 ('t', 'topo', False, _('show topological heads only')),
4025 ('t', 'topo', False, _('show topological heads only')),
4026 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4026 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
4027 ('c', 'closed', False, _('show normal and closed branch heads')),
4027 ('c', 'closed', False, _('show normal and closed branch heads')),
4028 ] + templateopts,
4028 ] + templateopts,
4029 _('[-ct] [-r STARTREV] [REV]...'))
4029 _('[-ct] [-r STARTREV] [REV]...'))
4030 def heads(ui, repo, *branchrevs, **opts):
4030 def heads(ui, repo, *branchrevs, **opts):
4031 """show branch heads
4031 """show branch heads
4032
4032
4033 With no arguments, show all open branch heads in the repository.
4033 With no arguments, show all open branch heads in the repository.
4034 Branch heads are changesets that have no descendants on the
4034 Branch heads are changesets that have no descendants on the
4035 same branch. They are where development generally takes place and
4035 same branch. They are where development generally takes place and
4036 are the usual targets for update and merge operations.
4036 are the usual targets for update and merge operations.
4037
4037
4038 If one or more REVs are given, only open branch heads on the
4038 If one or more REVs are given, only open branch heads on the
4039 branches associated with the specified changesets are shown. This
4039 branches associated with the specified changesets are shown. This
4040 means that you can use :hg:`heads .` to see the heads on the
4040 means that you can use :hg:`heads .` to see the heads on the
4041 currently checked-out branch.
4041 currently checked-out branch.
4042
4042
4043 If -c/--closed is specified, also show branch heads marked closed
4043 If -c/--closed is specified, also show branch heads marked closed
4044 (see :hg:`commit --close-branch`).
4044 (see :hg:`commit --close-branch`).
4045
4045
4046 If STARTREV is specified, only those heads that are descendants of
4046 If STARTREV is specified, only those heads that are descendants of
4047 STARTREV will be displayed.
4047 STARTREV will be displayed.
4048
4048
4049 If -t/--topo is specified, named branch mechanics will be ignored and only
4049 If -t/--topo is specified, named branch mechanics will be ignored and only
4050 topological heads (changesets with no children) will be shown.
4050 topological heads (changesets with no children) will be shown.
4051
4051
4052 Returns 0 if matching heads are found, 1 if not.
4052 Returns 0 if matching heads are found, 1 if not.
4053 """
4053 """
4054
4054
4055 start = None
4055 start = None
4056 if 'rev' in opts:
4056 if 'rev' in opts:
4057 start = scmutil.revsingle(repo, opts['rev'], None).node()
4057 start = scmutil.revsingle(repo, opts['rev'], None).node()
4058
4058
4059 if opts.get('topo'):
4059 if opts.get('topo'):
4060 heads = [repo[h] for h in repo.heads(start)]
4060 heads = [repo[h] for h in repo.heads(start)]
4061 else:
4061 else:
4062 heads = []
4062 heads = []
4063 for branch in repo.branchmap():
4063 for branch in repo.branchmap():
4064 heads += repo.branchheads(branch, start, opts.get('closed'))
4064 heads += repo.branchheads(branch, start, opts.get('closed'))
4065 heads = [repo[h] for h in heads]
4065 heads = [repo[h] for h in heads]
4066
4066
4067 if branchrevs:
4067 if branchrevs:
4068 branches = set(repo[br].branch() for br in branchrevs)
4068 branches = set(repo[br].branch() for br in branchrevs)
4069 heads = [h for h in heads if h.branch() in branches]
4069 heads = [h for h in heads if h.branch() in branches]
4070
4070
4071 if opts.get('active') and branchrevs:
4071 if opts.get('active') and branchrevs:
4072 dagheads = repo.heads(start)
4072 dagheads = repo.heads(start)
4073 heads = [h for h in heads if h.node() in dagheads]
4073 heads = [h for h in heads if h.node() in dagheads]
4074
4074
4075 if branchrevs:
4075 if branchrevs:
4076 haveheads = set(h.branch() for h in heads)
4076 haveheads = set(h.branch() for h in heads)
4077 if branches - haveheads:
4077 if branches - haveheads:
4078 headless = ', '.join(b for b in branches - haveheads)
4078 headless = ', '.join(b for b in branches - haveheads)
4079 msg = _('no open branch heads found on branches %s')
4079 msg = _('no open branch heads found on branches %s')
4080 if opts.get('rev'):
4080 if opts.get('rev'):
4081 msg += _(' (started at %s)') % opts['rev']
4081 msg += _(' (started at %s)') % opts['rev']
4082 ui.warn((msg + '\n') % headless)
4082 ui.warn((msg + '\n') % headless)
4083
4083
4084 if not heads:
4084 if not heads:
4085 return 1
4085 return 1
4086
4086
4087 heads = sorted(heads, key=lambda x: -x.rev())
4087 heads = sorted(heads, key=lambda x: -x.rev())
4088 displayer = cmdutil.show_changeset(ui, repo, opts)
4088 displayer = cmdutil.show_changeset(ui, repo, opts)
4089 for ctx in heads:
4089 for ctx in heads:
4090 displayer.show(ctx)
4090 displayer.show(ctx)
4091 displayer.close()
4091 displayer.close()
4092
4092
4093 @command('help',
4093 @command('help',
4094 [('e', 'extension', None, _('show only help for extensions')),
4094 [('e', 'extension', None, _('show only help for extensions')),
4095 ('c', 'command', None, _('show only help for commands')),
4095 ('c', 'command', None, _('show only help for commands')),
4096 ('k', 'keyword', None, _('show topics matching keyword')),
4096 ('k', 'keyword', None, _('show topics matching keyword')),
4097 ],
4097 ],
4098 _('[-eck] [TOPIC]'),
4098 _('[-eck] [TOPIC]'),
4099 norepo=True)
4099 norepo=True)
4100 def help_(ui, name=None, **opts):
4100 def help_(ui, name=None, **opts):
4101 """show help for a given topic or a help overview
4101 """show help for a given topic or a help overview
4102
4102
4103 With no arguments, print a list of commands with short help messages.
4103 With no arguments, print a list of commands with short help messages.
4104
4104
4105 Given a topic, extension, or command name, print help for that
4105 Given a topic, extension, or command name, print help for that
4106 topic.
4106 topic.
4107
4107
4108 Returns 0 if successful.
4108 Returns 0 if successful.
4109 """
4109 """
4110
4110
4111 textwidth = min(ui.termwidth(), 80) - 2
4111 textwidth = min(ui.termwidth(), 80) - 2
4112
4112
4113 keep = []
4113 keep = []
4114 if ui.verbose:
4114 if ui.verbose:
4115 keep.append('verbose')
4115 keep.append('verbose')
4116 if sys.platform.startswith('win'):
4116 if sys.platform.startswith('win'):
4117 keep.append('windows')
4117 keep.append('windows')
4118 elif sys.platform == 'OpenVMS':
4118 elif sys.platform == 'OpenVMS':
4119 keep.append('vms')
4119 keep.append('vms')
4120 elif sys.platform == 'plan9':
4120 elif sys.platform == 'plan9':
4121 keep.append('plan9')
4121 keep.append('plan9')
4122 else:
4122 else:
4123 keep.append('unix')
4123 keep.append('unix')
4124 keep.append(sys.platform.lower())
4124 keep.append(sys.platform.lower())
4125
4125
4126 section = None
4126 section = None
4127 if name and '.' in name:
4127 if name and '.' in name:
4128 name, section = name.split('.', 1)
4128 name, section = name.split('.', 1)
4129 section = section.lower()
4129 section = section.lower()
4130
4130
4131 text = help.help_(ui, name, **opts)
4131 text = help.help_(ui, name, **opts)
4132
4132
4133 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4133 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4134 section=section)
4134 section=section)
4135
4135
4136 # We could have been given a weird ".foo" section without a name
4136 # We could have been given a weird ".foo" section without a name
4137 # to look for, or we could have simply failed to found "foo.bar"
4137 # to look for, or we could have simply failed to found "foo.bar"
4138 # because bar isn't a section of foo
4138 # because bar isn't a section of foo
4139 if section and not (formatted and name):
4139 if section and not (formatted and name):
4140 raise error.Abort(_("help section not found"))
4140 raise error.Abort(_("help section not found"))
4141
4141
4142 if 'verbose' in pruned:
4142 if 'verbose' in pruned:
4143 keep.append('omitted')
4143 keep.append('omitted')
4144 else:
4144 else:
4145 keep.append('notomitted')
4145 keep.append('notomitted')
4146 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4146 formatted, pruned = minirst.format(text, textwidth, keep=keep,
4147 section=section)
4147 section=section)
4148 ui.write(formatted)
4148 ui.write(formatted)
4149
4149
4150
4150
4151 @command('identify|id',
4151 @command('identify|id',
4152 [('r', 'rev', '',
4152 [('r', 'rev', '',
4153 _('identify the specified revision'), _('REV')),
4153 _('identify the specified revision'), _('REV')),
4154 ('n', 'num', None, _('show local revision number')),
4154 ('n', 'num', None, _('show local revision number')),
4155 ('i', 'id', None, _('show global revision id')),
4155 ('i', 'id', None, _('show global revision id')),
4156 ('b', 'branch', None, _('show branch')),
4156 ('b', 'branch', None, _('show branch')),
4157 ('t', 'tags', None, _('show tags')),
4157 ('t', 'tags', None, _('show tags')),
4158 ('B', 'bookmarks', None, _('show bookmarks')),
4158 ('B', 'bookmarks', None, _('show bookmarks')),
4159 ] + remoteopts,
4159 ] + remoteopts,
4160 _('[-nibtB] [-r REV] [SOURCE]'),
4160 _('[-nibtB] [-r REV] [SOURCE]'),
4161 optionalrepo=True)
4161 optionalrepo=True)
4162 def identify(ui, repo, source=None, rev=None,
4162 def identify(ui, repo, source=None, rev=None,
4163 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4163 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
4164 """identify the working directory or specified revision
4164 """identify the working directory or specified revision
4165
4165
4166 Print a summary identifying the repository state at REV using one or
4166 Print a summary identifying the repository state at REV using one or
4167 two parent hash identifiers, followed by a "+" if the working
4167 two parent hash identifiers, followed by a "+" if the working
4168 directory has uncommitted changes, the branch name (if not default),
4168 directory has uncommitted changes, the branch name (if not default),
4169 a list of tags, and a list of bookmarks.
4169 a list of tags, and a list of bookmarks.
4170
4170
4171 When REV is not given, print a summary of the current state of the
4171 When REV is not given, print a summary of the current state of the
4172 repository.
4172 repository.
4173
4173
4174 Specifying a path to a repository root or Mercurial bundle will
4174 Specifying a path to a repository root or Mercurial bundle will
4175 cause lookup to operate on that repository/bundle.
4175 cause lookup to operate on that repository/bundle.
4176
4176
4177 .. container:: verbose
4177 .. container:: verbose
4178
4178
4179 Examples:
4179 Examples:
4180
4180
4181 - generate a build identifier for the working directory::
4181 - generate a build identifier for the working directory::
4182
4182
4183 hg id --id > build-id.dat
4183 hg id --id > build-id.dat
4184
4184
4185 - find the revision corresponding to a tag::
4185 - find the revision corresponding to a tag::
4186
4186
4187 hg id -n -r 1.3
4187 hg id -n -r 1.3
4188
4188
4189 - check the most recent revision of a remote repository::
4189 - check the most recent revision of a remote repository::
4190
4190
4191 hg id -r tip http://selenic.com/hg/
4191 hg id -r tip http://selenic.com/hg/
4192
4192
4193 Returns 0 if successful.
4193 Returns 0 if successful.
4194 """
4194 """
4195
4195
4196 if not repo and not source:
4196 if not repo and not source:
4197 raise error.Abort(_("there is no Mercurial repository here "
4197 raise error.Abort(_("there is no Mercurial repository here "
4198 "(.hg not found)"))
4198 "(.hg not found)"))
4199
4199
4200 if ui.debugflag:
4200 if ui.debugflag:
4201 hexfunc = hex
4201 hexfunc = hex
4202 else:
4202 else:
4203 hexfunc = short
4203 hexfunc = short
4204 default = not (num or id or branch or tags or bookmarks)
4204 default = not (num or id or branch or tags or bookmarks)
4205 output = []
4205 output = []
4206 revs = []
4206 revs = []
4207
4207
4208 if source:
4208 if source:
4209 source, branches = hg.parseurl(ui.expandpath(source))
4209 source, branches = hg.parseurl(ui.expandpath(source))
4210 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4210 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
4211 repo = peer.local()
4211 repo = peer.local()
4212 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4212 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
4213
4213
4214 if not repo:
4214 if not repo:
4215 if num or branch or tags:
4215 if num or branch or tags:
4216 raise error.Abort(
4216 raise error.Abort(
4217 _("can't query remote revision number, branch, or tags"))
4217 _("can't query remote revision number, branch, or tags"))
4218 if not rev and revs:
4218 if not rev and revs:
4219 rev = revs[0]
4219 rev = revs[0]
4220 if not rev:
4220 if not rev:
4221 rev = "tip"
4221 rev = "tip"
4222
4222
4223 remoterev = peer.lookup(rev)
4223 remoterev = peer.lookup(rev)
4224 if default or id:
4224 if default or id:
4225 output = [hexfunc(remoterev)]
4225 output = [hexfunc(remoterev)]
4226
4226
4227 def getbms():
4227 def getbms():
4228 bms = []
4228 bms = []
4229
4229
4230 if 'bookmarks' in peer.listkeys('namespaces'):
4230 if 'bookmarks' in peer.listkeys('namespaces'):
4231 hexremoterev = hex(remoterev)
4231 hexremoterev = hex(remoterev)
4232 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4232 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
4233 if bmr == hexremoterev]
4233 if bmr == hexremoterev]
4234
4234
4235 return sorted(bms)
4235 return sorted(bms)
4236
4236
4237 if bookmarks:
4237 if bookmarks:
4238 output.extend(getbms())
4238 output.extend(getbms())
4239 elif default and not ui.quiet:
4239 elif default and not ui.quiet:
4240 # multiple bookmarks for a single parent separated by '/'
4240 # multiple bookmarks for a single parent separated by '/'
4241 bm = '/'.join(getbms())
4241 bm = '/'.join(getbms())
4242 if bm:
4242 if bm:
4243 output.append(bm)
4243 output.append(bm)
4244 else:
4244 else:
4245 ctx = scmutil.revsingle(repo, rev, None)
4245 ctx = scmutil.revsingle(repo, rev, None)
4246
4246
4247 if ctx.rev() is None:
4247 if ctx.rev() is None:
4248 ctx = repo[None]
4248 ctx = repo[None]
4249 parents = ctx.parents()
4249 parents = ctx.parents()
4250 taglist = []
4250 taglist = []
4251 for p in parents:
4251 for p in parents:
4252 taglist.extend(p.tags())
4252 taglist.extend(p.tags())
4253
4253
4254 changed = ""
4254 changed = ""
4255 if default or id or num:
4255 if default or id or num:
4256 if (any(repo.status())
4256 if (any(repo.status())
4257 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4257 or any(ctx.sub(s).dirty() for s in ctx.substate)):
4258 changed = '+'
4258 changed = '+'
4259 if default or id:
4259 if default or id:
4260 output = ["%s%s" %
4260 output = ["%s%s" %
4261 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4261 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4262 if num:
4262 if num:
4263 output.append("%s%s" %
4263 output.append("%s%s" %
4264 ('+'.join([str(p.rev()) for p in parents]), changed))
4264 ('+'.join([str(p.rev()) for p in parents]), changed))
4265 else:
4265 else:
4266 if default or id:
4266 if default or id:
4267 output = [hexfunc(ctx.node())]
4267 output = [hexfunc(ctx.node())]
4268 if num:
4268 if num:
4269 output.append(str(ctx.rev()))
4269 output.append(str(ctx.rev()))
4270 taglist = ctx.tags()
4270 taglist = ctx.tags()
4271
4271
4272 if default and not ui.quiet:
4272 if default and not ui.quiet:
4273 b = ctx.branch()
4273 b = ctx.branch()
4274 if b != 'default':
4274 if b != 'default':
4275 output.append("(%s)" % b)
4275 output.append("(%s)" % b)
4276
4276
4277 # multiple tags for a single parent separated by '/'
4277 # multiple tags for a single parent separated by '/'
4278 t = '/'.join(taglist)
4278 t = '/'.join(taglist)
4279 if t:
4279 if t:
4280 output.append(t)
4280 output.append(t)
4281
4281
4282 # multiple bookmarks for a single parent separated by '/'
4282 # multiple bookmarks for a single parent separated by '/'
4283 bm = '/'.join(ctx.bookmarks())
4283 bm = '/'.join(ctx.bookmarks())
4284 if bm:
4284 if bm:
4285 output.append(bm)
4285 output.append(bm)
4286 else:
4286 else:
4287 if branch:
4287 if branch:
4288 output.append(ctx.branch())
4288 output.append(ctx.branch())
4289
4289
4290 if tags:
4290 if tags:
4291 output.extend(taglist)
4291 output.extend(taglist)
4292
4292
4293 if bookmarks:
4293 if bookmarks:
4294 output.extend(ctx.bookmarks())
4294 output.extend(ctx.bookmarks())
4295
4295
4296 ui.write("%s\n" % ' '.join(output))
4296 ui.write("%s\n" % ' '.join(output))
4297
4297
4298 @command('import|patch',
4298 @command('import|patch',
4299 [('p', 'strip', 1,
4299 [('p', 'strip', 1,
4300 _('directory strip option for patch. This has the same '
4300 _('directory strip option for patch. This has the same '
4301 'meaning as the corresponding patch option'), _('NUM')),
4301 'meaning as the corresponding patch option'), _('NUM')),
4302 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4302 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4303 ('e', 'edit', False, _('invoke editor on commit messages')),
4303 ('e', 'edit', False, _('invoke editor on commit messages')),
4304 ('f', 'force', None,
4304 ('f', 'force', None,
4305 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4305 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4306 ('', 'no-commit', None,
4306 ('', 'no-commit', None,
4307 _("don't commit, just update the working directory")),
4307 _("don't commit, just update the working directory")),
4308 ('', 'bypass', None,
4308 ('', 'bypass', None,
4309 _("apply patch without touching the working directory")),
4309 _("apply patch without touching the working directory")),
4310 ('', 'partial', None,
4310 ('', 'partial', None,
4311 _('commit even if some hunks fail')),
4311 _('commit even if some hunks fail')),
4312 ('', 'exact', None,
4312 ('', 'exact', None,
4313 _('apply patch to the nodes from which it was generated')),
4313 _('apply patch to the nodes from which it was generated')),
4314 ('', 'prefix', '',
4314 ('', 'prefix', '',
4315 _('apply patch to subdirectory'), _('DIR')),
4315 _('apply patch to subdirectory'), _('DIR')),
4316 ('', 'import-branch', None,
4316 ('', 'import-branch', None,
4317 _('use any branch information in patch (implied by --exact)'))] +
4317 _('use any branch information in patch (implied by --exact)'))] +
4318 commitopts + commitopts2 + similarityopts,
4318 commitopts + commitopts2 + similarityopts,
4319 _('[OPTION]... PATCH...'))
4319 _('[OPTION]... PATCH...'))
4320 def import_(ui, repo, patch1=None, *patches, **opts):
4320 def import_(ui, repo, patch1=None, *patches, **opts):
4321 """import an ordered set of patches
4321 """import an ordered set of patches
4322
4322
4323 Import a list of patches and commit them individually (unless
4323 Import a list of patches and commit them individually (unless
4324 --no-commit is specified).
4324 --no-commit is specified).
4325
4325
4326 Because import first applies changes to the working directory,
4326 Because import first applies changes to the working directory,
4327 import will abort if there are outstanding changes.
4327 import will abort if there are outstanding changes.
4328
4328
4329 You can import a patch straight from a mail message. Even patches
4329 You can import a patch straight from a mail message. Even patches
4330 as attachments work (to use the body part, it must have type
4330 as attachments work (to use the body part, it must have type
4331 text/plain or text/x-patch). From and Subject headers of email
4331 text/plain or text/x-patch). From and Subject headers of email
4332 message are used as default committer and commit message. All
4332 message are used as default committer and commit message. All
4333 text/plain body parts before first diff are added to commit
4333 text/plain body parts before first diff are added to commit
4334 message.
4334 message.
4335
4335
4336 If the imported patch was generated by :hg:`export`, user and
4336 If the imported patch was generated by :hg:`export`, user and
4337 description from patch override values from message headers and
4337 description from patch override values from message headers and
4338 body. Values given on command line with -m/--message and -u/--user
4338 body. Values given on command line with -m/--message and -u/--user
4339 override these.
4339 override these.
4340
4340
4341 If --exact is specified, import will set the working directory to
4341 If --exact is specified, import will set the working directory to
4342 the parent of each patch before applying it, and will abort if the
4342 the parent of each patch before applying it, and will abort if the
4343 resulting changeset has a different ID than the one recorded in
4343 resulting changeset has a different ID than the one recorded in
4344 the patch. This may happen due to character set problems or other
4344 the patch. This may happen due to character set problems or other
4345 deficiencies in the text patch format.
4345 deficiencies in the text patch format.
4346
4346
4347 Use --bypass to apply and commit patches directly to the
4347 Use --bypass to apply and commit patches directly to the
4348 repository, not touching the working directory. Without --exact,
4348 repository, not touching the working directory. Without --exact,
4349 patches will be applied on top of the working directory parent
4349 patches will be applied on top of the working directory parent
4350 revision.
4350 revision.
4351
4351
4352 With -s/--similarity, hg will attempt to discover renames and
4352 With -s/--similarity, hg will attempt to discover renames and
4353 copies in the patch in the same way as :hg:`addremove`.
4353 copies in the patch in the same way as :hg:`addremove`.
4354
4354
4355 Use --partial to ensure a changeset will be created from the patch
4355 Use --partial to ensure a changeset will be created from the patch
4356 even if some hunks fail to apply. Hunks that fail to apply will be
4356 even if some hunks fail to apply. Hunks that fail to apply will be
4357 written to a <target-file>.rej file. Conflicts can then be resolved
4357 written to a <target-file>.rej file. Conflicts can then be resolved
4358 by hand before :hg:`commit --amend` is run to update the created
4358 by hand before :hg:`commit --amend` is run to update the created
4359 changeset. This flag exists to let people import patches that
4359 changeset. This flag exists to let people import patches that
4360 partially apply without losing the associated metadata (author,
4360 partially apply without losing the associated metadata (author,
4361 date, description, ...). Note that when none of the hunk applies
4361 date, description, ...). Note that when none of the hunk applies
4362 cleanly, :hg:`import --partial` will create an empty changeset,
4362 cleanly, :hg:`import --partial` will create an empty changeset,
4363 importing only the patch metadata.
4363 importing only the patch metadata.
4364
4364
4365 It is possible to use external patch programs to perform the patch
4365 It is possible to use external patch programs to perform the patch
4366 by setting the ``ui.patch`` configuration option. For the default
4366 by setting the ``ui.patch`` configuration option. For the default
4367 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4367 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4368 See :hg:`help config` for more information about configuration
4368 See :hg:`help config` for more information about configuration
4369 files and how to use these options.
4369 files and how to use these options.
4370
4370
4371 To read a patch from standard input, use "-" as the patch name. If
4371 To read a patch from standard input, use "-" as the patch name. If
4372 a URL is specified, the patch will be downloaded from it.
4372 a URL is specified, the patch will be downloaded from it.
4373 See :hg:`help dates` for a list of formats valid for -d/--date.
4373 See :hg:`help dates` for a list of formats valid for -d/--date.
4374
4374
4375 .. container:: verbose
4375 .. container:: verbose
4376
4376
4377 Examples:
4377 Examples:
4378
4378
4379 - import a traditional patch from a website and detect renames::
4379 - import a traditional patch from a website and detect renames::
4380
4380
4381 hg import -s 80 http://example.com/bugfix.patch
4381 hg import -s 80 http://example.com/bugfix.patch
4382
4382
4383 - import a changeset from an hgweb server::
4383 - import a changeset from an hgweb server::
4384
4384
4385 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4385 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4386
4386
4387 - import all the patches in an Unix-style mbox::
4387 - import all the patches in an Unix-style mbox::
4388
4388
4389 hg import incoming-patches.mbox
4389 hg import incoming-patches.mbox
4390
4390
4391 - attempt to exactly restore an exported changeset (not always
4391 - attempt to exactly restore an exported changeset (not always
4392 possible)::
4392 possible)::
4393
4393
4394 hg import --exact proposed-fix.patch
4394 hg import --exact proposed-fix.patch
4395
4395
4396 - use an external tool to apply a patch which is too fuzzy for
4396 - use an external tool to apply a patch which is too fuzzy for
4397 the default internal tool.
4397 the default internal tool.
4398
4398
4399 hg import --config ui.patch="patch --merge" fuzzy.patch
4399 hg import --config ui.patch="patch --merge" fuzzy.patch
4400
4400
4401 - change the default fuzzing from 2 to a less strict 7
4401 - change the default fuzzing from 2 to a less strict 7
4402
4402
4403 hg import --config ui.fuzz=7 fuzz.patch
4403 hg import --config ui.fuzz=7 fuzz.patch
4404
4404
4405 Returns 0 on success, 1 on partial success (see --partial).
4405 Returns 0 on success, 1 on partial success (see --partial).
4406 """
4406 """
4407
4407
4408 if not patch1:
4408 if not patch1:
4409 raise error.Abort(_('need at least one patch to import'))
4409 raise error.Abort(_('need at least one patch to import'))
4410
4410
4411 patches = (patch1,) + patches
4411 patches = (patch1,) + patches
4412
4412
4413 date = opts.get('date')
4413 date = opts.get('date')
4414 if date:
4414 if date:
4415 opts['date'] = util.parsedate(date)
4415 opts['date'] = util.parsedate(date)
4416
4416
4417 update = not opts.get('bypass')
4417 update = not opts.get('bypass')
4418 if not update and opts.get('no_commit'):
4418 if not update and opts.get('no_commit'):
4419 raise error.Abort(_('cannot use --no-commit with --bypass'))
4419 raise error.Abort(_('cannot use --no-commit with --bypass'))
4420 try:
4420 try:
4421 sim = float(opts.get('similarity') or 0)
4421 sim = float(opts.get('similarity') or 0)
4422 except ValueError:
4422 except ValueError:
4423 raise error.Abort(_('similarity must be a number'))
4423 raise error.Abort(_('similarity must be a number'))
4424 if sim < 0 or sim > 100:
4424 if sim < 0 or sim > 100:
4425 raise error.Abort(_('similarity must be between 0 and 100'))
4425 raise error.Abort(_('similarity must be between 0 and 100'))
4426 if sim and not update:
4426 if sim and not update:
4427 raise error.Abort(_('cannot use --similarity with --bypass'))
4427 raise error.Abort(_('cannot use --similarity with --bypass'))
4428 if opts.get('exact') and opts.get('edit'):
4428 if opts.get('exact') and opts.get('edit'):
4429 raise error.Abort(_('cannot use --exact with --edit'))
4429 raise error.Abort(_('cannot use --exact with --edit'))
4430 if opts.get('exact') and opts.get('prefix'):
4430 if opts.get('exact') and opts.get('prefix'):
4431 raise error.Abort(_('cannot use --exact with --prefix'))
4431 raise error.Abort(_('cannot use --exact with --prefix'))
4432
4432
4433 if update:
4433 if update:
4434 cmdutil.checkunfinished(repo)
4434 cmdutil.checkunfinished(repo)
4435 if (opts.get('exact') or not opts.get('force')) and update:
4435 if (opts.get('exact') or not opts.get('force')) and update:
4436 cmdutil.bailifchanged(repo)
4436 cmdutil.bailifchanged(repo)
4437
4437
4438 base = opts["base"]
4438 base = opts["base"]
4439 wlock = dsguard = lock = tr = None
4439 wlock = dsguard = lock = tr = None
4440 msgs = []
4440 msgs = []
4441 ret = 0
4441 ret = 0
4442
4442
4443
4443
4444 try:
4444 try:
4445 try:
4445 try:
4446 wlock = repo.wlock()
4446 wlock = repo.wlock()
4447 if not opts.get('no_commit'):
4447 if not opts.get('no_commit'):
4448 lock = repo.lock()
4448 lock = repo.lock()
4449 tr = repo.transaction('import')
4449 tr = repo.transaction('import')
4450 else:
4450 else:
4451 dsguard = cmdutil.dirstateguard(repo, 'import')
4451 dsguard = cmdutil.dirstateguard(repo, 'import')
4452 parents = repo.parents()
4452 parents = repo.parents()
4453 for patchurl in patches:
4453 for patchurl in patches:
4454 if patchurl == '-':
4454 if patchurl == '-':
4455 ui.status(_('applying patch from stdin\n'))
4455 ui.status(_('applying patch from stdin\n'))
4456 patchfile = ui.fin
4456 patchfile = ui.fin
4457 patchurl = 'stdin' # for error message
4457 patchurl = 'stdin' # for error message
4458 else:
4458 else:
4459 patchurl = os.path.join(base, patchurl)
4459 patchurl = os.path.join(base, patchurl)
4460 ui.status(_('applying %s\n') % patchurl)
4460 ui.status(_('applying %s\n') % patchurl)
4461 patchfile = hg.openpath(ui, patchurl)
4461 patchfile = hg.openpath(ui, patchurl)
4462
4462
4463 haspatch = False
4463 haspatch = False
4464 for hunk in patch.split(patchfile):
4464 for hunk in patch.split(patchfile):
4465 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4465 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4466 parents, opts,
4466 parents, opts,
4467 msgs, hg.clean)
4467 msgs, hg.clean)
4468 if msg:
4468 if msg:
4469 haspatch = True
4469 haspatch = True
4470 ui.note(msg + '\n')
4470 ui.note(msg + '\n')
4471 if update or opts.get('exact'):
4471 if update or opts.get('exact'):
4472 parents = repo.parents()
4472 parents = repo.parents()
4473 else:
4473 else:
4474 parents = [repo[node]]
4474 parents = [repo[node]]
4475 if rej:
4475 if rej:
4476 ui.write_err(_("patch applied partially\n"))
4476 ui.write_err(_("patch applied partially\n"))
4477 ui.write_err(_("(fix the .rej files and run "
4477 ui.write_err(_("(fix the .rej files and run "
4478 "`hg commit --amend`)\n"))
4478 "`hg commit --amend`)\n"))
4479 ret = 1
4479 ret = 1
4480 break
4480 break
4481
4481
4482 if not haspatch:
4482 if not haspatch:
4483 raise error.Abort(_('%s: no diffs found') % patchurl)
4483 raise error.Abort(_('%s: no diffs found') % patchurl)
4484
4484
4485 if tr:
4485 if tr:
4486 tr.close()
4486 tr.close()
4487 if msgs:
4487 if msgs:
4488 repo.savecommitmessage('\n* * *\n'.join(msgs))
4488 repo.savecommitmessage('\n* * *\n'.join(msgs))
4489 if dsguard:
4489 if dsguard:
4490 dsguard.close()
4490 dsguard.close()
4491 return ret
4491 return ret
4492 finally:
4492 finally:
4493 # TODO: get rid of this meaningless try/finally enclosing.
4493 # TODO: get rid of this meaningless try/finally enclosing.
4494 # this is kept only to reduce changes in a patch.
4494 # this is kept only to reduce changes in a patch.
4495 pass
4495 pass
4496 finally:
4496 finally:
4497 if tr:
4497 if tr:
4498 tr.release()
4498 tr.release()
4499 release(lock, dsguard, wlock)
4499 release(lock, dsguard, wlock)
4500
4500
4501 @command('incoming|in',
4501 @command('incoming|in',
4502 [('f', 'force', None,
4502 [('f', 'force', None,
4503 _('run even if remote repository is unrelated')),
4503 _('run even if remote repository is unrelated')),
4504 ('n', 'newest-first', None, _('show newest record first')),
4504 ('n', 'newest-first', None, _('show newest record first')),
4505 ('', 'bundle', '',
4505 ('', 'bundle', '',
4506 _('file to store the bundles into'), _('FILE')),
4506 _('file to store the bundles into'), _('FILE')),
4507 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4507 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4508 ('B', 'bookmarks', False, _("compare bookmarks")),
4508 ('B', 'bookmarks', False, _("compare bookmarks")),
4509 ('b', 'branch', [],
4509 ('b', 'branch', [],
4510 _('a specific branch you would like to pull'), _('BRANCH')),
4510 _('a specific branch you would like to pull'), _('BRANCH')),
4511 ] + logopts + remoteopts + subrepoopts,
4511 ] + logopts + remoteopts + subrepoopts,
4512 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4512 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4513 def incoming(ui, repo, source="default", **opts):
4513 def incoming(ui, repo, source="default", **opts):
4514 """show new changesets found in source
4514 """show new changesets found in source
4515
4515
4516 Show new changesets found in the specified path/URL or the default
4516 Show new changesets found in the specified path/URL or the default
4517 pull location. These are the changesets that would have been pulled
4517 pull location. These are the changesets that would have been pulled
4518 if a pull at the time you issued this command.
4518 if a pull at the time you issued this command.
4519
4519
4520 See pull for valid source format details.
4520 See pull for valid source format details.
4521
4521
4522 .. container:: verbose
4522 .. container:: verbose
4523
4523
4524 With -B/--bookmarks, the result of bookmark comparison between
4524 With -B/--bookmarks, the result of bookmark comparison between
4525 local and remote repositories is displayed. With -v/--verbose,
4525 local and remote repositories is displayed. With -v/--verbose,
4526 status is also displayed for each bookmark like below::
4526 status is also displayed for each bookmark like below::
4527
4527
4528 BM1 01234567890a added
4528 BM1 01234567890a added
4529 BM2 1234567890ab advanced
4529 BM2 1234567890ab advanced
4530 BM3 234567890abc diverged
4530 BM3 234567890abc diverged
4531 BM4 34567890abcd changed
4531 BM4 34567890abcd changed
4532
4532
4533 The action taken locally when pulling depends on the
4533 The action taken locally when pulling depends on the
4534 status of each bookmark:
4534 status of each bookmark:
4535
4535
4536 :``added``: pull will create it
4536 :``added``: pull will create it
4537 :``advanced``: pull will update it
4537 :``advanced``: pull will update it
4538 :``diverged``: pull will create a divergent bookmark
4538 :``diverged``: pull will create a divergent bookmark
4539 :``changed``: result depends on remote changesets
4539 :``changed``: result depends on remote changesets
4540
4540
4541 From the point of view of pulling behavior, bookmark
4541 From the point of view of pulling behavior, bookmark
4542 existing only in the remote repository are treated as ``added``,
4542 existing only in the remote repository are treated as ``added``,
4543 even if it is in fact locally deleted.
4543 even if it is in fact locally deleted.
4544
4544
4545 .. container:: verbose
4545 .. container:: verbose
4546
4546
4547 For remote repository, using --bundle avoids downloading the
4547 For remote repository, using --bundle avoids downloading the
4548 changesets twice if the incoming is followed by a pull.
4548 changesets twice if the incoming is followed by a pull.
4549
4549
4550 Examples:
4550 Examples:
4551
4551
4552 - show incoming changes with patches and full description::
4552 - show incoming changes with patches and full description::
4553
4553
4554 hg incoming -vp
4554 hg incoming -vp
4555
4555
4556 - show incoming changes excluding merges, store a bundle::
4556 - show incoming changes excluding merges, store a bundle::
4557
4557
4558 hg in -vpM --bundle incoming.hg
4558 hg in -vpM --bundle incoming.hg
4559 hg pull incoming.hg
4559 hg pull incoming.hg
4560
4560
4561 - briefly list changes inside a bundle::
4561 - briefly list changes inside a bundle::
4562
4562
4563 hg in changes.hg -T "{desc|firstline}\\n"
4563 hg in changes.hg -T "{desc|firstline}\\n"
4564
4564
4565 Returns 0 if there are incoming changes, 1 otherwise.
4565 Returns 0 if there are incoming changes, 1 otherwise.
4566 """
4566 """
4567 if opts.get('graph'):
4567 if opts.get('graph'):
4568 cmdutil.checkunsupportedgraphflags([], opts)
4568 cmdutil.checkunsupportedgraphflags([], opts)
4569 def display(other, chlist, displayer):
4569 def display(other, chlist, displayer):
4570 revdag = cmdutil.graphrevs(other, chlist, opts)
4570 revdag = cmdutil.graphrevs(other, chlist, opts)
4571 showparents = [ctx.node() for ctx in repo[None].parents()]
4571 showparents = [ctx.node() for ctx in repo[None].parents()]
4572 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4572 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4573 graphmod.asciiedges)
4573 graphmod.asciiedges)
4574
4574
4575 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4575 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4576 return 0
4576 return 0
4577
4577
4578 if opts.get('bundle') and opts.get('subrepos'):
4578 if opts.get('bundle') and opts.get('subrepos'):
4579 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4579 raise error.Abort(_('cannot combine --bundle and --subrepos'))
4580
4580
4581 if opts.get('bookmarks'):
4581 if opts.get('bookmarks'):
4582 source, branches = hg.parseurl(ui.expandpath(source),
4582 source, branches = hg.parseurl(ui.expandpath(source),
4583 opts.get('branch'))
4583 opts.get('branch'))
4584 other = hg.peer(repo, opts, source)
4584 other = hg.peer(repo, opts, source)
4585 if 'bookmarks' not in other.listkeys('namespaces'):
4585 if 'bookmarks' not in other.listkeys('namespaces'):
4586 ui.warn(_("remote doesn't support bookmarks\n"))
4586 ui.warn(_("remote doesn't support bookmarks\n"))
4587 return 0
4587 return 0
4588 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4588 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4589 return bookmarks.incoming(ui, repo, other)
4589 return bookmarks.incoming(ui, repo, other)
4590
4590
4591 repo._subtoppath = ui.expandpath(source)
4591 repo._subtoppath = ui.expandpath(source)
4592 try:
4592 try:
4593 return hg.incoming(ui, repo, source, opts)
4593 return hg.incoming(ui, repo, source, opts)
4594 finally:
4594 finally:
4595 del repo._subtoppath
4595 del repo._subtoppath
4596
4596
4597
4597
4598 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4598 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4599 norepo=True)
4599 norepo=True)
4600 def init(ui, dest=".", **opts):
4600 def init(ui, dest=".", **opts):
4601 """create a new repository in the given directory
4601 """create a new repository in the given directory
4602
4602
4603 Initialize a new repository in the given directory. If the given
4603 Initialize a new repository in the given directory. If the given
4604 directory does not exist, it will be created.
4604 directory does not exist, it will be created.
4605
4605
4606 If no directory is given, the current directory is used.
4606 If no directory is given, the current directory is used.
4607
4607
4608 It is possible to specify an ``ssh://`` URL as the destination.
4608 It is possible to specify an ``ssh://`` URL as the destination.
4609 See :hg:`help urls` for more information.
4609 See :hg:`help urls` for more information.
4610
4610
4611 Returns 0 on success.
4611 Returns 0 on success.
4612 """
4612 """
4613 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4613 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4614
4614
4615 @command('locate',
4615 @command('locate',
4616 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4616 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4617 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4617 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4618 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4618 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4619 ] + walkopts,
4619 ] + walkopts,
4620 _('[OPTION]... [PATTERN]...'))
4620 _('[OPTION]... [PATTERN]...'))
4621 def locate(ui, repo, *pats, **opts):
4621 def locate(ui, repo, *pats, **opts):
4622 """locate files matching specific patterns (DEPRECATED)
4622 """locate files matching specific patterns (DEPRECATED)
4623
4623
4624 Print files under Mercurial control in the working directory whose
4624 Print files under Mercurial control in the working directory whose
4625 names match the given patterns.
4625 names match the given patterns.
4626
4626
4627 By default, this command searches all directories in the working
4627 By default, this command searches all directories in the working
4628 directory. To search just the current directory and its
4628 directory. To search just the current directory and its
4629 subdirectories, use "--include .".
4629 subdirectories, use "--include .".
4630
4630
4631 If no patterns are given to match, this command prints the names
4631 If no patterns are given to match, this command prints the names
4632 of all files under Mercurial control in the working directory.
4632 of all files under Mercurial control in the working directory.
4633
4633
4634 If you want to feed the output of this command into the "xargs"
4634 If you want to feed the output of this command into the "xargs"
4635 command, use the -0 option to both this command and "xargs". This
4635 command, use the -0 option to both this command and "xargs". This
4636 will avoid the problem of "xargs" treating single filenames that
4636 will avoid the problem of "xargs" treating single filenames that
4637 contain whitespace as multiple filenames.
4637 contain whitespace as multiple filenames.
4638
4638
4639 See :hg:`help files` for a more versatile command.
4639 See :hg:`help files` for a more versatile command.
4640
4640
4641 Returns 0 if a match is found, 1 otherwise.
4641 Returns 0 if a match is found, 1 otherwise.
4642 """
4642 """
4643 if opts.get('print0'):
4643 if opts.get('print0'):
4644 end = '\0'
4644 end = '\0'
4645 else:
4645 else:
4646 end = '\n'
4646 end = '\n'
4647 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4647 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4648
4648
4649 ret = 1
4649 ret = 1
4650 ctx = repo[rev]
4650 ctx = repo[rev]
4651 m = scmutil.match(ctx, pats, opts, default='relglob',
4651 m = scmutil.match(ctx, pats, opts, default='relglob',
4652 badfn=lambda x, y: False)
4652 badfn=lambda x, y: False)
4653
4653
4654 for abs in ctx.matches(m):
4654 for abs in ctx.matches(m):
4655 if opts.get('fullpath'):
4655 if opts.get('fullpath'):
4656 ui.write(repo.wjoin(abs), end)
4656 ui.write(repo.wjoin(abs), end)
4657 else:
4657 else:
4658 ui.write(((pats and m.rel(abs)) or abs), end)
4658 ui.write(((pats and m.rel(abs)) or abs), end)
4659 ret = 0
4659 ret = 0
4660
4660
4661 return ret
4661 return ret
4662
4662
4663 @command('^log|history',
4663 @command('^log|history',
4664 [('f', 'follow', None,
4664 [('f', 'follow', None,
4665 _('follow changeset history, or file history across copies and renames')),
4665 _('follow changeset history, or file history across copies and renames')),
4666 ('', 'follow-first', None,
4666 ('', 'follow-first', None,
4667 _('only follow the first parent of merge changesets (DEPRECATED)')),
4667 _('only follow the first parent of merge changesets (DEPRECATED)')),
4668 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4668 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4669 ('C', 'copies', None, _('show copied files')),
4669 ('C', 'copies', None, _('show copied files')),
4670 ('k', 'keyword', [],
4670 ('k', 'keyword', [],
4671 _('do case-insensitive search for a given text'), _('TEXT')),
4671 _('do case-insensitive search for a given text'), _('TEXT')),
4672 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4672 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4673 ('', 'removed', None, _('include revisions where files were removed')),
4673 ('', 'removed', None, _('include revisions where files were removed')),
4674 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4674 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4675 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4675 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4676 ('', 'only-branch', [],
4676 ('', 'only-branch', [],
4677 _('show only changesets within the given named branch (DEPRECATED)'),
4677 _('show only changesets within the given named branch (DEPRECATED)'),
4678 _('BRANCH')),
4678 _('BRANCH')),
4679 ('b', 'branch', [],
4679 ('b', 'branch', [],
4680 _('show changesets within the given named branch'), _('BRANCH')),
4680 _('show changesets within the given named branch'), _('BRANCH')),
4681 ('P', 'prune', [],
4681 ('P', 'prune', [],
4682 _('do not display revision or any of its ancestors'), _('REV')),
4682 _('do not display revision or any of its ancestors'), _('REV')),
4683 ] + logopts + walkopts,
4683 ] + logopts + walkopts,
4684 _('[OPTION]... [FILE]'),
4684 _('[OPTION]... [FILE]'),
4685 inferrepo=True)
4685 inferrepo=True)
4686 def log(ui, repo, *pats, **opts):
4686 def log(ui, repo, *pats, **opts):
4687 """show revision history of entire repository or files
4687 """show revision history of entire repository or files
4688
4688
4689 Print the revision history of the specified files or the entire
4689 Print the revision history of the specified files or the entire
4690 project.
4690 project.
4691
4691
4692 If no revision range is specified, the default is ``tip:0`` unless
4692 If no revision range is specified, the default is ``tip:0`` unless
4693 --follow is set, in which case the working directory parent is
4693 --follow is set, in which case the working directory parent is
4694 used as the starting revision.
4694 used as the starting revision.
4695
4695
4696 File history is shown without following rename or copy history of
4696 File history is shown without following rename or copy history of
4697 files. Use -f/--follow with a filename to follow history across
4697 files. Use -f/--follow with a filename to follow history across
4698 renames and copies. --follow without a filename will only show
4698 renames and copies. --follow without a filename will only show
4699 ancestors or descendants of the starting revision.
4699 ancestors or descendants of the starting revision.
4700
4700
4701 By default this command prints revision number and changeset id,
4701 By default this command prints revision number and changeset id,
4702 tags, non-trivial parents, user, date and time, and a summary for
4702 tags, non-trivial parents, user, date and time, and a summary for
4703 each commit. When the -v/--verbose switch is used, the list of
4703 each commit. When the -v/--verbose switch is used, the list of
4704 changed files and full commit message are shown.
4704 changed files and full commit message are shown.
4705
4705
4706 With --graph the revisions are shown as an ASCII art DAG with the most
4706 With --graph the revisions are shown as an ASCII art DAG with the most
4707 recent changeset at the top.
4707 recent changeset at the top.
4708 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4708 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4709 and '+' represents a fork where the changeset from the lines below is a
4709 and '+' represents a fork where the changeset from the lines below is a
4710 parent of the 'o' merge on the same line.
4710 parent of the 'o' merge on the same line.
4711
4711
4712 .. note::
4712 .. note::
4713
4713
4714 log -p/--patch may generate unexpected diff output for merge
4714 log -p/--patch may generate unexpected diff output for merge
4715 changesets, as it will only compare the merge changeset against
4715 changesets, as it will only compare the merge changeset against
4716 its first parent. Also, only files different from BOTH parents
4716 its first parent. Also, only files different from BOTH parents
4717 will appear in files:.
4717 will appear in files:.
4718
4718
4719 .. note::
4719 .. note::
4720
4720
4721 for performance reasons, log FILE may omit duplicate changes
4721 for performance reasons, log FILE may omit duplicate changes
4722 made on branches and will not show removals or mode changes. To
4722 made on branches and will not show removals or mode changes. To
4723 see all such changes, use the --removed switch.
4723 see all such changes, use the --removed switch.
4724
4724
4725 .. container:: verbose
4725 .. container:: verbose
4726
4726
4727 Some examples:
4727 Some examples:
4728
4728
4729 - changesets with full descriptions and file lists::
4729 - changesets with full descriptions and file lists::
4730
4730
4731 hg log -v
4731 hg log -v
4732
4732
4733 - changesets ancestral to the working directory::
4733 - changesets ancestral to the working directory::
4734
4734
4735 hg log -f
4735 hg log -f
4736
4736
4737 - last 10 commits on the current branch::
4737 - last 10 commits on the current branch::
4738
4738
4739 hg log -l 10 -b .
4739 hg log -l 10 -b .
4740
4740
4741 - changesets showing all modifications of a file, including removals::
4741 - changesets showing all modifications of a file, including removals::
4742
4742
4743 hg log --removed file.c
4743 hg log --removed file.c
4744
4744
4745 - all changesets that touch a directory, with diffs, excluding merges::
4745 - all changesets that touch a directory, with diffs, excluding merges::
4746
4746
4747 hg log -Mp lib/
4747 hg log -Mp lib/
4748
4748
4749 - all revision numbers that match a keyword::
4749 - all revision numbers that match a keyword::
4750
4750
4751 hg log -k bug --template "{rev}\\n"
4751 hg log -k bug --template "{rev}\\n"
4752
4752
4753 - list available log templates::
4753 - list available log templates::
4754
4754
4755 hg log -T list
4755 hg log -T list
4756
4756
4757 - check if a given changeset is included in a tagged release::
4757 - check if a given changeset is included in a tagged release::
4758
4758
4759 hg log -r "a21ccf and ancestor(1.9)"
4759 hg log -r "a21ccf and ancestor(1.9)"
4760
4760
4761 - find all changesets by some user in a date range::
4761 - find all changesets by some user in a date range::
4762
4762
4763 hg log -k alice -d "may 2008 to jul 2008"
4763 hg log -k alice -d "may 2008 to jul 2008"
4764
4764
4765 - summary of all changesets after the last tag::
4765 - summary of all changesets after the last tag::
4766
4766
4767 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4767 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4768
4768
4769 See :hg:`help dates` for a list of formats valid for -d/--date.
4769 See :hg:`help dates` for a list of formats valid for -d/--date.
4770
4770
4771 See :hg:`help revisions` and :hg:`help revsets` for more about
4771 See :hg:`help revisions` and :hg:`help revsets` for more about
4772 specifying revisions.
4772 specifying revisions.
4773
4773
4774 See :hg:`help templates` for more about pre-packaged styles and
4774 See :hg:`help templates` for more about pre-packaged styles and
4775 specifying custom templates.
4775 specifying custom templates.
4776
4776
4777 Returns 0 on success.
4777 Returns 0 on success.
4778
4778
4779 """
4779 """
4780 if opts.get('follow') and opts.get('rev'):
4780 if opts.get('follow') and opts.get('rev'):
4781 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4781 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4782 del opts['follow']
4782 del opts['follow']
4783
4783
4784 if opts.get('graph'):
4784 if opts.get('graph'):
4785 return cmdutil.graphlog(ui, repo, *pats, **opts)
4785 return cmdutil.graphlog(ui, repo, *pats, **opts)
4786
4786
4787 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4787 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4788 limit = cmdutil.loglimit(opts)
4788 limit = cmdutil.loglimit(opts)
4789 count = 0
4789 count = 0
4790
4790
4791 getrenamed = None
4791 getrenamed = None
4792 if opts.get('copies'):
4792 if opts.get('copies'):
4793 endrev = None
4793 endrev = None
4794 if opts.get('rev'):
4794 if opts.get('rev'):
4795 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4795 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4796 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4796 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4797
4797
4798 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4798 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4799 for rev in revs:
4799 for rev in revs:
4800 if count == limit:
4800 if count == limit:
4801 break
4801 break
4802 ctx = repo[rev]
4802 ctx = repo[rev]
4803 copies = None
4803 copies = None
4804 if getrenamed is not None and rev:
4804 if getrenamed is not None and rev:
4805 copies = []
4805 copies = []
4806 for fn in ctx.files():
4806 for fn in ctx.files():
4807 rename = getrenamed(fn, rev)
4807 rename = getrenamed(fn, rev)
4808 if rename:
4808 if rename:
4809 copies.append((fn, rename[0]))
4809 copies.append((fn, rename[0]))
4810 if filematcher:
4810 if filematcher:
4811 revmatchfn = filematcher(ctx.rev())
4811 revmatchfn = filematcher(ctx.rev())
4812 else:
4812 else:
4813 revmatchfn = None
4813 revmatchfn = None
4814 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4814 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4815 if displayer.flush(ctx):
4815 if displayer.flush(ctx):
4816 count += 1
4816 count += 1
4817
4817
4818 displayer.close()
4818 displayer.close()
4819
4819
4820 @command('manifest',
4820 @command('manifest',
4821 [('r', 'rev', '', _('revision to display'), _('REV')),
4821 [('r', 'rev', '', _('revision to display'), _('REV')),
4822 ('', 'all', False, _("list files from all revisions"))]
4822 ('', 'all', False, _("list files from all revisions"))]
4823 + formatteropts,
4823 + formatteropts,
4824 _('[-r REV]'))
4824 _('[-r REV]'))
4825 def manifest(ui, repo, node=None, rev=None, **opts):
4825 def manifest(ui, repo, node=None, rev=None, **opts):
4826 """output the current or given revision of the project manifest
4826 """output the current or given revision of the project manifest
4827
4827
4828 Print a list of version controlled files for the given revision.
4828 Print a list of version controlled files for the given revision.
4829 If no revision is given, the first parent of the working directory
4829 If no revision is given, the first parent of the working directory
4830 is used, or the null revision if no revision is checked out.
4830 is used, or the null revision if no revision is checked out.
4831
4831
4832 With -v, print file permissions, symlink and executable bits.
4832 With -v, print file permissions, symlink and executable bits.
4833 With --debug, print file revision hashes.
4833 With --debug, print file revision hashes.
4834
4834
4835 If option --all is specified, the list of all files from all revisions
4835 If option --all is specified, the list of all files from all revisions
4836 is printed. This includes deleted and renamed files.
4836 is printed. This includes deleted and renamed files.
4837
4837
4838 Returns 0 on success.
4838 Returns 0 on success.
4839 """
4839 """
4840
4840
4841 fm = ui.formatter('manifest', opts)
4841 fm = ui.formatter('manifest', opts)
4842
4842
4843 if opts.get('all'):
4843 if opts.get('all'):
4844 if rev or node:
4844 if rev or node:
4845 raise error.Abort(_("can't specify a revision with --all"))
4845 raise error.Abort(_("can't specify a revision with --all"))
4846
4846
4847 res = []
4847 res = []
4848 prefix = "data/"
4848 prefix = "data/"
4849 suffix = ".i"
4849 suffix = ".i"
4850 plen = len(prefix)
4850 plen = len(prefix)
4851 slen = len(suffix)
4851 slen = len(suffix)
4852 lock = repo.lock()
4852 lock = repo.lock()
4853 try:
4853 try:
4854 for fn, b, size in repo.store.datafiles():
4854 for fn, b, size in repo.store.datafiles():
4855 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4855 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4856 res.append(fn[plen:-slen])
4856 res.append(fn[plen:-slen])
4857 finally:
4857 finally:
4858 lock.release()
4858 lock.release()
4859 for f in res:
4859 for f in res:
4860 fm.startitem()
4860 fm.startitem()
4861 fm.write("path", '%s\n', f)
4861 fm.write("path", '%s\n', f)
4862 fm.end()
4862 fm.end()
4863 return
4863 return
4864
4864
4865 if rev and node:
4865 if rev and node:
4866 raise error.Abort(_("please specify just one revision"))
4866 raise error.Abort(_("please specify just one revision"))
4867
4867
4868 if not node:
4868 if not node:
4869 node = rev
4869 node = rev
4870
4870
4871 char = {'l': '@', 'x': '*', '': ''}
4871 char = {'l': '@', 'x': '*', '': ''}
4872 mode = {'l': '644', 'x': '755', '': '644'}
4872 mode = {'l': '644', 'x': '755', '': '644'}
4873 ctx = scmutil.revsingle(repo, node)
4873 ctx = scmutil.revsingle(repo, node)
4874 mf = ctx.manifest()
4874 mf = ctx.manifest()
4875 for f in ctx:
4875 for f in ctx:
4876 fm.startitem()
4876 fm.startitem()
4877 fl = ctx[f].flags()
4877 fl = ctx[f].flags()
4878 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4878 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4879 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4879 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4880 fm.write('path', '%s\n', f)
4880 fm.write('path', '%s\n', f)
4881 fm.end()
4881 fm.end()
4882
4882
4883 @command('^merge',
4883 @command('^merge',
4884 [('f', 'force', None,
4884 [('f', 'force', None,
4885 _('force a merge including outstanding changes (DEPRECATED)')),
4885 _('force a merge including outstanding changes (DEPRECATED)')),
4886 ('r', 'rev', '', _('revision to merge'), _('REV')),
4886 ('r', 'rev', '', _('revision to merge'), _('REV')),
4887 ('P', 'preview', None,
4887 ('P', 'preview', None,
4888 _('review revisions to merge (no merge is performed)'))
4888 _('review revisions to merge (no merge is performed)'))
4889 ] + mergetoolopts,
4889 ] + mergetoolopts,
4890 _('[-P] [-f] [[-r] REV]'))
4890 _('[-P] [-f] [[-r] REV]'))
4891 def merge(ui, repo, node=None, **opts):
4891 def merge(ui, repo, node=None, **opts):
4892 """merge another revision into working directory
4892 """merge another revision into working directory
4893
4893
4894 The current working directory is updated with all changes made in
4894 The current working directory is updated with all changes made in
4895 the requested revision since the last common predecessor revision.
4895 the requested revision since the last common predecessor revision.
4896
4896
4897 Files that changed between either parent are marked as changed for
4897 Files that changed between either parent are marked as changed for
4898 the next commit and a commit must be performed before any further
4898 the next commit and a commit must be performed before any further
4899 updates to the repository are allowed. The next commit will have
4899 updates to the repository are allowed. The next commit will have
4900 two parents.
4900 two parents.
4901
4901
4902 ``--tool`` can be used to specify the merge tool used for file
4902 ``--tool`` can be used to specify the merge tool used for file
4903 merges. It overrides the HGMERGE environment variable and your
4903 merges. It overrides the HGMERGE environment variable and your
4904 configuration files. See :hg:`help merge-tools` for options.
4904 configuration files. See :hg:`help merge-tools` for options.
4905
4905
4906 If no revision is specified, the working directory's parent is a
4906 If no revision is specified, the working directory's parent is a
4907 head revision, and the current branch contains exactly one other
4907 head revision, and the current branch contains exactly one other
4908 head, the other head is merged with by default. Otherwise, an
4908 head, the other head is merged with by default. Otherwise, an
4909 explicit revision with which to merge with must be provided.
4909 explicit revision with which to merge with must be provided.
4910
4910
4911 :hg:`resolve` must be used to resolve unresolved files.
4911 :hg:`resolve` must be used to resolve unresolved files.
4912
4912
4913 To undo an uncommitted merge, use :hg:`update --clean .` which
4913 To undo an uncommitted merge, use :hg:`update --clean .` which
4914 will check out a clean copy of the original merge parent, losing
4914 will check out a clean copy of the original merge parent, losing
4915 all changes.
4915 all changes.
4916
4916
4917 Returns 0 on success, 1 if there are unresolved files.
4917 Returns 0 on success, 1 if there are unresolved files.
4918 """
4918 """
4919
4919
4920 if opts.get('rev') and node:
4920 if opts.get('rev') and node:
4921 raise error.Abort(_("please specify just one revision"))
4921 raise error.Abort(_("please specify just one revision"))
4922 if not node:
4922 if not node:
4923 node = opts.get('rev')
4923 node = opts.get('rev')
4924
4924
4925 if node:
4925 if node:
4926 node = scmutil.revsingle(repo, node).node()
4926 node = scmutil.revsingle(repo, node).node()
4927
4927
4928 if not node:
4928 if not node:
4929 node = repo[destutil.destmerge(repo)].node()
4929 node = repo[destutil.destmerge(repo)].node()
4930
4930
4931 if opts.get('preview'):
4931 if opts.get('preview'):
4932 # find nodes that are ancestors of p2 but not of p1
4932 # find nodes that are ancestors of p2 but not of p1
4933 p1 = repo.lookup('.')
4933 p1 = repo.lookup('.')
4934 p2 = repo.lookup(node)
4934 p2 = repo.lookup(node)
4935 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4935 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4936
4936
4937 displayer = cmdutil.show_changeset(ui, repo, opts)
4937 displayer = cmdutil.show_changeset(ui, repo, opts)
4938 for node in nodes:
4938 for node in nodes:
4939 displayer.show(repo[node])
4939 displayer.show(repo[node])
4940 displayer.close()
4940 displayer.close()
4941 return 0
4941 return 0
4942
4942
4943 try:
4943 try:
4944 # ui.forcemerge is an internal variable, do not document
4944 # ui.forcemerge is an internal variable, do not document
4945 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4945 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4946 return hg.merge(repo, node, force=opts.get('force'))
4946 return hg.merge(repo, node, force=opts.get('force'))
4947 finally:
4947 finally:
4948 ui.setconfig('ui', 'forcemerge', '', 'merge')
4948 ui.setconfig('ui', 'forcemerge', '', 'merge')
4949
4949
4950 @command('outgoing|out',
4950 @command('outgoing|out',
4951 [('f', 'force', None, _('run even when the destination is unrelated')),
4951 [('f', 'force', None, _('run even when the destination is unrelated')),
4952 ('r', 'rev', [],
4952 ('r', 'rev', [],
4953 _('a changeset intended to be included in the destination'), _('REV')),
4953 _('a changeset intended to be included in the destination'), _('REV')),
4954 ('n', 'newest-first', None, _('show newest record first')),
4954 ('n', 'newest-first', None, _('show newest record first')),
4955 ('B', 'bookmarks', False, _('compare bookmarks')),
4955 ('B', 'bookmarks', False, _('compare bookmarks')),
4956 ('b', 'branch', [], _('a specific branch you would like to push'),
4956 ('b', 'branch', [], _('a specific branch you would like to push'),
4957 _('BRANCH')),
4957 _('BRANCH')),
4958 ] + logopts + remoteopts + subrepoopts,
4958 ] + logopts + remoteopts + subrepoopts,
4959 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4959 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4960 def outgoing(ui, repo, dest=None, **opts):
4960 def outgoing(ui, repo, dest=None, **opts):
4961 """show changesets not found in the destination
4961 """show changesets not found in the destination
4962
4962
4963 Show changesets not found in the specified destination repository
4963 Show changesets not found in the specified destination repository
4964 or the default push location. These are the changesets that would
4964 or the default push location. These are the changesets that would
4965 be pushed if a push was requested.
4965 be pushed if a push was requested.
4966
4966
4967 See pull for details of valid destination formats.
4967 See pull for details of valid destination formats.
4968
4968
4969 .. container:: verbose
4969 .. container:: verbose
4970
4970
4971 With -B/--bookmarks, the result of bookmark comparison between
4971 With -B/--bookmarks, the result of bookmark comparison between
4972 local and remote repositories is displayed. With -v/--verbose,
4972 local and remote repositories is displayed. With -v/--verbose,
4973 status is also displayed for each bookmark like below::
4973 status is also displayed for each bookmark like below::
4974
4974
4975 BM1 01234567890a added
4975 BM1 01234567890a added
4976 BM2 deleted
4976 BM2 deleted
4977 BM3 234567890abc advanced
4977 BM3 234567890abc advanced
4978 BM4 34567890abcd diverged
4978 BM4 34567890abcd diverged
4979 BM5 4567890abcde changed
4979 BM5 4567890abcde changed
4980
4980
4981 The action taken when pushing depends on the
4981 The action taken when pushing depends on the
4982 status of each bookmark:
4982 status of each bookmark:
4983
4983
4984 :``added``: push with ``-B`` will create it
4984 :``added``: push with ``-B`` will create it
4985 :``deleted``: push with ``-B`` will delete it
4985 :``deleted``: push with ``-B`` will delete it
4986 :``advanced``: push will update it
4986 :``advanced``: push will update it
4987 :``diverged``: push with ``-B`` will update it
4987 :``diverged``: push with ``-B`` will update it
4988 :``changed``: push with ``-B`` will update it
4988 :``changed``: push with ``-B`` will update it
4989
4989
4990 From the point of view of pushing behavior, bookmarks
4990 From the point of view of pushing behavior, bookmarks
4991 existing only in the remote repository are treated as
4991 existing only in the remote repository are treated as
4992 ``deleted``, even if it is in fact added remotely.
4992 ``deleted``, even if it is in fact added remotely.
4993
4993
4994 Returns 0 if there are outgoing changes, 1 otherwise.
4994 Returns 0 if there are outgoing changes, 1 otherwise.
4995 """
4995 """
4996 if opts.get('graph'):
4996 if opts.get('graph'):
4997 cmdutil.checkunsupportedgraphflags([], opts)
4997 cmdutil.checkunsupportedgraphflags([], opts)
4998 o, other = hg._outgoing(ui, repo, dest, opts)
4998 o, other = hg._outgoing(ui, repo, dest, opts)
4999 if not o:
4999 if not o:
5000 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5000 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5001 return
5001 return
5002
5002
5003 revdag = cmdutil.graphrevs(repo, o, opts)
5003 revdag = cmdutil.graphrevs(repo, o, opts)
5004 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5004 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
5005 showparents = [ctx.node() for ctx in repo[None].parents()]
5005 showparents = [ctx.node() for ctx in repo[None].parents()]
5006 cmdutil.displaygraph(ui, revdag, displayer, showparents,
5006 cmdutil.displaygraph(ui, revdag, displayer, showparents,
5007 graphmod.asciiedges)
5007 graphmod.asciiedges)
5008 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5008 cmdutil.outgoinghooks(ui, repo, other, opts, o)
5009 return 0
5009 return 0
5010
5010
5011 if opts.get('bookmarks'):
5011 if opts.get('bookmarks'):
5012 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5012 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5013 dest, branches = hg.parseurl(dest, opts.get('branch'))
5013 dest, branches = hg.parseurl(dest, opts.get('branch'))
5014 other = hg.peer(repo, opts, dest)
5014 other = hg.peer(repo, opts, dest)
5015 if 'bookmarks' not in other.listkeys('namespaces'):
5015 if 'bookmarks' not in other.listkeys('namespaces'):
5016 ui.warn(_("remote doesn't support bookmarks\n"))
5016 ui.warn(_("remote doesn't support bookmarks\n"))
5017 return 0
5017 return 0
5018 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5018 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
5019 return bookmarks.outgoing(ui, repo, other)
5019 return bookmarks.outgoing(ui, repo, other)
5020
5020
5021 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5021 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
5022 try:
5022 try:
5023 return hg.outgoing(ui, repo, dest, opts)
5023 return hg.outgoing(ui, repo, dest, opts)
5024 finally:
5024 finally:
5025 del repo._subtoppath
5025 del repo._subtoppath
5026
5026
5027 @command('parents',
5027 @command('parents',
5028 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5028 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
5029 ] + templateopts,
5029 ] + templateopts,
5030 _('[-r REV] [FILE]'),
5030 _('[-r REV] [FILE]'),
5031 inferrepo=True)
5031 inferrepo=True)
5032 def parents(ui, repo, file_=None, **opts):
5032 def parents(ui, repo, file_=None, **opts):
5033 """show the parents of the working directory or revision (DEPRECATED)
5033 """show the parents of the working directory or revision (DEPRECATED)
5034
5034
5035 Print the working directory's parent revisions. If a revision is
5035 Print the working directory's parent revisions. If a revision is
5036 given via -r/--rev, the parent of that revision will be printed.
5036 given via -r/--rev, the parent of that revision will be printed.
5037 If a file argument is given, the revision in which the file was
5037 If a file argument is given, the revision in which the file was
5038 last changed (before the working directory revision or the
5038 last changed (before the working directory revision or the
5039 argument to --rev if given) is printed.
5039 argument to --rev if given) is printed.
5040
5040
5041 See :hg:`summary` and :hg:`help revsets` for related information.
5041 See :hg:`summary` and :hg:`help revsets` for related information.
5042
5042
5043 Returns 0 on success.
5043 Returns 0 on success.
5044 """
5044 """
5045
5045
5046 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5046 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
5047
5047
5048 if file_:
5048 if file_:
5049 m = scmutil.match(ctx, (file_,), opts)
5049 m = scmutil.match(ctx, (file_,), opts)
5050 if m.anypats() or len(m.files()) != 1:
5050 if m.anypats() or len(m.files()) != 1:
5051 raise error.Abort(_('can only specify an explicit filename'))
5051 raise error.Abort(_('can only specify an explicit filename'))
5052 file_ = m.files()[0]
5052 file_ = m.files()[0]
5053 filenodes = []
5053 filenodes = []
5054 for cp in ctx.parents():
5054 for cp in ctx.parents():
5055 if not cp:
5055 if not cp:
5056 continue
5056 continue
5057 try:
5057 try:
5058 filenodes.append(cp.filenode(file_))
5058 filenodes.append(cp.filenode(file_))
5059 except error.LookupError:
5059 except error.LookupError:
5060 pass
5060 pass
5061 if not filenodes:
5061 if not filenodes:
5062 raise error.Abort(_("'%s' not found in manifest!") % file_)
5062 raise error.Abort(_("'%s' not found in manifest!") % file_)
5063 p = []
5063 p = []
5064 for fn in filenodes:
5064 for fn in filenodes:
5065 fctx = repo.filectx(file_, fileid=fn)
5065 fctx = repo.filectx(file_, fileid=fn)
5066 p.append(fctx.node())
5066 p.append(fctx.node())
5067 else:
5067 else:
5068 p = [cp.node() for cp in ctx.parents()]
5068 p = [cp.node() for cp in ctx.parents()]
5069
5069
5070 displayer = cmdutil.show_changeset(ui, repo, opts)
5070 displayer = cmdutil.show_changeset(ui, repo, opts)
5071 for n in p:
5071 for n in p:
5072 if n != nullid:
5072 if n != nullid:
5073 displayer.show(repo[n])
5073 displayer.show(repo[n])
5074 displayer.close()
5074 displayer.close()
5075
5075
5076 @command('paths', [], _('[NAME]'), optionalrepo=True)
5076 @command('paths', [], _('[NAME]'), optionalrepo=True)
5077 def paths(ui, repo, search=None):
5077 def paths(ui, repo, search=None):
5078 """show aliases for remote repositories
5078 """show aliases for remote repositories
5079
5079
5080 Show definition of symbolic path name NAME. If no name is given,
5080 Show definition of symbolic path name NAME. If no name is given,
5081 show definition of all available names.
5081 show definition of all available names.
5082
5082
5083 Option -q/--quiet suppresses all output when searching for NAME
5083 Option -q/--quiet suppresses all output when searching for NAME
5084 and shows only the path names when listing all definitions.
5084 and shows only the path names when listing all definitions.
5085
5085
5086 Path names are defined in the [paths] section of your
5086 Path names are defined in the [paths] section of your
5087 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5087 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5088 repository, ``.hg/hgrc`` is used, too.
5088 repository, ``.hg/hgrc`` is used, too.
5089
5089
5090 The path names ``default`` and ``default-push`` have a special
5090 The path names ``default`` and ``default-push`` have a special
5091 meaning. When performing a push or pull operation, they are used
5091 meaning. When performing a push or pull operation, they are used
5092 as fallbacks if no location is specified on the command-line.
5092 as fallbacks if no location is specified on the command-line.
5093 When ``default-push`` is set, it will be used for push and
5093 When ``default-push`` is set, it will be used for push and
5094 ``default`` will be used for pull; otherwise ``default`` is used
5094 ``default`` will be used for pull; otherwise ``default`` is used
5095 as the fallback for both. When cloning a repository, the clone
5095 as the fallback for both. When cloning a repository, the clone
5096 source is written as ``default`` in ``.hg/hgrc``. Note that
5096 source is written as ``default`` in ``.hg/hgrc``. Note that
5097 ``default`` and ``default-push`` apply to all inbound (e.g.
5097 ``default`` and ``default-push`` apply to all inbound (e.g.
5098 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
5098 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
5099 :hg:`bundle`) operations.
5099 :hg:`bundle`) operations.
5100
5100
5101 See :hg:`help urls` for more information.
5101 See :hg:`help urls` for more information.
5102
5102
5103 Returns 0 on success.
5103 Returns 0 on success.
5104 """
5104 """
5105 if search:
5105 if search:
5106 for name, path in sorted(ui.paths.iteritems()):
5106 for name, path in sorted(ui.paths.iteritems()):
5107 if name == search:
5107 if name == search:
5108 ui.status("%s\n" % util.hidepassword(path.loc))
5108 ui.status("%s\n" % util.hidepassword(path.loc))
5109 return
5109 return
5110 if not ui.quiet:
5110 if not ui.quiet:
5111 ui.warn(_("not found!\n"))
5111 ui.warn(_("not found!\n"))
5112 return 1
5112 return 1
5113 else:
5113 else:
5114 for name, path in sorted(ui.paths.iteritems()):
5114 for name, path in sorted(ui.paths.iteritems()):
5115 if ui.quiet:
5115 if ui.quiet:
5116 ui.write("%s\n" % name)
5116 ui.write("%s\n" % name)
5117 else:
5117 else:
5118 ui.write("%s = %s\n" % (name,
5118 ui.write("%s = %s\n" % (name,
5119 util.hidepassword(path.loc)))
5119 util.hidepassword(path.loc)))
5120
5120
5121 @command('phase',
5121 @command('phase',
5122 [('p', 'public', False, _('set changeset phase to public')),
5122 [('p', 'public', False, _('set changeset phase to public')),
5123 ('d', 'draft', False, _('set changeset phase to draft')),
5123 ('d', 'draft', False, _('set changeset phase to draft')),
5124 ('s', 'secret', False, _('set changeset phase to secret')),
5124 ('s', 'secret', False, _('set changeset phase to secret')),
5125 ('f', 'force', False, _('allow to move boundary backward')),
5125 ('f', 'force', False, _('allow to move boundary backward')),
5126 ('r', 'rev', [], _('target revision'), _('REV')),
5126 ('r', 'rev', [], _('target revision'), _('REV')),
5127 ],
5127 ],
5128 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5128 _('[-p|-d|-s] [-f] [-r] [REV...]'))
5129 def phase(ui, repo, *revs, **opts):
5129 def phase(ui, repo, *revs, **opts):
5130 """set or show the current phase name
5130 """set or show the current phase name
5131
5131
5132 With no argument, show the phase name of the current revision(s).
5132 With no argument, show the phase name of the current revision(s).
5133
5133
5134 With one of -p/--public, -d/--draft or -s/--secret, change the
5134 With one of -p/--public, -d/--draft or -s/--secret, change the
5135 phase value of the specified revisions.
5135 phase value of the specified revisions.
5136
5136
5137 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5137 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
5138 lower phase to an higher phase. Phases are ordered as follows::
5138 lower phase to an higher phase. Phases are ordered as follows::
5139
5139
5140 public < draft < secret
5140 public < draft < secret
5141
5141
5142 Returns 0 on success, 1 if some phases could not be changed.
5142 Returns 0 on success, 1 if some phases could not be changed.
5143
5143
5144 (For more information about the phases concept, see :hg:`help phases`.)
5144 (For more information about the phases concept, see :hg:`help phases`.)
5145 """
5145 """
5146 # search for a unique phase argument
5146 # search for a unique phase argument
5147 targetphase = None
5147 targetphase = None
5148 for idx, name in enumerate(phases.phasenames):
5148 for idx, name in enumerate(phases.phasenames):
5149 if opts[name]:
5149 if opts[name]:
5150 if targetphase is not None:
5150 if targetphase is not None:
5151 raise error.Abort(_('only one phase can be specified'))
5151 raise error.Abort(_('only one phase can be specified'))
5152 targetphase = idx
5152 targetphase = idx
5153
5153
5154 # look for specified revision
5154 # look for specified revision
5155 revs = list(revs)
5155 revs = list(revs)
5156 revs.extend(opts['rev'])
5156 revs.extend(opts['rev'])
5157 if not revs:
5157 if not revs:
5158 # display both parents as the second parent phase can influence
5158 # display both parents as the second parent phase can influence
5159 # the phase of a merge commit
5159 # the phase of a merge commit
5160 revs = [c.rev() for c in repo[None].parents()]
5160 revs = [c.rev() for c in repo[None].parents()]
5161
5161
5162 revs = scmutil.revrange(repo, revs)
5162 revs = scmutil.revrange(repo, revs)
5163
5163
5164 lock = None
5164 lock = None
5165 ret = 0
5165 ret = 0
5166 if targetphase is None:
5166 if targetphase is None:
5167 # display
5167 # display
5168 for r in revs:
5168 for r in revs:
5169 ctx = repo[r]
5169 ctx = repo[r]
5170 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5170 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5171 else:
5171 else:
5172 tr = None
5172 tr = None
5173 lock = repo.lock()
5173 lock = repo.lock()
5174 try:
5174 try:
5175 tr = repo.transaction("phase")
5175 tr = repo.transaction("phase")
5176 # set phase
5176 # set phase
5177 if not revs:
5177 if not revs:
5178 raise error.Abort(_('empty revision set'))
5178 raise error.Abort(_('empty revision set'))
5179 nodes = [repo[r].node() for r in revs]
5179 nodes = [repo[r].node() for r in revs]
5180 # moving revision from public to draft may hide them
5180 # moving revision from public to draft may hide them
5181 # We have to check result on an unfiltered repository
5181 # We have to check result on an unfiltered repository
5182 unfi = repo.unfiltered()
5182 unfi = repo.unfiltered()
5183 getphase = unfi._phasecache.phase
5183 getphase = unfi._phasecache.phase
5184 olddata = [getphase(unfi, r) for r in unfi]
5184 olddata = [getphase(unfi, r) for r in unfi]
5185 phases.advanceboundary(repo, tr, targetphase, nodes)
5185 phases.advanceboundary(repo, tr, targetphase, nodes)
5186 if opts['force']:
5186 if opts['force']:
5187 phases.retractboundary(repo, tr, targetphase, nodes)
5187 phases.retractboundary(repo, tr, targetphase, nodes)
5188 tr.close()
5188 tr.close()
5189 finally:
5189 finally:
5190 if tr is not None:
5190 if tr is not None:
5191 tr.release()
5191 tr.release()
5192 lock.release()
5192 lock.release()
5193 getphase = unfi._phasecache.phase
5193 getphase = unfi._phasecache.phase
5194 newdata = [getphase(unfi, r) for r in unfi]
5194 newdata = [getphase(unfi, r) for r in unfi]
5195 changes = sum(newdata[r] != olddata[r] for r in unfi)
5195 changes = sum(newdata[r] != olddata[r] for r in unfi)
5196 cl = unfi.changelog
5196 cl = unfi.changelog
5197 rejected = [n for n in nodes
5197 rejected = [n for n in nodes
5198 if newdata[cl.rev(n)] < targetphase]
5198 if newdata[cl.rev(n)] < targetphase]
5199 if rejected:
5199 if rejected:
5200 ui.warn(_('cannot move %i changesets to a higher '
5200 ui.warn(_('cannot move %i changesets to a higher '
5201 'phase, use --force\n') % len(rejected))
5201 'phase, use --force\n') % len(rejected))
5202 ret = 1
5202 ret = 1
5203 if changes:
5203 if changes:
5204 msg = _('phase changed for %i changesets\n') % changes
5204 msg = _('phase changed for %i changesets\n') % changes
5205 if ret:
5205 if ret:
5206 ui.status(msg)
5206 ui.status(msg)
5207 else:
5207 else:
5208 ui.note(msg)
5208 ui.note(msg)
5209 else:
5209 else:
5210 ui.warn(_('no phases changed\n'))
5210 ui.warn(_('no phases changed\n'))
5211 return ret
5211 return ret
5212
5212
5213 def postincoming(ui, repo, modheads, optupdate, checkout):
5213 def postincoming(ui, repo, modheads, optupdate, checkout):
5214 if modheads == 0:
5214 if modheads == 0:
5215 return
5215 return
5216 if optupdate:
5216 if optupdate:
5217 try:
5217 try:
5218 brev = checkout
5218 brev = checkout
5219 movemarkfrom = None
5219 movemarkfrom = None
5220 if not checkout:
5220 if not checkout:
5221 updata = destutil.destupdate(repo)
5221 updata = destutil.destupdate(repo)
5222 checkout, movemarkfrom, brev = updata
5222 checkout, movemarkfrom, brev = updata
5223 ret = hg.update(repo, checkout)
5223 ret = hg.update(repo, checkout)
5224 except error.UpdateAbort as inst:
5224 except error.UpdateAbort as inst:
5225 ui.warn(_("not updating: %s\n") % str(inst))
5225 ui.warn(_("not updating: %s\n") % str(inst))
5226 if inst.hint:
5226 if inst.hint:
5227 ui.warn(_("(%s)\n") % inst.hint)
5227 ui.warn(_("(%s)\n") % inst.hint)
5228 return 0
5228 return 0
5229 if not ret and not checkout:
5229 if not ret and not checkout:
5230 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5230 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5231 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5231 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
5232 return ret
5232 return ret
5233 if modheads > 1:
5233 if modheads > 1:
5234 currentbranchheads = len(repo.branchheads())
5234 currentbranchheads = len(repo.branchheads())
5235 if currentbranchheads == modheads:
5235 if currentbranchheads == modheads:
5236 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5236 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
5237 elif currentbranchheads > 1:
5237 elif currentbranchheads > 1:
5238 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5238 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
5239 "merge)\n"))
5239 "merge)\n"))
5240 else:
5240 else:
5241 ui.status(_("(run 'hg heads' to see heads)\n"))
5241 ui.status(_("(run 'hg heads' to see heads)\n"))
5242 else:
5242 else:
5243 ui.status(_("(run 'hg update' to get a working copy)\n"))
5243 ui.status(_("(run 'hg update' to get a working copy)\n"))
5244
5244
5245 @command('^pull',
5245 @command('^pull',
5246 [('u', 'update', None,
5246 [('u', 'update', None,
5247 _('update to new branch head if changesets were pulled')),
5247 _('update to new branch head if changesets were pulled')),
5248 ('f', 'force', None, _('run even when remote repository is unrelated')),
5248 ('f', 'force', None, _('run even when remote repository is unrelated')),
5249 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5249 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
5250 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5250 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
5251 ('b', 'branch', [], _('a specific branch you would like to pull'),
5251 ('b', 'branch', [], _('a specific branch you would like to pull'),
5252 _('BRANCH')),
5252 _('BRANCH')),
5253 ] + remoteopts,
5253 ] + remoteopts,
5254 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5254 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
5255 def pull(ui, repo, source="default", **opts):
5255 def pull(ui, repo, source="default", **opts):
5256 """pull changes from the specified source
5256 """pull changes from the specified source
5257
5257
5258 Pull changes from a remote repository to a local one.
5258 Pull changes from a remote repository to a local one.
5259
5259
5260 This finds all changes from the repository at the specified path
5260 This finds all changes from the repository at the specified path
5261 or URL and adds them to a local repository (the current one unless
5261 or URL and adds them to a local repository (the current one unless
5262 -R is specified). By default, this does not update the copy of the
5262 -R is specified). By default, this does not update the copy of the
5263 project in the working directory.
5263 project in the working directory.
5264
5264
5265 Use :hg:`incoming` if you want to see what would have been added
5265 Use :hg:`incoming` if you want to see what would have been added
5266 by a pull at the time you issued this command. If you then decide
5266 by a pull at the time you issued this command. If you then decide
5267 to add those changes to the repository, you should use :hg:`pull
5267 to add those changes to the repository, you should use :hg:`pull
5268 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5268 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5269
5269
5270 If SOURCE is omitted, the 'default' path will be used.
5270 If SOURCE is omitted, the 'default' path will be used.
5271 See :hg:`help urls` for more information.
5271 See :hg:`help urls` for more information.
5272
5272
5273 Returns 0 on success, 1 if an update had unresolved files.
5273 Returns 0 on success, 1 if an update had unresolved files.
5274 """
5274 """
5275 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5275 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5276 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5276 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5277 other = hg.peer(repo, opts, source)
5277 other = hg.peer(repo, opts, source)
5278 try:
5278 try:
5279 revs, checkout = hg.addbranchrevs(repo, other, branches,
5279 revs, checkout = hg.addbranchrevs(repo, other, branches,
5280 opts.get('rev'))
5280 opts.get('rev'))
5281
5281
5282
5282
5283 pullopargs = {}
5283 pullopargs = {}
5284 if opts.get('bookmark'):
5284 if opts.get('bookmark'):
5285 if not revs:
5285 if not revs:
5286 revs = []
5286 revs = []
5287 # The list of bookmark used here is not the one used to actually
5287 # The list of bookmark used here is not the one used to actually
5288 # update the bookmark name. This can result in the revision pulled
5288 # update the bookmark name. This can result in the revision pulled
5289 # not ending up with the name of the bookmark because of a race
5289 # not ending up with the name of the bookmark because of a race
5290 # condition on the server. (See issue 4689 for details)
5290 # condition on the server. (See issue 4689 for details)
5291 remotebookmarks = other.listkeys('bookmarks')
5291 remotebookmarks = other.listkeys('bookmarks')
5292 pullopargs['remotebookmarks'] = remotebookmarks
5292 pullopargs['remotebookmarks'] = remotebookmarks
5293 for b in opts['bookmark']:
5293 for b in opts['bookmark']:
5294 if b not in remotebookmarks:
5294 if b not in remotebookmarks:
5295 raise error.Abort(_('remote bookmark %s not found!') % b)
5295 raise error.Abort(_('remote bookmark %s not found!') % b)
5296 revs.append(remotebookmarks[b])
5296 revs.append(remotebookmarks[b])
5297
5297
5298 if revs:
5298 if revs:
5299 try:
5299 try:
5300 # When 'rev' is a bookmark name, we cannot guarantee that it
5300 # When 'rev' is a bookmark name, we cannot guarantee that it
5301 # will be updated with that name because of a race condition
5301 # will be updated with that name because of a race condition
5302 # server side. (See issue 4689 for details)
5302 # server side. (See issue 4689 for details)
5303 oldrevs = revs
5303 oldrevs = revs
5304 revs = [] # actually, nodes
5304 revs = [] # actually, nodes
5305 for r in oldrevs:
5305 for r in oldrevs:
5306 node = other.lookup(r)
5306 node = other.lookup(r)
5307 revs.append(node)
5307 revs.append(node)
5308 if r == checkout:
5308 if r == checkout:
5309 checkout = node
5309 checkout = node
5310 except error.CapabilityError:
5310 except error.CapabilityError:
5311 err = _("other repository doesn't support revision lookup, "
5311 err = _("other repository doesn't support revision lookup, "
5312 "so a rev cannot be specified.")
5312 "so a rev cannot be specified.")
5313 raise error.Abort(err)
5313 raise error.Abort(err)
5314
5314
5315 modheads = exchange.pull(repo, other, heads=revs,
5315 modheads = exchange.pull(repo, other, heads=revs,
5316 force=opts.get('force'),
5316 force=opts.get('force'),
5317 bookmarks=opts.get('bookmark', ()),
5317 bookmarks=opts.get('bookmark', ()),
5318 opargs=pullopargs).cgresult
5318 opargs=pullopargs).cgresult
5319 if checkout:
5319 if checkout:
5320 checkout = str(repo.changelog.rev(checkout))
5320 checkout = str(repo.changelog.rev(checkout))
5321 repo._subtoppath = source
5321 repo._subtoppath = source
5322 try:
5322 try:
5323 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5323 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5324
5324
5325 finally:
5325 finally:
5326 del repo._subtoppath
5326 del repo._subtoppath
5327
5327
5328 finally:
5328 finally:
5329 other.close()
5329 other.close()
5330 return ret
5330 return ret
5331
5331
5332 @command('^push',
5332 @command('^push',
5333 [('f', 'force', None, _('force push')),
5333 [('f', 'force', None, _('force push')),
5334 ('r', 'rev', [],
5334 ('r', 'rev', [],
5335 _('a changeset intended to be included in the destination'),
5335 _('a changeset intended to be included in the destination'),
5336 _('REV')),
5336 _('REV')),
5337 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5337 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5338 ('b', 'branch', [],
5338 ('b', 'branch', [],
5339 _('a specific branch you would like to push'), _('BRANCH')),
5339 _('a specific branch you would like to push'), _('BRANCH')),
5340 ('', 'new-branch', False, _('allow pushing a new branch')),
5340 ('', 'new-branch', False, _('allow pushing a new branch')),
5341 ] + remoteopts,
5341 ] + remoteopts,
5342 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5342 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5343 def push(ui, repo, dest=None, **opts):
5343 def push(ui, repo, dest=None, **opts):
5344 """push changes to the specified destination
5344 """push changes to the specified destination
5345
5345
5346 Push changesets from the local repository to the specified
5346 Push changesets from the local repository to the specified
5347 destination.
5347 destination.
5348
5348
5349 This operation is symmetrical to pull: it is identical to a pull
5349 This operation is symmetrical to pull: it is identical to a pull
5350 in the destination repository from the current one.
5350 in the destination repository from the current one.
5351
5351
5352 By default, push will not allow creation of new heads at the
5352 By default, push will not allow creation of new heads at the
5353 destination, since multiple heads would make it unclear which head
5353 destination, since multiple heads would make it unclear which head
5354 to use. In this situation, it is recommended to pull and merge
5354 to use. In this situation, it is recommended to pull and merge
5355 before pushing.
5355 before pushing.
5356
5356
5357 Use --new-branch if you want to allow push to create a new named
5357 Use --new-branch if you want to allow push to create a new named
5358 branch that is not present at the destination. This allows you to
5358 branch that is not present at the destination. This allows you to
5359 only create a new branch without forcing other changes.
5359 only create a new branch without forcing other changes.
5360
5360
5361 .. note::
5361 .. note::
5362
5362
5363 Extra care should be taken with the -f/--force option,
5363 Extra care should be taken with the -f/--force option,
5364 which will push all new heads on all branches, an action which will
5364 which will push all new heads on all branches, an action which will
5365 almost always cause confusion for collaborators.
5365 almost always cause confusion for collaborators.
5366
5366
5367 If -r/--rev is used, the specified revision and all its ancestors
5367 If -r/--rev is used, the specified revision and all its ancestors
5368 will be pushed to the remote repository.
5368 will be pushed to the remote repository.
5369
5369
5370 If -B/--bookmark is used, the specified bookmarked revision, its
5370 If -B/--bookmark is used, the specified bookmarked revision, its
5371 ancestors, and the bookmark will be pushed to the remote
5371 ancestors, and the bookmark will be pushed to the remote
5372 repository.
5372 repository.
5373
5373
5374 Please see :hg:`help urls` for important details about ``ssh://``
5374 Please see :hg:`help urls` for important details about ``ssh://``
5375 URLs. If DESTINATION is omitted, a default path will be used.
5375 URLs. If DESTINATION is omitted, a default path will be used.
5376
5376
5377 Returns 0 if push was successful, 1 if nothing to push.
5377 Returns 0 if push was successful, 1 if nothing to push.
5378 """
5378 """
5379
5379
5380 if opts.get('bookmark'):
5380 if opts.get('bookmark'):
5381 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5381 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5382 for b in opts['bookmark']:
5382 for b in opts['bookmark']:
5383 # translate -B options to -r so changesets get pushed
5383 # translate -B options to -r so changesets get pushed
5384 if b in repo._bookmarks:
5384 if b in repo._bookmarks:
5385 opts.setdefault('rev', []).append(b)
5385 opts.setdefault('rev', []).append(b)
5386 else:
5386 else:
5387 # if we try to push a deleted bookmark, translate it to null
5387 # if we try to push a deleted bookmark, translate it to null
5388 # this lets simultaneous -r, -b options continue working
5388 # this lets simultaneous -r, -b options continue working
5389 opts.setdefault('rev', []).append("null")
5389 opts.setdefault('rev', []).append("null")
5390
5390
5391 path = ui.paths.getpath(dest, default='default')
5391 path = ui.paths.getpath(dest, default='default')
5392 if not path:
5392 if not path:
5393 raise error.Abort(_('default repository not configured!'),
5393 raise error.Abort(_('default repository not configured!'),
5394 hint=_('see the "path" section in "hg help config"'))
5394 hint=_('see the "path" section in "hg help config"'))
5395 dest, branches = path.pushloc, (path.branch, opts.get('branch') or [])
5395 dest, branches = path.pushloc, (path.branch, opts.get('branch') or [])
5396 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5396 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5397 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5397 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5398 other = hg.peer(repo, opts, dest)
5398 other = hg.peer(repo, opts, dest)
5399
5399
5400 if revs:
5400 if revs:
5401 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5401 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5402 if not revs:
5402 if not revs:
5403 raise error.Abort(_("specified revisions evaluate to an empty set"),
5403 raise error.Abort(_("specified revisions evaluate to an empty set"),
5404 hint=_("use different revision arguments"))
5404 hint=_("use different revision arguments"))
5405
5405
5406 repo._subtoppath = dest
5406 repo._subtoppath = dest
5407 try:
5407 try:
5408 # push subrepos depth-first for coherent ordering
5408 # push subrepos depth-first for coherent ordering
5409 c = repo['']
5409 c = repo['']
5410 subs = c.substate # only repos that are committed
5410 subs = c.substate # only repos that are committed
5411 for s in sorted(subs):
5411 for s in sorted(subs):
5412 result = c.sub(s).push(opts)
5412 result = c.sub(s).push(opts)
5413 if result == 0:
5413 if result == 0:
5414 return not result
5414 return not result
5415 finally:
5415 finally:
5416 del repo._subtoppath
5416 del repo._subtoppath
5417 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5417 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5418 newbranch=opts.get('new_branch'),
5418 newbranch=opts.get('new_branch'),
5419 bookmarks=opts.get('bookmark', ()))
5419 bookmarks=opts.get('bookmark', ()))
5420
5420
5421 result = not pushop.cgresult
5421 result = not pushop.cgresult
5422
5422
5423 if pushop.bkresult is not None:
5423 if pushop.bkresult is not None:
5424 if pushop.bkresult == 2:
5424 if pushop.bkresult == 2:
5425 result = 2
5425 result = 2
5426 elif not result and pushop.bkresult:
5426 elif not result and pushop.bkresult:
5427 result = 2
5427 result = 2
5428
5428
5429 return result
5429 return result
5430
5430
5431 @command('recover', [])
5431 @command('recover', [])
5432 def recover(ui, repo):
5432 def recover(ui, repo):
5433 """roll back an interrupted transaction
5433 """roll back an interrupted transaction
5434
5434
5435 Recover from an interrupted commit or pull.
5435 Recover from an interrupted commit or pull.
5436
5436
5437 This command tries to fix the repository status after an
5437 This command tries to fix the repository status after an
5438 interrupted operation. It should only be necessary when Mercurial
5438 interrupted operation. It should only be necessary when Mercurial
5439 suggests it.
5439 suggests it.
5440
5440
5441 Returns 0 if successful, 1 if nothing to recover or verify fails.
5441 Returns 0 if successful, 1 if nothing to recover or verify fails.
5442 """
5442 """
5443 if repo.recover():
5443 if repo.recover():
5444 return hg.verify(repo)
5444 return hg.verify(repo)
5445 return 1
5445 return 1
5446
5446
5447 @command('^remove|rm',
5447 @command('^remove|rm',
5448 [('A', 'after', None, _('record delete for missing files')),
5448 [('A', 'after', None, _('record delete for missing files')),
5449 ('f', 'force', None,
5449 ('f', 'force', None,
5450 _('remove (and delete) file even if added or modified')),
5450 _('remove (and delete) file even if added or modified')),
5451 ] + subrepoopts + walkopts,
5451 ] + subrepoopts + walkopts,
5452 _('[OPTION]... FILE...'),
5452 _('[OPTION]... FILE...'),
5453 inferrepo=True)
5453 inferrepo=True)
5454 def remove(ui, repo, *pats, **opts):
5454 def remove(ui, repo, *pats, **opts):
5455 """remove the specified files on the next commit
5455 """remove the specified files on the next commit
5456
5456
5457 Schedule the indicated files for removal from the current branch.
5457 Schedule the indicated files for removal from the current branch.
5458
5458
5459 This command schedules the files to be removed at the next commit.
5459 This command schedules the files to be removed at the next commit.
5460 To undo a remove before that, see :hg:`revert`. To undo added
5460 To undo a remove before that, see :hg:`revert`. To undo added
5461 files, see :hg:`forget`.
5461 files, see :hg:`forget`.
5462
5462
5463 .. container:: verbose
5463 .. container:: verbose
5464
5464
5465 -A/--after can be used to remove only files that have already
5465 -A/--after can be used to remove only files that have already
5466 been deleted, -f/--force can be used to force deletion, and -Af
5466 been deleted, -f/--force can be used to force deletion, and -Af
5467 can be used to remove files from the next revision without
5467 can be used to remove files from the next revision without
5468 deleting them from the working directory.
5468 deleting them from the working directory.
5469
5469
5470 The following table details the behavior of remove for different
5470 The following table details the behavior of remove for different
5471 file states (columns) and option combinations (rows). The file
5471 file states (columns) and option combinations (rows). The file
5472 states are Added [A], Clean [C], Modified [M] and Missing [!]
5472 states are Added [A], Clean [C], Modified [M] and Missing [!]
5473 (as reported by :hg:`status`). The actions are Warn, Remove
5473 (as reported by :hg:`status`). The actions are Warn, Remove
5474 (from branch) and Delete (from disk):
5474 (from branch) and Delete (from disk):
5475
5475
5476 ========= == == == ==
5476 ========= == == == ==
5477 opt/state A C M !
5477 opt/state A C M !
5478 ========= == == == ==
5478 ========= == == == ==
5479 none W RD W R
5479 none W RD W R
5480 -f R RD RD R
5480 -f R RD RD R
5481 -A W W W R
5481 -A W W W R
5482 -Af R R R R
5482 -Af R R R R
5483 ========= == == == ==
5483 ========= == == == ==
5484
5484
5485 Note that remove never deletes files in Added [A] state from the
5485 Note that remove never deletes files in Added [A] state from the
5486 working directory, not even if option --force is specified.
5486 working directory, not even if option --force is specified.
5487
5487
5488 Returns 0 on success, 1 if any warnings encountered.
5488 Returns 0 on success, 1 if any warnings encountered.
5489 """
5489 """
5490
5490
5491 after, force = opts.get('after'), opts.get('force')
5491 after, force = opts.get('after'), opts.get('force')
5492 if not pats and not after:
5492 if not pats and not after:
5493 raise error.Abort(_('no files specified'))
5493 raise error.Abort(_('no files specified'))
5494
5494
5495 m = scmutil.match(repo[None], pats, opts)
5495 m = scmutil.match(repo[None], pats, opts)
5496 subrepos = opts.get('subrepos')
5496 subrepos = opts.get('subrepos')
5497 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5497 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5498
5498
5499 @command('rename|move|mv',
5499 @command('rename|move|mv',
5500 [('A', 'after', None, _('record a rename that has already occurred')),
5500 [('A', 'after', None, _('record a rename that has already occurred')),
5501 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5501 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5502 ] + walkopts + dryrunopts,
5502 ] + walkopts + dryrunopts,
5503 _('[OPTION]... SOURCE... DEST'))
5503 _('[OPTION]... SOURCE... DEST'))
5504 def rename(ui, repo, *pats, **opts):
5504 def rename(ui, repo, *pats, **opts):
5505 """rename files; equivalent of copy + remove
5505 """rename files; equivalent of copy + remove
5506
5506
5507 Mark dest as copies of sources; mark sources for deletion. If dest
5507 Mark dest as copies of sources; mark sources for deletion. If dest
5508 is a directory, copies are put in that directory. If dest is a
5508 is a directory, copies are put in that directory. If dest is a
5509 file, there can only be one source.
5509 file, there can only be one source.
5510
5510
5511 By default, this command copies the contents of files as they
5511 By default, this command copies the contents of files as they
5512 exist in the working directory. If invoked with -A/--after, the
5512 exist in the working directory. If invoked with -A/--after, the
5513 operation is recorded, but no copying is performed.
5513 operation is recorded, but no copying is performed.
5514
5514
5515 This command takes effect at the next commit. To undo a rename
5515 This command takes effect at the next commit. To undo a rename
5516 before that, see :hg:`revert`.
5516 before that, see :hg:`revert`.
5517
5517
5518 Returns 0 on success, 1 if errors are encountered.
5518 Returns 0 on success, 1 if errors are encountered.
5519 """
5519 """
5520 wlock = repo.wlock(False)
5520 wlock = repo.wlock(False)
5521 try:
5521 try:
5522 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5522 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5523 finally:
5523 finally:
5524 wlock.release()
5524 wlock.release()
5525
5525
5526 @command('resolve',
5526 @command('resolve',
5527 [('a', 'all', None, _('select all unresolved files')),
5527 [('a', 'all', None, _('select all unresolved files')),
5528 ('l', 'list', None, _('list state of files needing merge')),
5528 ('l', 'list', None, _('list state of files needing merge')),
5529 ('m', 'mark', None, _('mark files as resolved')),
5529 ('m', 'mark', None, _('mark files as resolved')),
5530 ('u', 'unmark', None, _('mark files as unresolved')),
5530 ('u', 'unmark', None, _('mark files as unresolved')),
5531 ('n', 'no-status', None, _('hide status prefix'))]
5531 ('n', 'no-status', None, _('hide status prefix'))]
5532 + mergetoolopts + walkopts + formatteropts,
5532 + mergetoolopts + walkopts + formatteropts,
5533 _('[OPTION]... [FILE]...'),
5533 _('[OPTION]... [FILE]...'),
5534 inferrepo=True)
5534 inferrepo=True)
5535 def resolve(ui, repo, *pats, **opts):
5535 def resolve(ui, repo, *pats, **opts):
5536 """redo merges or set/view the merge status of files
5536 """redo merges or set/view the merge status of files
5537
5537
5538 Merges with unresolved conflicts are often the result of
5538 Merges with unresolved conflicts are often the result of
5539 non-interactive merging using the ``internal:merge`` configuration
5539 non-interactive merging using the ``internal:merge`` configuration
5540 setting, or a command-line merge tool like ``diff3``. The resolve
5540 setting, or a command-line merge tool like ``diff3``. The resolve
5541 command is used to manage the files involved in a merge, after
5541 command is used to manage the files involved in a merge, after
5542 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5542 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5543 working directory must have two parents). See :hg:`help
5543 working directory must have two parents). See :hg:`help
5544 merge-tools` for information on configuring merge tools.
5544 merge-tools` for information on configuring merge tools.
5545
5545
5546 The resolve command can be used in the following ways:
5546 The resolve command can be used in the following ways:
5547
5547
5548 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5548 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5549 files, discarding any previous merge attempts. Re-merging is not
5549 files, discarding any previous merge attempts. Re-merging is not
5550 performed for files already marked as resolved. Use ``--all/-a``
5550 performed for files already marked as resolved. Use ``--all/-a``
5551 to select all unresolved files. ``--tool`` can be used to specify
5551 to select all unresolved files. ``--tool`` can be used to specify
5552 the merge tool used for the given files. It overrides the HGMERGE
5552 the merge tool used for the given files. It overrides the HGMERGE
5553 environment variable and your configuration files. Previous file
5553 environment variable and your configuration files. Previous file
5554 contents are saved with a ``.orig`` suffix.
5554 contents are saved with a ``.orig`` suffix.
5555
5555
5556 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5556 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5557 (e.g. after having manually fixed-up the files). The default is
5557 (e.g. after having manually fixed-up the files). The default is
5558 to mark all unresolved files.
5558 to mark all unresolved files.
5559
5559
5560 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5560 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5561 default is to mark all resolved files.
5561 default is to mark all resolved files.
5562
5562
5563 - :hg:`resolve -l`: list files which had or still have conflicts.
5563 - :hg:`resolve -l`: list files which had or still have conflicts.
5564 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5564 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5565
5565
5566 Note that Mercurial will not let you commit files with unresolved
5566 Note that Mercurial will not let you commit files with unresolved
5567 merge conflicts. You must use :hg:`resolve -m ...` before you can
5567 merge conflicts. You must use :hg:`resolve -m ...` before you can
5568 commit after a conflicting merge.
5568 commit after a conflicting merge.
5569
5569
5570 Returns 0 on success, 1 if any files fail a resolve attempt.
5570 Returns 0 on success, 1 if any files fail a resolve attempt.
5571 """
5571 """
5572
5572
5573 all, mark, unmark, show, nostatus = \
5573 all, mark, unmark, show, nostatus = \
5574 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5574 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5575
5575
5576 if (show and (mark or unmark)) or (mark and unmark):
5576 if (show and (mark or unmark)) or (mark and unmark):
5577 raise error.Abort(_("too many options specified"))
5577 raise error.Abort(_("too many options specified"))
5578 if pats and all:
5578 if pats and all:
5579 raise error.Abort(_("can't specify --all and patterns"))
5579 raise error.Abort(_("can't specify --all and patterns"))
5580 if not (all or pats or show or mark or unmark):
5580 if not (all or pats or show or mark or unmark):
5581 raise error.Abort(_('no files or directories specified'),
5581 raise error.Abort(_('no files or directories specified'),
5582 hint=('use --all to re-merge all unresolved files'))
5582 hint=('use --all to re-merge all unresolved files'))
5583
5583
5584 if show:
5584 if show:
5585 fm = ui.formatter('resolve', opts)
5585 fm = ui.formatter('resolve', opts)
5586 ms = mergemod.mergestate(repo)
5586 ms = mergemod.mergestate(repo)
5587 m = scmutil.match(repo[None], pats, opts)
5587 m = scmutil.match(repo[None], pats, opts)
5588 for f in ms:
5588 for f in ms:
5589 if not m(f):
5589 if not m(f):
5590 continue
5590 continue
5591 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5591 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved',
5592 'd': 'driverresolved'}[ms[f]]
5592 'd': 'driverresolved'}[ms[f]]
5593 fm.startitem()
5593 fm.startitem()
5594 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5594 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5595 fm.write('path', '%s\n', f, label=l)
5595 fm.write('path', '%s\n', f, label=l)
5596 fm.end()
5596 fm.end()
5597 return 0
5597 return 0
5598
5598
5599 wlock = repo.wlock()
5599 wlock = repo.wlock()
5600 try:
5600 try:
5601 ms = mergemod.mergestate(repo)
5601 ms = mergemod.mergestate(repo)
5602
5602
5603 if not (ms.active() or repo.dirstate.p2() != nullid):
5603 if not (ms.active() or repo.dirstate.p2() != nullid):
5604 raise error.Abort(
5604 raise error.Abort(
5605 _('resolve command not applicable when not merging'))
5605 _('resolve command not applicable when not merging'))
5606
5606
5607 wctx = repo[None]
5607 wctx = repo[None]
5608
5608
5609 m = scmutil.match(wctx, pats, opts)
5609 m = scmutil.match(wctx, pats, opts)
5610 ret = 0
5610 ret = 0
5611 didwork = False
5611 didwork = False
5612
5612
5613 tocomplete = []
5613 tocomplete = []
5614 for f in ms:
5614 for f in ms:
5615 if not m(f):
5615 if not m(f):
5616 continue
5616 continue
5617
5617
5618 didwork = True
5618 didwork = True
5619
5619
5620 # don't let driver-resolved files be marked
5621 if ms[f] == "d":
5622 exact = m.exact(f)
5623 if mark:
5624 if exact:
5625 ui.warn(_('not marking %s as it is driver-resolved\n')
5626 % f)
5627 elif unmark:
5628 if exact:
5629 ui.warn(_('not unmarking %s as it is driver-resolved\n')
5630 % f)
5631 continue
5632
5620 if mark:
5633 if mark:
5621 ms.mark(f, "r")
5634 ms.mark(f, "r")
5622 elif unmark:
5635 elif unmark:
5623 ms.mark(f, "u")
5636 ms.mark(f, "u")
5624 else:
5637 else:
5625 # backup pre-resolve (merge uses .orig for its own purposes)
5638 # backup pre-resolve (merge uses .orig for its own purposes)
5626 a = repo.wjoin(f)
5639 a = repo.wjoin(f)
5627 util.copyfile(a, a + ".resolve")
5640 util.copyfile(a, a + ".resolve")
5628
5641
5629 try:
5642 try:
5630 # preresolve file
5643 # preresolve file
5631 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5644 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5632 'resolve')
5645 'resolve')
5633 complete, r = ms.preresolve(f, wctx)
5646 complete, r = ms.preresolve(f, wctx)
5634 if not complete:
5647 if not complete:
5635 tocomplete.append(f)
5648 tocomplete.append(f)
5636 elif r:
5649 elif r:
5637 ret = 1
5650 ret = 1
5638 finally:
5651 finally:
5639 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5652 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5640 ms.commit()
5653 ms.commit()
5641
5654
5642 # replace filemerge's .orig file with our resolve file
5655 # replace filemerge's .orig file with our resolve file
5643 # for files in tocomplete, ms.resolve will not overwrite
5656 # for files in tocomplete, ms.resolve will not overwrite
5644 # .orig -- only preresolve does
5657 # .orig -- only preresolve does
5645 util.rename(a + ".resolve", a + ".orig")
5658 util.rename(a + ".resolve", a + ".orig")
5646
5659
5647 for f in tocomplete:
5660 for f in tocomplete:
5648 try:
5661 try:
5649 # resolve file
5662 # resolve file
5650 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5663 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5651 'resolve')
5664 'resolve')
5652 r = ms.resolve(f, wctx)
5665 r = ms.resolve(f, wctx)
5653 if r:
5666 if r:
5654 ret = 1
5667 ret = 1
5655 finally:
5668 finally:
5656 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5669 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5657 ms.commit()
5670 ms.commit()
5658
5671
5659 ms.commit()
5672 ms.commit()
5660
5673
5661 if not didwork and pats:
5674 if not didwork and pats:
5662 ui.warn(_("arguments do not match paths that need resolving\n"))
5675 ui.warn(_("arguments do not match paths that need resolving\n"))
5663
5676
5664 finally:
5677 finally:
5665 wlock.release()
5678 wlock.release()
5666
5679
5667 # Nudge users into finishing an unfinished operation
5680 # Nudge users into finishing an unfinished operation
5668 unresolvedf = list(ms.unresolved())
5681 unresolvedf = list(ms.unresolved())
5669 driverresolvedf = list(ms.driverresolved())
5682 driverresolvedf = list(ms.driverresolved())
5670 if not unresolvedf and not driverresolvedf:
5683 if not unresolvedf and not driverresolvedf:
5671 ui.status(_('(no more unresolved files)\n'))
5684 ui.status(_('(no more unresolved files)\n'))
5672 elif not unresolvedf:
5685 elif not unresolvedf:
5673 ui.status(_('(no more unresolved files -- '
5686 ui.status(_('(no more unresolved files -- '
5674 'run "hg resolve --all" to conclude)\n'))
5687 'run "hg resolve --all" to conclude)\n'))
5675
5688
5676 return ret
5689 return ret
5677
5690
5678 @command('revert',
5691 @command('revert',
5679 [('a', 'all', None, _('revert all changes when no arguments given')),
5692 [('a', 'all', None, _('revert all changes when no arguments given')),
5680 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5693 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5681 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5694 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5682 ('C', 'no-backup', None, _('do not save backup copies of files')),
5695 ('C', 'no-backup', None, _('do not save backup copies of files')),
5683 ('i', 'interactive', None,
5696 ('i', 'interactive', None,
5684 _('interactively select the changes (EXPERIMENTAL)')),
5697 _('interactively select the changes (EXPERIMENTAL)')),
5685 ] + walkopts + dryrunopts,
5698 ] + walkopts + dryrunopts,
5686 _('[OPTION]... [-r REV] [NAME]...'))
5699 _('[OPTION]... [-r REV] [NAME]...'))
5687 def revert(ui, repo, *pats, **opts):
5700 def revert(ui, repo, *pats, **opts):
5688 """restore files to their checkout state
5701 """restore files to their checkout state
5689
5702
5690 .. note::
5703 .. note::
5691
5704
5692 To check out earlier revisions, you should use :hg:`update REV`.
5705 To check out earlier revisions, you should use :hg:`update REV`.
5693 To cancel an uncommitted merge (and lose your changes),
5706 To cancel an uncommitted merge (and lose your changes),
5694 use :hg:`update --clean .`.
5707 use :hg:`update --clean .`.
5695
5708
5696 With no revision specified, revert the specified files or directories
5709 With no revision specified, revert the specified files or directories
5697 to the contents they had in the parent of the working directory.
5710 to the contents they had in the parent of the working directory.
5698 This restores the contents of files to an unmodified
5711 This restores the contents of files to an unmodified
5699 state and unschedules adds, removes, copies, and renames. If the
5712 state and unschedules adds, removes, copies, and renames. If the
5700 working directory has two parents, you must explicitly specify a
5713 working directory has two parents, you must explicitly specify a
5701 revision.
5714 revision.
5702
5715
5703 Using the -r/--rev or -d/--date options, revert the given files or
5716 Using the -r/--rev or -d/--date options, revert the given files or
5704 directories to their states as of a specific revision. Because
5717 directories to their states as of a specific revision. Because
5705 revert does not change the working directory parents, this will
5718 revert does not change the working directory parents, this will
5706 cause these files to appear modified. This can be helpful to "back
5719 cause these files to appear modified. This can be helpful to "back
5707 out" some or all of an earlier change. See :hg:`backout` for a
5720 out" some or all of an earlier change. See :hg:`backout` for a
5708 related method.
5721 related method.
5709
5722
5710 Modified files are saved with a .orig suffix before reverting.
5723 Modified files are saved with a .orig suffix before reverting.
5711 To disable these backups, use --no-backup.
5724 To disable these backups, use --no-backup.
5712
5725
5713 See :hg:`help dates` for a list of formats valid for -d/--date.
5726 See :hg:`help dates` for a list of formats valid for -d/--date.
5714
5727
5715 See :hg:`help backout` for a way to reverse the effect of an
5728 See :hg:`help backout` for a way to reverse the effect of an
5716 earlier changeset.
5729 earlier changeset.
5717
5730
5718 Returns 0 on success.
5731 Returns 0 on success.
5719 """
5732 """
5720
5733
5721 if opts.get("date"):
5734 if opts.get("date"):
5722 if opts.get("rev"):
5735 if opts.get("rev"):
5723 raise error.Abort(_("you can't specify a revision and a date"))
5736 raise error.Abort(_("you can't specify a revision and a date"))
5724 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5737 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5725
5738
5726 parent, p2 = repo.dirstate.parents()
5739 parent, p2 = repo.dirstate.parents()
5727 if not opts.get('rev') and p2 != nullid:
5740 if not opts.get('rev') and p2 != nullid:
5728 # revert after merge is a trap for new users (issue2915)
5741 # revert after merge is a trap for new users (issue2915)
5729 raise error.Abort(_('uncommitted merge with no revision specified'),
5742 raise error.Abort(_('uncommitted merge with no revision specified'),
5730 hint=_('use "hg update" or see "hg help revert"'))
5743 hint=_('use "hg update" or see "hg help revert"'))
5731
5744
5732 ctx = scmutil.revsingle(repo, opts.get('rev'))
5745 ctx = scmutil.revsingle(repo, opts.get('rev'))
5733
5746
5734 if (not (pats or opts.get('include') or opts.get('exclude') or
5747 if (not (pats or opts.get('include') or opts.get('exclude') or
5735 opts.get('all') or opts.get('interactive'))):
5748 opts.get('all') or opts.get('interactive'))):
5736 msg = _("no files or directories specified")
5749 msg = _("no files or directories specified")
5737 if p2 != nullid:
5750 if p2 != nullid:
5738 hint = _("uncommitted merge, use --all to discard all changes,"
5751 hint = _("uncommitted merge, use --all to discard all changes,"
5739 " or 'hg update -C .' to abort the merge")
5752 " or 'hg update -C .' to abort the merge")
5740 raise error.Abort(msg, hint=hint)
5753 raise error.Abort(msg, hint=hint)
5741 dirty = any(repo.status())
5754 dirty = any(repo.status())
5742 node = ctx.node()
5755 node = ctx.node()
5743 if node != parent:
5756 if node != parent:
5744 if dirty:
5757 if dirty:
5745 hint = _("uncommitted changes, use --all to discard all"
5758 hint = _("uncommitted changes, use --all to discard all"
5746 " changes, or 'hg update %s' to update") % ctx.rev()
5759 " changes, or 'hg update %s' to update") % ctx.rev()
5747 else:
5760 else:
5748 hint = _("use --all to revert all files,"
5761 hint = _("use --all to revert all files,"
5749 " or 'hg update %s' to update") % ctx.rev()
5762 " or 'hg update %s' to update") % ctx.rev()
5750 elif dirty:
5763 elif dirty:
5751 hint = _("uncommitted changes, use --all to discard all changes")
5764 hint = _("uncommitted changes, use --all to discard all changes")
5752 else:
5765 else:
5753 hint = _("use --all to revert all files")
5766 hint = _("use --all to revert all files")
5754 raise error.Abort(msg, hint=hint)
5767 raise error.Abort(msg, hint=hint)
5755
5768
5756 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5769 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5757
5770
5758 @command('rollback', dryrunopts +
5771 @command('rollback', dryrunopts +
5759 [('f', 'force', False, _('ignore safety measures'))])
5772 [('f', 'force', False, _('ignore safety measures'))])
5760 def rollback(ui, repo, **opts):
5773 def rollback(ui, repo, **opts):
5761 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5774 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5762
5775
5763 Please use :hg:`commit --amend` instead of rollback to correct
5776 Please use :hg:`commit --amend` instead of rollback to correct
5764 mistakes in the last commit.
5777 mistakes in the last commit.
5765
5778
5766 This command should be used with care. There is only one level of
5779 This command should be used with care. There is only one level of
5767 rollback, and there is no way to undo a rollback. It will also
5780 rollback, and there is no way to undo a rollback. It will also
5768 restore the dirstate at the time of the last transaction, losing
5781 restore the dirstate at the time of the last transaction, losing
5769 any dirstate changes since that time. This command does not alter
5782 any dirstate changes since that time. This command does not alter
5770 the working directory.
5783 the working directory.
5771
5784
5772 Transactions are used to encapsulate the effects of all commands
5785 Transactions are used to encapsulate the effects of all commands
5773 that create new changesets or propagate existing changesets into a
5786 that create new changesets or propagate existing changesets into a
5774 repository.
5787 repository.
5775
5788
5776 .. container:: verbose
5789 .. container:: verbose
5777
5790
5778 For example, the following commands are transactional, and their
5791 For example, the following commands are transactional, and their
5779 effects can be rolled back:
5792 effects can be rolled back:
5780
5793
5781 - commit
5794 - commit
5782 - import
5795 - import
5783 - pull
5796 - pull
5784 - push (with this repository as the destination)
5797 - push (with this repository as the destination)
5785 - unbundle
5798 - unbundle
5786
5799
5787 To avoid permanent data loss, rollback will refuse to rollback a
5800 To avoid permanent data loss, rollback will refuse to rollback a
5788 commit transaction if it isn't checked out. Use --force to
5801 commit transaction if it isn't checked out. Use --force to
5789 override this protection.
5802 override this protection.
5790
5803
5791 This command is not intended for use on public repositories. Once
5804 This command is not intended for use on public repositories. Once
5792 changes are visible for pull by other users, rolling a transaction
5805 changes are visible for pull by other users, rolling a transaction
5793 back locally is ineffective (someone else may already have pulled
5806 back locally is ineffective (someone else may already have pulled
5794 the changes). Furthermore, a race is possible with readers of the
5807 the changes). Furthermore, a race is possible with readers of the
5795 repository; for example an in-progress pull from the repository
5808 repository; for example an in-progress pull from the repository
5796 may fail if a rollback is performed.
5809 may fail if a rollback is performed.
5797
5810
5798 Returns 0 on success, 1 if no rollback data is available.
5811 Returns 0 on success, 1 if no rollback data is available.
5799 """
5812 """
5800 return repo.rollback(dryrun=opts.get('dry_run'),
5813 return repo.rollback(dryrun=opts.get('dry_run'),
5801 force=opts.get('force'))
5814 force=opts.get('force'))
5802
5815
5803 @command('root', [])
5816 @command('root', [])
5804 def root(ui, repo):
5817 def root(ui, repo):
5805 """print the root (top) of the current working directory
5818 """print the root (top) of the current working directory
5806
5819
5807 Print the root directory of the current repository.
5820 Print the root directory of the current repository.
5808
5821
5809 Returns 0 on success.
5822 Returns 0 on success.
5810 """
5823 """
5811 ui.write(repo.root + "\n")
5824 ui.write(repo.root + "\n")
5812
5825
5813 @command('^serve',
5826 @command('^serve',
5814 [('A', 'accesslog', '', _('name of access log file to write to'),
5827 [('A', 'accesslog', '', _('name of access log file to write to'),
5815 _('FILE')),
5828 _('FILE')),
5816 ('d', 'daemon', None, _('run server in background')),
5829 ('d', 'daemon', None, _('run server in background')),
5817 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5830 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5818 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5831 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5819 # use string type, then we can check if something was passed
5832 # use string type, then we can check if something was passed
5820 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5833 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5821 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5834 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5822 _('ADDR')),
5835 _('ADDR')),
5823 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5836 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5824 _('PREFIX')),
5837 _('PREFIX')),
5825 ('n', 'name', '',
5838 ('n', 'name', '',
5826 _('name to show in web pages (default: working directory)'), _('NAME')),
5839 _('name to show in web pages (default: working directory)'), _('NAME')),
5827 ('', 'web-conf', '',
5840 ('', 'web-conf', '',
5828 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5841 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5829 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5842 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5830 _('FILE')),
5843 _('FILE')),
5831 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5844 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5832 ('', 'stdio', None, _('for remote clients')),
5845 ('', 'stdio', None, _('for remote clients')),
5833 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5846 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5834 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5847 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5835 ('', 'style', '', _('template style to use'), _('STYLE')),
5848 ('', 'style', '', _('template style to use'), _('STYLE')),
5836 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5849 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5837 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5850 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5838 _('[OPTION]...'),
5851 _('[OPTION]...'),
5839 optionalrepo=True)
5852 optionalrepo=True)
5840 def serve(ui, repo, **opts):
5853 def serve(ui, repo, **opts):
5841 """start stand-alone webserver
5854 """start stand-alone webserver
5842
5855
5843 Start a local HTTP repository browser and pull server. You can use
5856 Start a local HTTP repository browser and pull server. You can use
5844 this for ad-hoc sharing and browsing of repositories. It is
5857 this for ad-hoc sharing and browsing of repositories. It is
5845 recommended to use a real web server to serve a repository for
5858 recommended to use a real web server to serve a repository for
5846 longer periods of time.
5859 longer periods of time.
5847
5860
5848 Please note that the server does not implement access control.
5861 Please note that the server does not implement access control.
5849 This means that, by default, anybody can read from the server and
5862 This means that, by default, anybody can read from the server and
5850 nobody can write to it by default. Set the ``web.allow_push``
5863 nobody can write to it by default. Set the ``web.allow_push``
5851 option to ``*`` to allow everybody to push to the server. You
5864 option to ``*`` to allow everybody to push to the server. You
5852 should use a real web server if you need to authenticate users.
5865 should use a real web server if you need to authenticate users.
5853
5866
5854 By default, the server logs accesses to stdout and errors to
5867 By default, the server logs accesses to stdout and errors to
5855 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5868 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5856 files.
5869 files.
5857
5870
5858 To have the server choose a free port number to listen on, specify
5871 To have the server choose a free port number to listen on, specify
5859 a port number of 0; in this case, the server will print the port
5872 a port number of 0; in this case, the server will print the port
5860 number it uses.
5873 number it uses.
5861
5874
5862 Returns 0 on success.
5875 Returns 0 on success.
5863 """
5876 """
5864
5877
5865 if opts["stdio"] and opts["cmdserver"]:
5878 if opts["stdio"] and opts["cmdserver"]:
5866 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5879 raise error.Abort(_("cannot use --stdio with --cmdserver"))
5867
5880
5868 if opts["stdio"]:
5881 if opts["stdio"]:
5869 if repo is None:
5882 if repo is None:
5870 raise error.RepoError(_("there is no Mercurial repository here"
5883 raise error.RepoError(_("there is no Mercurial repository here"
5871 " (.hg not found)"))
5884 " (.hg not found)"))
5872 s = sshserver.sshserver(ui, repo)
5885 s = sshserver.sshserver(ui, repo)
5873 s.serve_forever()
5886 s.serve_forever()
5874
5887
5875 if opts["cmdserver"]:
5888 if opts["cmdserver"]:
5876 import commandserver
5889 import commandserver
5877 service = commandserver.createservice(ui, repo, opts)
5890 service = commandserver.createservice(ui, repo, opts)
5878 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5891 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5879
5892
5880 # this way we can check if something was given in the command-line
5893 # this way we can check if something was given in the command-line
5881 if opts.get('port'):
5894 if opts.get('port'):
5882 opts['port'] = util.getport(opts.get('port'))
5895 opts['port'] = util.getport(opts.get('port'))
5883
5896
5884 if repo:
5897 if repo:
5885 baseui = repo.baseui
5898 baseui = repo.baseui
5886 else:
5899 else:
5887 baseui = ui
5900 baseui = ui
5888 optlist = ("name templates style address port prefix ipv6"
5901 optlist = ("name templates style address port prefix ipv6"
5889 " accesslog errorlog certificate encoding")
5902 " accesslog errorlog certificate encoding")
5890 for o in optlist.split():
5903 for o in optlist.split():
5891 val = opts.get(o, '')
5904 val = opts.get(o, '')
5892 if val in (None, ''): # should check against default options instead
5905 if val in (None, ''): # should check against default options instead
5893 continue
5906 continue
5894 baseui.setconfig("web", o, val, 'serve')
5907 baseui.setconfig("web", o, val, 'serve')
5895 if repo and repo.ui != baseui:
5908 if repo and repo.ui != baseui:
5896 repo.ui.setconfig("web", o, val, 'serve')
5909 repo.ui.setconfig("web", o, val, 'serve')
5897
5910
5898 o = opts.get('web_conf') or opts.get('webdir_conf')
5911 o = opts.get('web_conf') or opts.get('webdir_conf')
5899 if not o:
5912 if not o:
5900 if not repo:
5913 if not repo:
5901 raise error.RepoError(_("there is no Mercurial repository"
5914 raise error.RepoError(_("there is no Mercurial repository"
5902 " here (.hg not found)"))
5915 " here (.hg not found)"))
5903 o = repo
5916 o = repo
5904
5917
5905 app = hgweb.hgweb(o, baseui=baseui)
5918 app = hgweb.hgweb(o, baseui=baseui)
5906 service = httpservice(ui, app, opts)
5919 service = httpservice(ui, app, opts)
5907 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5920 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5908
5921
5909 class httpservice(object):
5922 class httpservice(object):
5910 def __init__(self, ui, app, opts):
5923 def __init__(self, ui, app, opts):
5911 self.ui = ui
5924 self.ui = ui
5912 self.app = app
5925 self.app = app
5913 self.opts = opts
5926 self.opts = opts
5914
5927
5915 def init(self):
5928 def init(self):
5916 util.setsignalhandler()
5929 util.setsignalhandler()
5917 self.httpd = hgweb_server.create_server(self.ui, self.app)
5930 self.httpd = hgweb_server.create_server(self.ui, self.app)
5918
5931
5919 if self.opts['port'] and not self.ui.verbose:
5932 if self.opts['port'] and not self.ui.verbose:
5920 return
5933 return
5921
5934
5922 if self.httpd.prefix:
5935 if self.httpd.prefix:
5923 prefix = self.httpd.prefix.strip('/') + '/'
5936 prefix = self.httpd.prefix.strip('/') + '/'
5924 else:
5937 else:
5925 prefix = ''
5938 prefix = ''
5926
5939
5927 port = ':%d' % self.httpd.port
5940 port = ':%d' % self.httpd.port
5928 if port == ':80':
5941 if port == ':80':
5929 port = ''
5942 port = ''
5930
5943
5931 bindaddr = self.httpd.addr
5944 bindaddr = self.httpd.addr
5932 if bindaddr == '0.0.0.0':
5945 if bindaddr == '0.0.0.0':
5933 bindaddr = '*'
5946 bindaddr = '*'
5934 elif ':' in bindaddr: # IPv6
5947 elif ':' in bindaddr: # IPv6
5935 bindaddr = '[%s]' % bindaddr
5948 bindaddr = '[%s]' % bindaddr
5936
5949
5937 fqaddr = self.httpd.fqaddr
5950 fqaddr = self.httpd.fqaddr
5938 if ':' in fqaddr:
5951 if ':' in fqaddr:
5939 fqaddr = '[%s]' % fqaddr
5952 fqaddr = '[%s]' % fqaddr
5940 if self.opts['port']:
5953 if self.opts['port']:
5941 write = self.ui.status
5954 write = self.ui.status
5942 else:
5955 else:
5943 write = self.ui.write
5956 write = self.ui.write
5944 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5957 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5945 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5958 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5946 self.ui.flush() # avoid buffering of status message
5959 self.ui.flush() # avoid buffering of status message
5947
5960
5948 def run(self):
5961 def run(self):
5949 self.httpd.serve_forever()
5962 self.httpd.serve_forever()
5950
5963
5951
5964
5952 @command('^status|st',
5965 @command('^status|st',
5953 [('A', 'all', None, _('show status of all files')),
5966 [('A', 'all', None, _('show status of all files')),
5954 ('m', 'modified', None, _('show only modified files')),
5967 ('m', 'modified', None, _('show only modified files')),
5955 ('a', 'added', None, _('show only added files')),
5968 ('a', 'added', None, _('show only added files')),
5956 ('r', 'removed', None, _('show only removed files')),
5969 ('r', 'removed', None, _('show only removed files')),
5957 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5970 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5958 ('c', 'clean', None, _('show only files without changes')),
5971 ('c', 'clean', None, _('show only files without changes')),
5959 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5972 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5960 ('i', 'ignored', None, _('show only ignored files')),
5973 ('i', 'ignored', None, _('show only ignored files')),
5961 ('n', 'no-status', None, _('hide status prefix')),
5974 ('n', 'no-status', None, _('hide status prefix')),
5962 ('C', 'copies', None, _('show source of copied files')),
5975 ('C', 'copies', None, _('show source of copied files')),
5963 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5976 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5964 ('', 'rev', [], _('show difference from revision'), _('REV')),
5977 ('', 'rev', [], _('show difference from revision'), _('REV')),
5965 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5978 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5966 ] + walkopts + subrepoopts + formatteropts,
5979 ] + walkopts + subrepoopts + formatteropts,
5967 _('[OPTION]... [FILE]...'),
5980 _('[OPTION]... [FILE]...'),
5968 inferrepo=True)
5981 inferrepo=True)
5969 def status(ui, repo, *pats, **opts):
5982 def status(ui, repo, *pats, **opts):
5970 """show changed files in the working directory
5983 """show changed files in the working directory
5971
5984
5972 Show status of files in the repository. If names are given, only
5985 Show status of files in the repository. If names are given, only
5973 files that match are shown. Files that are clean or ignored or
5986 files that match are shown. Files that are clean or ignored or
5974 the source of a copy/move operation, are not listed unless
5987 the source of a copy/move operation, are not listed unless
5975 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5988 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5976 Unless options described with "show only ..." are given, the
5989 Unless options described with "show only ..." are given, the
5977 options -mardu are used.
5990 options -mardu are used.
5978
5991
5979 Option -q/--quiet hides untracked (unknown and ignored) files
5992 Option -q/--quiet hides untracked (unknown and ignored) files
5980 unless explicitly requested with -u/--unknown or -i/--ignored.
5993 unless explicitly requested with -u/--unknown or -i/--ignored.
5981
5994
5982 .. note::
5995 .. note::
5983
5996
5984 status may appear to disagree with diff if permissions have
5997 status may appear to disagree with diff if permissions have
5985 changed or a merge has occurred. The standard diff format does
5998 changed or a merge has occurred. The standard diff format does
5986 not report permission changes and diff only reports changes
5999 not report permission changes and diff only reports changes
5987 relative to one merge parent.
6000 relative to one merge parent.
5988
6001
5989 If one revision is given, it is used as the base revision.
6002 If one revision is given, it is used as the base revision.
5990 If two revisions are given, the differences between them are
6003 If two revisions are given, the differences between them are
5991 shown. The --change option can also be used as a shortcut to list
6004 shown. The --change option can also be used as a shortcut to list
5992 the changed files of a revision from its first parent.
6005 the changed files of a revision from its first parent.
5993
6006
5994 The codes used to show the status of files are::
6007 The codes used to show the status of files are::
5995
6008
5996 M = modified
6009 M = modified
5997 A = added
6010 A = added
5998 R = removed
6011 R = removed
5999 C = clean
6012 C = clean
6000 ! = missing (deleted by non-hg command, but still tracked)
6013 ! = missing (deleted by non-hg command, but still tracked)
6001 ? = not tracked
6014 ? = not tracked
6002 I = ignored
6015 I = ignored
6003 = origin of the previous file (with --copies)
6016 = origin of the previous file (with --copies)
6004
6017
6005 .. container:: verbose
6018 .. container:: verbose
6006
6019
6007 Examples:
6020 Examples:
6008
6021
6009 - show changes in the working directory relative to a
6022 - show changes in the working directory relative to a
6010 changeset::
6023 changeset::
6011
6024
6012 hg status --rev 9353
6025 hg status --rev 9353
6013
6026
6014 - show changes in the working directory relative to the
6027 - show changes in the working directory relative to the
6015 current directory (see :hg:`help patterns` for more information)::
6028 current directory (see :hg:`help patterns` for more information)::
6016
6029
6017 hg status re:
6030 hg status re:
6018
6031
6019 - show all changes including copies in an existing changeset::
6032 - show all changes including copies in an existing changeset::
6020
6033
6021 hg status --copies --change 9353
6034 hg status --copies --change 9353
6022
6035
6023 - get a NUL separated list of added files, suitable for xargs::
6036 - get a NUL separated list of added files, suitable for xargs::
6024
6037
6025 hg status -an0
6038 hg status -an0
6026
6039
6027 Returns 0 on success.
6040 Returns 0 on success.
6028 """
6041 """
6029
6042
6030 revs = opts.get('rev')
6043 revs = opts.get('rev')
6031 change = opts.get('change')
6044 change = opts.get('change')
6032
6045
6033 if revs and change:
6046 if revs and change:
6034 msg = _('cannot specify --rev and --change at the same time')
6047 msg = _('cannot specify --rev and --change at the same time')
6035 raise error.Abort(msg)
6048 raise error.Abort(msg)
6036 elif change:
6049 elif change:
6037 node2 = scmutil.revsingle(repo, change, None).node()
6050 node2 = scmutil.revsingle(repo, change, None).node()
6038 node1 = repo[node2].p1().node()
6051 node1 = repo[node2].p1().node()
6039 else:
6052 else:
6040 node1, node2 = scmutil.revpair(repo, revs)
6053 node1, node2 = scmutil.revpair(repo, revs)
6041
6054
6042 if pats:
6055 if pats:
6043 cwd = repo.getcwd()
6056 cwd = repo.getcwd()
6044 else:
6057 else:
6045 cwd = ''
6058 cwd = ''
6046
6059
6047 if opts.get('print0'):
6060 if opts.get('print0'):
6048 end = '\0'
6061 end = '\0'
6049 else:
6062 else:
6050 end = '\n'
6063 end = '\n'
6051 copy = {}
6064 copy = {}
6052 states = 'modified added removed deleted unknown ignored clean'.split()
6065 states = 'modified added removed deleted unknown ignored clean'.split()
6053 show = [k for k in states if opts.get(k)]
6066 show = [k for k in states if opts.get(k)]
6054 if opts.get('all'):
6067 if opts.get('all'):
6055 show += ui.quiet and (states[:4] + ['clean']) or states
6068 show += ui.quiet and (states[:4] + ['clean']) or states
6056 if not show:
6069 if not show:
6057 if ui.quiet:
6070 if ui.quiet:
6058 show = states[:4]
6071 show = states[:4]
6059 else:
6072 else:
6060 show = states[:5]
6073 show = states[:5]
6061
6074
6062 m = scmutil.match(repo[node2], pats, opts)
6075 m = scmutil.match(repo[node2], pats, opts)
6063 stat = repo.status(node1, node2, m,
6076 stat = repo.status(node1, node2, m,
6064 'ignored' in show, 'clean' in show, 'unknown' in show,
6077 'ignored' in show, 'clean' in show, 'unknown' in show,
6065 opts.get('subrepos'))
6078 opts.get('subrepos'))
6066 changestates = zip(states, 'MAR!?IC', stat)
6079 changestates = zip(states, 'MAR!?IC', stat)
6067
6080
6068 if (opts.get('all') or opts.get('copies')
6081 if (opts.get('all') or opts.get('copies')
6069 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6082 or ui.configbool('ui', 'statuscopies')) and not opts.get('no_status'):
6070 copy = copies.pathcopies(repo[node1], repo[node2], m)
6083 copy = copies.pathcopies(repo[node1], repo[node2], m)
6071
6084
6072 fm = ui.formatter('status', opts)
6085 fm = ui.formatter('status', opts)
6073 fmt = '%s' + end
6086 fmt = '%s' + end
6074 showchar = not opts.get('no_status')
6087 showchar = not opts.get('no_status')
6075
6088
6076 for state, char, files in changestates:
6089 for state, char, files in changestates:
6077 if state in show:
6090 if state in show:
6078 label = 'status.' + state
6091 label = 'status.' + state
6079 for f in files:
6092 for f in files:
6080 fm.startitem()
6093 fm.startitem()
6081 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6094 fm.condwrite(showchar, 'status', '%s ', char, label=label)
6082 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6095 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
6083 if f in copy:
6096 if f in copy:
6084 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6097 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
6085 label='status.copied')
6098 label='status.copied')
6086 fm.end()
6099 fm.end()
6087
6100
6088 @command('^summary|sum',
6101 @command('^summary|sum',
6089 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6102 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
6090 def summary(ui, repo, **opts):
6103 def summary(ui, repo, **opts):
6091 """summarize working directory state
6104 """summarize working directory state
6092
6105
6093 This generates a brief summary of the working directory state,
6106 This generates a brief summary of the working directory state,
6094 including parents, branch, commit status, phase and available updates.
6107 including parents, branch, commit status, phase and available updates.
6095
6108
6096 With the --remote option, this will check the default paths for
6109 With the --remote option, this will check the default paths for
6097 incoming and outgoing changes. This can be time-consuming.
6110 incoming and outgoing changes. This can be time-consuming.
6098
6111
6099 Returns 0 on success.
6112 Returns 0 on success.
6100 """
6113 """
6101
6114
6102 ctx = repo[None]
6115 ctx = repo[None]
6103 parents = ctx.parents()
6116 parents = ctx.parents()
6104 pnode = parents[0].node()
6117 pnode = parents[0].node()
6105 marks = []
6118 marks = []
6106
6119
6107 for p in parents:
6120 for p in parents:
6108 # label with log.changeset (instead of log.parent) since this
6121 # label with log.changeset (instead of log.parent) since this
6109 # shows a working directory parent *changeset*:
6122 # shows a working directory parent *changeset*:
6110 # i18n: column positioning for "hg summary"
6123 # i18n: column positioning for "hg summary"
6111 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6124 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
6112 label='log.changeset changeset.%s' % p.phasestr())
6125 label='log.changeset changeset.%s' % p.phasestr())
6113 ui.write(' '.join(p.tags()), label='log.tag')
6126 ui.write(' '.join(p.tags()), label='log.tag')
6114 if p.bookmarks():
6127 if p.bookmarks():
6115 marks.extend(p.bookmarks())
6128 marks.extend(p.bookmarks())
6116 if p.rev() == -1:
6129 if p.rev() == -1:
6117 if not len(repo):
6130 if not len(repo):
6118 ui.write(_(' (empty repository)'))
6131 ui.write(_(' (empty repository)'))
6119 else:
6132 else:
6120 ui.write(_(' (no revision checked out)'))
6133 ui.write(_(' (no revision checked out)'))
6121 ui.write('\n')
6134 ui.write('\n')
6122 if p.description():
6135 if p.description():
6123 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6136 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
6124 label='log.summary')
6137 label='log.summary')
6125
6138
6126 branch = ctx.branch()
6139 branch = ctx.branch()
6127 bheads = repo.branchheads(branch)
6140 bheads = repo.branchheads(branch)
6128 # i18n: column positioning for "hg summary"
6141 # i18n: column positioning for "hg summary"
6129 m = _('branch: %s\n') % branch
6142 m = _('branch: %s\n') % branch
6130 if branch != 'default':
6143 if branch != 'default':
6131 ui.write(m, label='log.branch')
6144 ui.write(m, label='log.branch')
6132 else:
6145 else:
6133 ui.status(m, label='log.branch')
6146 ui.status(m, label='log.branch')
6134
6147
6135 if marks:
6148 if marks:
6136 active = repo._activebookmark
6149 active = repo._activebookmark
6137 # i18n: column positioning for "hg summary"
6150 # i18n: column positioning for "hg summary"
6138 ui.write(_('bookmarks:'), label='log.bookmark')
6151 ui.write(_('bookmarks:'), label='log.bookmark')
6139 if active is not None:
6152 if active is not None:
6140 if active in marks:
6153 if active in marks:
6141 ui.write(' *' + active, label=activebookmarklabel)
6154 ui.write(' *' + active, label=activebookmarklabel)
6142 marks.remove(active)
6155 marks.remove(active)
6143 else:
6156 else:
6144 ui.write(' [%s]' % active, label=activebookmarklabel)
6157 ui.write(' [%s]' % active, label=activebookmarklabel)
6145 for m in marks:
6158 for m in marks:
6146 ui.write(' ' + m, label='log.bookmark')
6159 ui.write(' ' + m, label='log.bookmark')
6147 ui.write('\n', label='log.bookmark')
6160 ui.write('\n', label='log.bookmark')
6148
6161
6149 status = repo.status(unknown=True)
6162 status = repo.status(unknown=True)
6150
6163
6151 c = repo.dirstate.copies()
6164 c = repo.dirstate.copies()
6152 copied, renamed = [], []
6165 copied, renamed = [], []
6153 for d, s in c.iteritems():
6166 for d, s in c.iteritems():
6154 if s in status.removed:
6167 if s in status.removed:
6155 status.removed.remove(s)
6168 status.removed.remove(s)
6156 renamed.append(d)
6169 renamed.append(d)
6157 else:
6170 else:
6158 copied.append(d)
6171 copied.append(d)
6159 if d in status.added:
6172 if d in status.added:
6160 status.added.remove(d)
6173 status.added.remove(d)
6161
6174
6162 ms = mergemod.mergestate(repo)
6175 ms = mergemod.mergestate(repo)
6163 unresolved = [f for f in ms if ms[f] == 'u']
6176 unresolved = [f for f in ms if ms[f] == 'u']
6164
6177
6165 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6178 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6166
6179
6167 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6180 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
6168 (ui.label(_('%d added'), 'status.added'), status.added),
6181 (ui.label(_('%d added'), 'status.added'), status.added),
6169 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6182 (ui.label(_('%d removed'), 'status.removed'), status.removed),
6170 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6183 (ui.label(_('%d renamed'), 'status.copied'), renamed),
6171 (ui.label(_('%d copied'), 'status.copied'), copied),
6184 (ui.label(_('%d copied'), 'status.copied'), copied),
6172 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6185 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
6173 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6186 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
6174 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6187 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
6175 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6188 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
6176 t = []
6189 t = []
6177 for l, s in labels:
6190 for l, s in labels:
6178 if s:
6191 if s:
6179 t.append(l % len(s))
6192 t.append(l % len(s))
6180
6193
6181 t = ', '.join(t)
6194 t = ', '.join(t)
6182 cleanworkdir = False
6195 cleanworkdir = False
6183
6196
6184 if repo.vfs.exists('updatestate'):
6197 if repo.vfs.exists('updatestate'):
6185 t += _(' (interrupted update)')
6198 t += _(' (interrupted update)')
6186 elif len(parents) > 1:
6199 elif len(parents) > 1:
6187 t += _(' (merge)')
6200 t += _(' (merge)')
6188 elif branch != parents[0].branch():
6201 elif branch != parents[0].branch():
6189 t += _(' (new branch)')
6202 t += _(' (new branch)')
6190 elif (parents[0].closesbranch() and
6203 elif (parents[0].closesbranch() and
6191 pnode in repo.branchheads(branch, closed=True)):
6204 pnode in repo.branchheads(branch, closed=True)):
6192 t += _(' (head closed)')
6205 t += _(' (head closed)')
6193 elif not (status.modified or status.added or status.removed or renamed or
6206 elif not (status.modified or status.added or status.removed or renamed or
6194 copied or subs):
6207 copied or subs):
6195 t += _(' (clean)')
6208 t += _(' (clean)')
6196 cleanworkdir = True
6209 cleanworkdir = True
6197 elif pnode not in bheads:
6210 elif pnode not in bheads:
6198 t += _(' (new branch head)')
6211 t += _(' (new branch head)')
6199
6212
6200 if parents:
6213 if parents:
6201 pendingphase = max(p.phase() for p in parents)
6214 pendingphase = max(p.phase() for p in parents)
6202 else:
6215 else:
6203 pendingphase = phases.public
6216 pendingphase = phases.public
6204
6217
6205 if pendingphase > phases.newcommitphase(ui):
6218 if pendingphase > phases.newcommitphase(ui):
6206 t += ' (%s)' % phases.phasenames[pendingphase]
6219 t += ' (%s)' % phases.phasenames[pendingphase]
6207
6220
6208 if cleanworkdir:
6221 if cleanworkdir:
6209 # i18n: column positioning for "hg summary"
6222 # i18n: column positioning for "hg summary"
6210 ui.status(_('commit: %s\n') % t.strip())
6223 ui.status(_('commit: %s\n') % t.strip())
6211 else:
6224 else:
6212 # i18n: column positioning for "hg summary"
6225 # i18n: column positioning for "hg summary"
6213 ui.write(_('commit: %s\n') % t.strip())
6226 ui.write(_('commit: %s\n') % t.strip())
6214
6227
6215 # all ancestors of branch heads - all ancestors of parent = new csets
6228 # all ancestors of branch heads - all ancestors of parent = new csets
6216 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6229 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
6217 bheads))
6230 bheads))
6218
6231
6219 if new == 0:
6232 if new == 0:
6220 # i18n: column positioning for "hg summary"
6233 # i18n: column positioning for "hg summary"
6221 ui.status(_('update: (current)\n'))
6234 ui.status(_('update: (current)\n'))
6222 elif pnode not in bheads:
6235 elif pnode not in bheads:
6223 # i18n: column positioning for "hg summary"
6236 # i18n: column positioning for "hg summary"
6224 ui.write(_('update: %d new changesets (update)\n') % new)
6237 ui.write(_('update: %d new changesets (update)\n') % new)
6225 else:
6238 else:
6226 # i18n: column positioning for "hg summary"
6239 # i18n: column positioning for "hg summary"
6227 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6240 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
6228 (new, len(bheads)))
6241 (new, len(bheads)))
6229
6242
6230 t = []
6243 t = []
6231 draft = len(repo.revs('draft()'))
6244 draft = len(repo.revs('draft()'))
6232 if draft:
6245 if draft:
6233 t.append(_('%d draft') % draft)
6246 t.append(_('%d draft') % draft)
6234 secret = len(repo.revs('secret()'))
6247 secret = len(repo.revs('secret()'))
6235 if secret:
6248 if secret:
6236 t.append(_('%d secret') % secret)
6249 t.append(_('%d secret') % secret)
6237
6250
6238 if draft or secret:
6251 if draft or secret:
6239 ui.status(_('phases: %s\n') % ', '.join(t))
6252 ui.status(_('phases: %s\n') % ', '.join(t))
6240
6253
6241 cmdutil.summaryhooks(ui, repo)
6254 cmdutil.summaryhooks(ui, repo)
6242
6255
6243 if opts.get('remote'):
6256 if opts.get('remote'):
6244 needsincoming, needsoutgoing = True, True
6257 needsincoming, needsoutgoing = True, True
6245 else:
6258 else:
6246 needsincoming, needsoutgoing = False, False
6259 needsincoming, needsoutgoing = False, False
6247 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6260 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
6248 if i:
6261 if i:
6249 needsincoming = True
6262 needsincoming = True
6250 if o:
6263 if o:
6251 needsoutgoing = True
6264 needsoutgoing = True
6252 if not needsincoming and not needsoutgoing:
6265 if not needsincoming and not needsoutgoing:
6253 return
6266 return
6254
6267
6255 def getincoming():
6268 def getincoming():
6256 source, branches = hg.parseurl(ui.expandpath('default'))
6269 source, branches = hg.parseurl(ui.expandpath('default'))
6257 sbranch = branches[0]
6270 sbranch = branches[0]
6258 try:
6271 try:
6259 other = hg.peer(repo, {}, source)
6272 other = hg.peer(repo, {}, source)
6260 except error.RepoError:
6273 except error.RepoError:
6261 if opts.get('remote'):
6274 if opts.get('remote'):
6262 raise
6275 raise
6263 return source, sbranch, None, None, None
6276 return source, sbranch, None, None, None
6264 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6277 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
6265 if revs:
6278 if revs:
6266 revs = [other.lookup(rev) for rev in revs]
6279 revs = [other.lookup(rev) for rev in revs]
6267 ui.debug('comparing with %s\n' % util.hidepassword(source))
6280 ui.debug('comparing with %s\n' % util.hidepassword(source))
6268 repo.ui.pushbuffer()
6281 repo.ui.pushbuffer()
6269 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6282 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
6270 repo.ui.popbuffer()
6283 repo.ui.popbuffer()
6271 return source, sbranch, other, commoninc, commoninc[1]
6284 return source, sbranch, other, commoninc, commoninc[1]
6272
6285
6273 if needsincoming:
6286 if needsincoming:
6274 source, sbranch, sother, commoninc, incoming = getincoming()
6287 source, sbranch, sother, commoninc, incoming = getincoming()
6275 else:
6288 else:
6276 source = sbranch = sother = commoninc = incoming = None
6289 source = sbranch = sother = commoninc = incoming = None
6277
6290
6278 def getoutgoing():
6291 def getoutgoing():
6279 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6292 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
6280 dbranch = branches[0]
6293 dbranch = branches[0]
6281 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6294 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
6282 if source != dest:
6295 if source != dest:
6283 try:
6296 try:
6284 dother = hg.peer(repo, {}, dest)
6297 dother = hg.peer(repo, {}, dest)
6285 except error.RepoError:
6298 except error.RepoError:
6286 if opts.get('remote'):
6299 if opts.get('remote'):
6287 raise
6300 raise
6288 return dest, dbranch, None, None
6301 return dest, dbranch, None, None
6289 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6302 ui.debug('comparing with %s\n' % util.hidepassword(dest))
6290 elif sother is None:
6303 elif sother is None:
6291 # there is no explicit destination peer, but source one is invalid
6304 # there is no explicit destination peer, but source one is invalid
6292 return dest, dbranch, None, None
6305 return dest, dbranch, None, None
6293 else:
6306 else:
6294 dother = sother
6307 dother = sother
6295 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6308 if (source != dest or (sbranch is not None and sbranch != dbranch)):
6296 common = None
6309 common = None
6297 else:
6310 else:
6298 common = commoninc
6311 common = commoninc
6299 if revs:
6312 if revs:
6300 revs = [repo.lookup(rev) for rev in revs]
6313 revs = [repo.lookup(rev) for rev in revs]
6301 repo.ui.pushbuffer()
6314 repo.ui.pushbuffer()
6302 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6315 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
6303 commoninc=common)
6316 commoninc=common)
6304 repo.ui.popbuffer()
6317 repo.ui.popbuffer()
6305 return dest, dbranch, dother, outgoing
6318 return dest, dbranch, dother, outgoing
6306
6319
6307 if needsoutgoing:
6320 if needsoutgoing:
6308 dest, dbranch, dother, outgoing = getoutgoing()
6321 dest, dbranch, dother, outgoing = getoutgoing()
6309 else:
6322 else:
6310 dest = dbranch = dother = outgoing = None
6323 dest = dbranch = dother = outgoing = None
6311
6324
6312 if opts.get('remote'):
6325 if opts.get('remote'):
6313 t = []
6326 t = []
6314 if incoming:
6327 if incoming:
6315 t.append(_('1 or more incoming'))
6328 t.append(_('1 or more incoming'))
6316 o = outgoing.missing
6329 o = outgoing.missing
6317 if o:
6330 if o:
6318 t.append(_('%d outgoing') % len(o))
6331 t.append(_('%d outgoing') % len(o))
6319 other = dother or sother
6332 other = dother or sother
6320 if 'bookmarks' in other.listkeys('namespaces'):
6333 if 'bookmarks' in other.listkeys('namespaces'):
6321 counts = bookmarks.summary(repo, other)
6334 counts = bookmarks.summary(repo, other)
6322 if counts[0] > 0:
6335 if counts[0] > 0:
6323 t.append(_('%d incoming bookmarks') % counts[0])
6336 t.append(_('%d incoming bookmarks') % counts[0])
6324 if counts[1] > 0:
6337 if counts[1] > 0:
6325 t.append(_('%d outgoing bookmarks') % counts[1])
6338 t.append(_('%d outgoing bookmarks') % counts[1])
6326
6339
6327 if t:
6340 if t:
6328 # i18n: column positioning for "hg summary"
6341 # i18n: column positioning for "hg summary"
6329 ui.write(_('remote: %s\n') % (', '.join(t)))
6342 ui.write(_('remote: %s\n') % (', '.join(t)))
6330 else:
6343 else:
6331 # i18n: column positioning for "hg summary"
6344 # i18n: column positioning for "hg summary"
6332 ui.status(_('remote: (synced)\n'))
6345 ui.status(_('remote: (synced)\n'))
6333
6346
6334 cmdutil.summaryremotehooks(ui, repo, opts,
6347 cmdutil.summaryremotehooks(ui, repo, opts,
6335 ((source, sbranch, sother, commoninc),
6348 ((source, sbranch, sother, commoninc),
6336 (dest, dbranch, dother, outgoing)))
6349 (dest, dbranch, dother, outgoing)))
6337
6350
6338 @command('tag',
6351 @command('tag',
6339 [('f', 'force', None, _('force tag')),
6352 [('f', 'force', None, _('force tag')),
6340 ('l', 'local', None, _('make the tag local')),
6353 ('l', 'local', None, _('make the tag local')),
6341 ('r', 'rev', '', _('revision to tag'), _('REV')),
6354 ('r', 'rev', '', _('revision to tag'), _('REV')),
6342 ('', 'remove', None, _('remove a tag')),
6355 ('', 'remove', None, _('remove a tag')),
6343 # -l/--local is already there, commitopts cannot be used
6356 # -l/--local is already there, commitopts cannot be used
6344 ('e', 'edit', None, _('invoke editor on commit messages')),
6357 ('e', 'edit', None, _('invoke editor on commit messages')),
6345 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6358 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6346 ] + commitopts2,
6359 ] + commitopts2,
6347 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6360 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6348 def tag(ui, repo, name1, *names, **opts):
6361 def tag(ui, repo, name1, *names, **opts):
6349 """add one or more tags for the current or given revision
6362 """add one or more tags for the current or given revision
6350
6363
6351 Name a particular revision using <name>.
6364 Name a particular revision using <name>.
6352
6365
6353 Tags are used to name particular revisions of the repository and are
6366 Tags are used to name particular revisions of the repository and are
6354 very useful to compare different revisions, to go back to significant
6367 very useful to compare different revisions, to go back to significant
6355 earlier versions or to mark branch points as releases, etc. Changing
6368 earlier versions or to mark branch points as releases, etc. Changing
6356 an existing tag is normally disallowed; use -f/--force to override.
6369 an existing tag is normally disallowed; use -f/--force to override.
6357
6370
6358 If no revision is given, the parent of the working directory is
6371 If no revision is given, the parent of the working directory is
6359 used.
6372 used.
6360
6373
6361 To facilitate version control, distribution, and merging of tags,
6374 To facilitate version control, distribution, and merging of tags,
6362 they are stored as a file named ".hgtags" which is managed similarly
6375 they are stored as a file named ".hgtags" which is managed similarly
6363 to other project files and can be hand-edited if necessary. This
6376 to other project files and can be hand-edited if necessary. This
6364 also means that tagging creates a new commit. The file
6377 also means that tagging creates a new commit. The file
6365 ".hg/localtags" is used for local tags (not shared among
6378 ".hg/localtags" is used for local tags (not shared among
6366 repositories).
6379 repositories).
6367
6380
6368 Tag commits are usually made at the head of a branch. If the parent
6381 Tag commits are usually made at the head of a branch. If the parent
6369 of the working directory is not a branch head, :hg:`tag` aborts; use
6382 of the working directory is not a branch head, :hg:`tag` aborts; use
6370 -f/--force to force the tag commit to be based on a non-head
6383 -f/--force to force the tag commit to be based on a non-head
6371 changeset.
6384 changeset.
6372
6385
6373 See :hg:`help dates` for a list of formats valid for -d/--date.
6386 See :hg:`help dates` for a list of formats valid for -d/--date.
6374
6387
6375 Since tag names have priority over branch names during revision
6388 Since tag names have priority over branch names during revision
6376 lookup, using an existing branch name as a tag name is discouraged.
6389 lookup, using an existing branch name as a tag name is discouraged.
6377
6390
6378 Returns 0 on success.
6391 Returns 0 on success.
6379 """
6392 """
6380 wlock = lock = None
6393 wlock = lock = None
6381 try:
6394 try:
6382 wlock = repo.wlock()
6395 wlock = repo.wlock()
6383 lock = repo.lock()
6396 lock = repo.lock()
6384 rev_ = "."
6397 rev_ = "."
6385 names = [t.strip() for t in (name1,) + names]
6398 names = [t.strip() for t in (name1,) + names]
6386 if len(names) != len(set(names)):
6399 if len(names) != len(set(names)):
6387 raise error.Abort(_('tag names must be unique'))
6400 raise error.Abort(_('tag names must be unique'))
6388 for n in names:
6401 for n in names:
6389 scmutil.checknewlabel(repo, n, 'tag')
6402 scmutil.checknewlabel(repo, n, 'tag')
6390 if not n:
6403 if not n:
6391 raise error.Abort(_('tag names cannot consist entirely of '
6404 raise error.Abort(_('tag names cannot consist entirely of '
6392 'whitespace'))
6405 'whitespace'))
6393 if opts.get('rev') and opts.get('remove'):
6406 if opts.get('rev') and opts.get('remove'):
6394 raise error.Abort(_("--rev and --remove are incompatible"))
6407 raise error.Abort(_("--rev and --remove are incompatible"))
6395 if opts.get('rev'):
6408 if opts.get('rev'):
6396 rev_ = opts['rev']
6409 rev_ = opts['rev']
6397 message = opts.get('message')
6410 message = opts.get('message')
6398 if opts.get('remove'):
6411 if opts.get('remove'):
6399 if opts.get('local'):
6412 if opts.get('local'):
6400 expectedtype = 'local'
6413 expectedtype = 'local'
6401 else:
6414 else:
6402 expectedtype = 'global'
6415 expectedtype = 'global'
6403
6416
6404 for n in names:
6417 for n in names:
6405 if not repo.tagtype(n):
6418 if not repo.tagtype(n):
6406 raise error.Abort(_("tag '%s' does not exist") % n)
6419 raise error.Abort(_("tag '%s' does not exist") % n)
6407 if repo.tagtype(n) != expectedtype:
6420 if repo.tagtype(n) != expectedtype:
6408 if expectedtype == 'global':
6421 if expectedtype == 'global':
6409 raise error.Abort(_("tag '%s' is not a global tag") % n)
6422 raise error.Abort(_("tag '%s' is not a global tag") % n)
6410 else:
6423 else:
6411 raise error.Abort(_("tag '%s' is not a local tag") % n)
6424 raise error.Abort(_("tag '%s' is not a local tag") % n)
6412 rev_ = 'null'
6425 rev_ = 'null'
6413 if not message:
6426 if not message:
6414 # we don't translate commit messages
6427 # we don't translate commit messages
6415 message = 'Removed tag %s' % ', '.join(names)
6428 message = 'Removed tag %s' % ', '.join(names)
6416 elif not opts.get('force'):
6429 elif not opts.get('force'):
6417 for n in names:
6430 for n in names:
6418 if n in repo.tags():
6431 if n in repo.tags():
6419 raise error.Abort(_("tag '%s' already exists "
6432 raise error.Abort(_("tag '%s' already exists "
6420 "(use -f to force)") % n)
6433 "(use -f to force)") % n)
6421 if not opts.get('local'):
6434 if not opts.get('local'):
6422 p1, p2 = repo.dirstate.parents()
6435 p1, p2 = repo.dirstate.parents()
6423 if p2 != nullid:
6436 if p2 != nullid:
6424 raise error.Abort(_('uncommitted merge'))
6437 raise error.Abort(_('uncommitted merge'))
6425 bheads = repo.branchheads()
6438 bheads = repo.branchheads()
6426 if not opts.get('force') and bheads and p1 not in bheads:
6439 if not opts.get('force') and bheads and p1 not in bheads:
6427 raise error.Abort(_('not at a branch head (use -f to force)'))
6440 raise error.Abort(_('not at a branch head (use -f to force)'))
6428 r = scmutil.revsingle(repo, rev_).node()
6441 r = scmutil.revsingle(repo, rev_).node()
6429
6442
6430 if not message:
6443 if not message:
6431 # we don't translate commit messages
6444 # we don't translate commit messages
6432 message = ('Added tag %s for changeset %s' %
6445 message = ('Added tag %s for changeset %s' %
6433 (', '.join(names), short(r)))
6446 (', '.join(names), short(r)))
6434
6447
6435 date = opts.get('date')
6448 date = opts.get('date')
6436 if date:
6449 if date:
6437 date = util.parsedate(date)
6450 date = util.parsedate(date)
6438
6451
6439 if opts.get('remove'):
6452 if opts.get('remove'):
6440 editform = 'tag.remove'
6453 editform = 'tag.remove'
6441 else:
6454 else:
6442 editform = 'tag.add'
6455 editform = 'tag.add'
6443 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6456 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6444
6457
6445 # don't allow tagging the null rev
6458 # don't allow tagging the null rev
6446 if (not opts.get('remove') and
6459 if (not opts.get('remove') and
6447 scmutil.revsingle(repo, rev_).rev() == nullrev):
6460 scmutil.revsingle(repo, rev_).rev() == nullrev):
6448 raise error.Abort(_("cannot tag null revision"))
6461 raise error.Abort(_("cannot tag null revision"))
6449
6462
6450 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6463 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6451 editor=editor)
6464 editor=editor)
6452 finally:
6465 finally:
6453 release(lock, wlock)
6466 release(lock, wlock)
6454
6467
6455 @command('tags', formatteropts, '')
6468 @command('tags', formatteropts, '')
6456 def tags(ui, repo, **opts):
6469 def tags(ui, repo, **opts):
6457 """list repository tags
6470 """list repository tags
6458
6471
6459 This lists both regular and local tags. When the -v/--verbose
6472 This lists both regular and local tags. When the -v/--verbose
6460 switch is used, a third column "local" is printed for local tags.
6473 switch is used, a third column "local" is printed for local tags.
6461
6474
6462 Returns 0 on success.
6475 Returns 0 on success.
6463 """
6476 """
6464
6477
6465 fm = ui.formatter('tags', opts)
6478 fm = ui.formatter('tags', opts)
6466 hexfunc = fm.hexfunc
6479 hexfunc = fm.hexfunc
6467 tagtype = ""
6480 tagtype = ""
6468
6481
6469 for t, n in reversed(repo.tagslist()):
6482 for t, n in reversed(repo.tagslist()):
6470 hn = hexfunc(n)
6483 hn = hexfunc(n)
6471 label = 'tags.normal'
6484 label = 'tags.normal'
6472 tagtype = ''
6485 tagtype = ''
6473 if repo.tagtype(t) == 'local':
6486 if repo.tagtype(t) == 'local':
6474 label = 'tags.local'
6487 label = 'tags.local'
6475 tagtype = 'local'
6488 tagtype = 'local'
6476
6489
6477 fm.startitem()
6490 fm.startitem()
6478 fm.write('tag', '%s', t, label=label)
6491 fm.write('tag', '%s', t, label=label)
6479 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6492 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6480 fm.condwrite(not ui.quiet, 'rev node', fmt,
6493 fm.condwrite(not ui.quiet, 'rev node', fmt,
6481 repo.changelog.rev(n), hn, label=label)
6494 repo.changelog.rev(n), hn, label=label)
6482 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6495 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6483 tagtype, label=label)
6496 tagtype, label=label)
6484 fm.plain('\n')
6497 fm.plain('\n')
6485 fm.end()
6498 fm.end()
6486
6499
6487 @command('tip',
6500 @command('tip',
6488 [('p', 'patch', None, _('show patch')),
6501 [('p', 'patch', None, _('show patch')),
6489 ('g', 'git', None, _('use git extended diff format')),
6502 ('g', 'git', None, _('use git extended diff format')),
6490 ] + templateopts,
6503 ] + templateopts,
6491 _('[-p] [-g]'))
6504 _('[-p] [-g]'))
6492 def tip(ui, repo, **opts):
6505 def tip(ui, repo, **opts):
6493 """show the tip revision (DEPRECATED)
6506 """show the tip revision (DEPRECATED)
6494
6507
6495 The tip revision (usually just called the tip) is the changeset
6508 The tip revision (usually just called the tip) is the changeset
6496 most recently added to the repository (and therefore the most
6509 most recently added to the repository (and therefore the most
6497 recently changed head).
6510 recently changed head).
6498
6511
6499 If you have just made a commit, that commit will be the tip. If
6512 If you have just made a commit, that commit will be the tip. If
6500 you have just pulled changes from another repository, the tip of
6513 you have just pulled changes from another repository, the tip of
6501 that repository becomes the current tip. The "tip" tag is special
6514 that repository becomes the current tip. The "tip" tag is special
6502 and cannot be renamed or assigned to a different changeset.
6515 and cannot be renamed or assigned to a different changeset.
6503
6516
6504 This command is deprecated, please use :hg:`heads` instead.
6517 This command is deprecated, please use :hg:`heads` instead.
6505
6518
6506 Returns 0 on success.
6519 Returns 0 on success.
6507 """
6520 """
6508 displayer = cmdutil.show_changeset(ui, repo, opts)
6521 displayer = cmdutil.show_changeset(ui, repo, opts)
6509 displayer.show(repo['tip'])
6522 displayer.show(repo['tip'])
6510 displayer.close()
6523 displayer.close()
6511
6524
6512 @command('unbundle',
6525 @command('unbundle',
6513 [('u', 'update', None,
6526 [('u', 'update', None,
6514 _('update to new branch head if changesets were unbundled'))],
6527 _('update to new branch head if changesets were unbundled'))],
6515 _('[-u] FILE...'))
6528 _('[-u] FILE...'))
6516 def unbundle(ui, repo, fname1, *fnames, **opts):
6529 def unbundle(ui, repo, fname1, *fnames, **opts):
6517 """apply one or more changegroup files
6530 """apply one or more changegroup files
6518
6531
6519 Apply one or more compressed changegroup files generated by the
6532 Apply one or more compressed changegroup files generated by the
6520 bundle command.
6533 bundle command.
6521
6534
6522 Returns 0 on success, 1 if an update has unresolved files.
6535 Returns 0 on success, 1 if an update has unresolved files.
6523 """
6536 """
6524 fnames = (fname1,) + fnames
6537 fnames = (fname1,) + fnames
6525
6538
6526 lock = repo.lock()
6539 lock = repo.lock()
6527 try:
6540 try:
6528 for fname in fnames:
6541 for fname in fnames:
6529 f = hg.openpath(ui, fname)
6542 f = hg.openpath(ui, fname)
6530 gen = exchange.readbundle(ui, f, fname)
6543 gen = exchange.readbundle(ui, f, fname)
6531 if isinstance(gen, bundle2.unbundle20):
6544 if isinstance(gen, bundle2.unbundle20):
6532 tr = repo.transaction('unbundle')
6545 tr = repo.transaction('unbundle')
6533 try:
6546 try:
6534 op = bundle2.processbundle(repo, gen, lambda: tr)
6547 op = bundle2.processbundle(repo, gen, lambda: tr)
6535 tr.close()
6548 tr.close()
6536 except error.BundleUnknownFeatureError as exc:
6549 except error.BundleUnknownFeatureError as exc:
6537 raise error.Abort(_('%s: unknown bundle feature, %s')
6550 raise error.Abort(_('%s: unknown bundle feature, %s')
6538 % (fname, exc),
6551 % (fname, exc),
6539 hint=_("see https://mercurial-scm.org/"
6552 hint=_("see https://mercurial-scm.org/"
6540 "wiki/BundleFeature for more "
6553 "wiki/BundleFeature for more "
6541 "information"))
6554 "information"))
6542 finally:
6555 finally:
6543 if tr:
6556 if tr:
6544 tr.release()
6557 tr.release()
6545 changes = [r.get('return', 0)
6558 changes = [r.get('return', 0)
6546 for r in op.records['changegroup']]
6559 for r in op.records['changegroup']]
6547 modheads = changegroup.combineresults(changes)
6560 modheads = changegroup.combineresults(changes)
6548 elif isinstance(gen, streamclone.streamcloneapplier):
6561 elif isinstance(gen, streamclone.streamcloneapplier):
6549 raise error.Abort(
6562 raise error.Abort(
6550 _('packed bundles cannot be applied with '
6563 _('packed bundles cannot be applied with '
6551 '"hg unbundle"'),
6564 '"hg unbundle"'),
6552 hint=_('use "hg debugapplystreamclonebundle"'))
6565 hint=_('use "hg debugapplystreamclonebundle"'))
6553 else:
6566 else:
6554 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6567 modheads = gen.apply(repo, 'unbundle', 'bundle:' + fname)
6555 finally:
6568 finally:
6556 lock.release()
6569 lock.release()
6557
6570
6558 return postincoming(ui, repo, modheads, opts.get('update'), None)
6571 return postincoming(ui, repo, modheads, opts.get('update'), None)
6559
6572
6560 @command('^update|up|checkout|co',
6573 @command('^update|up|checkout|co',
6561 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6574 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6562 ('c', 'check', None,
6575 ('c', 'check', None,
6563 _('update across branches if no uncommitted changes')),
6576 _('update across branches if no uncommitted changes')),
6564 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6577 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6565 ('r', 'rev', '', _('revision'), _('REV'))
6578 ('r', 'rev', '', _('revision'), _('REV'))
6566 ] + mergetoolopts,
6579 ] + mergetoolopts,
6567 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6580 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6568 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6581 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6569 tool=None):
6582 tool=None):
6570 """update working directory (or switch revisions)
6583 """update working directory (or switch revisions)
6571
6584
6572 Update the repository's working directory to the specified
6585 Update the repository's working directory to the specified
6573 changeset. If no changeset is specified, update to the tip of the
6586 changeset. If no changeset is specified, update to the tip of the
6574 current named branch and move the active bookmark (see :hg:`help
6587 current named branch and move the active bookmark (see :hg:`help
6575 bookmarks`).
6588 bookmarks`).
6576
6589
6577 Update sets the working directory's parent revision to the specified
6590 Update sets the working directory's parent revision to the specified
6578 changeset (see :hg:`help parents`).
6591 changeset (see :hg:`help parents`).
6579
6592
6580 If the changeset is not a descendant or ancestor of the working
6593 If the changeset is not a descendant or ancestor of the working
6581 directory's parent, the update is aborted. With the -c/--check
6594 directory's parent, the update is aborted. With the -c/--check
6582 option, the working directory is checked for uncommitted changes; if
6595 option, the working directory is checked for uncommitted changes; if
6583 none are found, the working directory is updated to the specified
6596 none are found, the working directory is updated to the specified
6584 changeset.
6597 changeset.
6585
6598
6586 .. container:: verbose
6599 .. container:: verbose
6587
6600
6588 The following rules apply when the working directory contains
6601 The following rules apply when the working directory contains
6589 uncommitted changes:
6602 uncommitted changes:
6590
6603
6591 1. If neither -c/--check nor -C/--clean is specified, and if
6604 1. If neither -c/--check nor -C/--clean is specified, and if
6592 the requested changeset is an ancestor or descendant of
6605 the requested changeset is an ancestor or descendant of
6593 the working directory's parent, the uncommitted changes
6606 the working directory's parent, the uncommitted changes
6594 are merged into the requested changeset and the merged
6607 are merged into the requested changeset and the merged
6595 result is left uncommitted. If the requested changeset is
6608 result is left uncommitted. If the requested changeset is
6596 not an ancestor or descendant (that is, it is on another
6609 not an ancestor or descendant (that is, it is on another
6597 branch), the update is aborted and the uncommitted changes
6610 branch), the update is aborted and the uncommitted changes
6598 are preserved.
6611 are preserved.
6599
6612
6600 2. With the -c/--check option, the update is aborted and the
6613 2. With the -c/--check option, the update is aborted and the
6601 uncommitted changes are preserved.
6614 uncommitted changes are preserved.
6602
6615
6603 3. With the -C/--clean option, uncommitted changes are discarded and
6616 3. With the -C/--clean option, uncommitted changes are discarded and
6604 the working directory is updated to the requested changeset.
6617 the working directory is updated to the requested changeset.
6605
6618
6606 To cancel an uncommitted merge (and lose your changes), use
6619 To cancel an uncommitted merge (and lose your changes), use
6607 :hg:`update --clean .`.
6620 :hg:`update --clean .`.
6608
6621
6609 Use null as the changeset to remove the working directory (like
6622 Use null as the changeset to remove the working directory (like
6610 :hg:`clone -U`).
6623 :hg:`clone -U`).
6611
6624
6612 If you want to revert just one file to an older revision, use
6625 If you want to revert just one file to an older revision, use
6613 :hg:`revert [-r REV] NAME`.
6626 :hg:`revert [-r REV] NAME`.
6614
6627
6615 See :hg:`help dates` for a list of formats valid for -d/--date.
6628 See :hg:`help dates` for a list of formats valid for -d/--date.
6616
6629
6617 Returns 0 on success, 1 if there are unresolved files.
6630 Returns 0 on success, 1 if there are unresolved files.
6618 """
6631 """
6619 movemarkfrom = None
6632 movemarkfrom = None
6620 if rev and node:
6633 if rev and node:
6621 raise error.Abort(_("please specify just one revision"))
6634 raise error.Abort(_("please specify just one revision"))
6622
6635
6623 if rev is None or rev == '':
6636 if rev is None or rev == '':
6624 rev = node
6637 rev = node
6625
6638
6626 wlock = repo.wlock()
6639 wlock = repo.wlock()
6627 try:
6640 try:
6628 cmdutil.clearunfinished(repo)
6641 cmdutil.clearunfinished(repo)
6629
6642
6630 if date:
6643 if date:
6631 if rev is not None:
6644 if rev is not None:
6632 raise error.Abort(_("you can't specify a revision and a date"))
6645 raise error.Abort(_("you can't specify a revision and a date"))
6633 rev = cmdutil.finddate(ui, repo, date)
6646 rev = cmdutil.finddate(ui, repo, date)
6634
6647
6635 # if we defined a bookmark, we have to remember the original name
6648 # if we defined a bookmark, we have to remember the original name
6636 brev = rev
6649 brev = rev
6637 rev = scmutil.revsingle(repo, rev, rev).rev()
6650 rev = scmutil.revsingle(repo, rev, rev).rev()
6638
6651
6639 if check and clean:
6652 if check and clean:
6640 raise error.Abort(_("cannot specify both -c/--check and -C/--clean")
6653 raise error.Abort(_("cannot specify both -c/--check and -C/--clean")
6641 )
6654 )
6642
6655
6643 if check:
6656 if check:
6644 cmdutil.bailifchanged(repo, merge=False)
6657 cmdutil.bailifchanged(repo, merge=False)
6645 if rev is None:
6658 if rev is None:
6646 updata = destutil.destupdate(repo, clean=clean, check=check)
6659 updata = destutil.destupdate(repo, clean=clean, check=check)
6647 rev, movemarkfrom, brev = updata
6660 rev, movemarkfrom, brev = updata
6648
6661
6649 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6662 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6650
6663
6651 if clean:
6664 if clean:
6652 ret = hg.clean(repo, rev)
6665 ret = hg.clean(repo, rev)
6653 else:
6666 else:
6654 ret = hg.update(repo, rev)
6667 ret = hg.update(repo, rev)
6655
6668
6656 if not ret and movemarkfrom:
6669 if not ret and movemarkfrom:
6657 if movemarkfrom == repo['.'].node():
6670 if movemarkfrom == repo['.'].node():
6658 pass # no-op update
6671 pass # no-op update
6659 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6672 elif bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6660 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6673 ui.status(_("updating bookmark %s\n") % repo._activebookmark)
6661 else:
6674 else:
6662 # this can happen with a non-linear update
6675 # this can happen with a non-linear update
6663 ui.status(_("(leaving bookmark %s)\n") %
6676 ui.status(_("(leaving bookmark %s)\n") %
6664 repo._activebookmark)
6677 repo._activebookmark)
6665 bookmarks.deactivate(repo)
6678 bookmarks.deactivate(repo)
6666 elif brev in repo._bookmarks:
6679 elif brev in repo._bookmarks:
6667 bookmarks.activate(repo, brev)
6680 bookmarks.activate(repo, brev)
6668 ui.status(_("(activating bookmark %s)\n") % brev)
6681 ui.status(_("(activating bookmark %s)\n") % brev)
6669 elif brev:
6682 elif brev:
6670 if repo._activebookmark:
6683 if repo._activebookmark:
6671 ui.status(_("(leaving bookmark %s)\n") %
6684 ui.status(_("(leaving bookmark %s)\n") %
6672 repo._activebookmark)
6685 repo._activebookmark)
6673 bookmarks.deactivate(repo)
6686 bookmarks.deactivate(repo)
6674 finally:
6687 finally:
6675 wlock.release()
6688 wlock.release()
6676
6689
6677 return ret
6690 return ret
6678
6691
6679 @command('verify', [])
6692 @command('verify', [])
6680 def verify(ui, repo):
6693 def verify(ui, repo):
6681 """verify the integrity of the repository
6694 """verify the integrity of the repository
6682
6695
6683 Verify the integrity of the current repository.
6696 Verify the integrity of the current repository.
6684
6697
6685 This will perform an extensive check of the repository's
6698 This will perform an extensive check of the repository's
6686 integrity, validating the hashes and checksums of each entry in
6699 integrity, validating the hashes and checksums of each entry in
6687 the changelog, manifest, and tracked files, as well as the
6700 the changelog, manifest, and tracked files, as well as the
6688 integrity of their crosslinks and indices.
6701 integrity of their crosslinks and indices.
6689
6702
6690 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6703 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
6691 for more information about recovery from corruption of the
6704 for more information about recovery from corruption of the
6692 repository.
6705 repository.
6693
6706
6694 Returns 0 on success, 1 if errors are encountered.
6707 Returns 0 on success, 1 if errors are encountered.
6695 """
6708 """
6696 return hg.verify(repo)
6709 return hg.verify(repo)
6697
6710
6698 @command('version', [], norepo=True)
6711 @command('version', [], norepo=True)
6699 def version_(ui):
6712 def version_(ui):
6700 """output version and copyright information"""
6713 """output version and copyright information"""
6701 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6714 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6702 % util.version())
6715 % util.version())
6703 ui.status(_(
6716 ui.status(_(
6704 "(see https://mercurial-scm.org for more information)\n"
6717 "(see https://mercurial-scm.org for more information)\n"
6705 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6718 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6706 "This is free software; see the source for copying conditions. "
6719 "This is free software; see the source for copying conditions. "
6707 "There is NO\nwarranty; "
6720 "There is NO\nwarranty; "
6708 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6721 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6709 ))
6722 ))
6710
6723
6711 ui.note(_("\nEnabled extensions:\n\n"))
6724 ui.note(_("\nEnabled extensions:\n\n"))
6712 if ui.verbose:
6725 if ui.verbose:
6713 # format names and versions into columns
6726 # format names and versions into columns
6714 names = []
6727 names = []
6715 vers = []
6728 vers = []
6716 for name, module in extensions.extensions():
6729 for name, module in extensions.extensions():
6717 names.append(name)
6730 names.append(name)
6718 vers.append(extensions.moduleversion(module))
6731 vers.append(extensions.moduleversion(module))
6719 if names:
6732 if names:
6720 maxnamelen = max(len(n) for n in names)
6733 maxnamelen = max(len(n) for n in names)
6721 for i, name in enumerate(names):
6734 for i, name in enumerate(names):
6722 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
6735 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
@@ -1,175 +1,227 b''
1 test that a commit clears the merge state.
1 test that a commit clears the merge state.
2
2
3 $ hg init repo
3 $ hg init repo
4 $ cd repo
4 $ cd repo
5
5
6 $ echo foo > file1
6 $ echo foo > file1
7 $ echo foo > file2
7 $ echo foo > file2
8 $ hg commit -Am 'add files'
8 $ hg commit -Am 'add files'
9 adding file1
9 adding file1
10 adding file2
10 adding file2
11
11
12 $ echo bar >> file1
12 $ echo bar >> file1
13 $ echo bar >> file2
13 $ echo bar >> file2
14 $ hg commit -Am 'append bar to files'
14 $ hg commit -Am 'append bar to files'
15
15
16 create a second head with conflicting edits
16 create a second head with conflicting edits
17
17
18 $ hg up -C 0
18 $ hg up -C 0
19 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
19 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
20 $ echo baz >> file1
20 $ echo baz >> file1
21 $ echo baz >> file2
21 $ echo baz >> file2
22 $ hg commit -Am 'append baz to files'
22 $ hg commit -Am 'append baz to files'
23 created new head
23 created new head
24
24
25 create a third head with no conflicting edits
25 create a third head with no conflicting edits
26 $ hg up -qC 0
26 $ hg up -qC 0
27 $ echo foo > file3
27 $ echo foo > file3
28 $ hg commit -Am 'add non-conflicting file'
28 $ hg commit -Am 'add non-conflicting file'
29 adding file3
29 adding file3
30 created new head
30 created new head
31
31
32 failing merge
32 failing merge
33
33
34 $ hg up -qC 2
34 $ hg up -qC 2
35 $ hg merge --tool=internal:fail 1
35 $ hg merge --tool=internal:fail 1
36 0 files updated, 0 files merged, 0 files removed, 2 files unresolved
36 0 files updated, 0 files merged, 0 files removed, 2 files unresolved
37 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
37 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
38 [1]
38 [1]
39
39
40 resolve -l should contain unresolved entries
40 resolve -l should contain unresolved entries
41
41
42 $ hg resolve -l
42 $ hg resolve -l
43 U file1
43 U file1
44 U file2
44 U file2
45
45
46 $ hg resolve -l --no-status
46 $ hg resolve -l --no-status
47 file1
47 file1
48 file2
48 file2
49
49
50 resolving an unknown path should emit a warning, but not for -l
50 resolving an unknown path should emit a warning, but not for -l
51
51
52 $ hg resolve -m does-not-exist
52 $ hg resolve -m does-not-exist
53 arguments do not match paths that need resolving
53 arguments do not match paths that need resolving
54 $ hg resolve -l does-not-exist
54 $ hg resolve -l does-not-exist
55
55
56 don't allow marking or unmarking driver-resolved files
57
58 $ cat > $TESTTMP/markdriver.py << EOF
59 > '''mark and unmark files as driver-resolved'''
60 > from mercurial import cmdutil, merge, scmutil
61 > cmdtable = {}
62 > command = cmdutil.command(cmdtable)
63 > @command('markdriver',
64 > [('u', 'unmark', None, '')],
65 > 'FILE...')
66 > def markdriver(ui, repo, *pats, **opts):
67 > wlock = repo.wlock()
68 > try:
69 > ms = merge.mergestate(repo)
70 > m = scmutil.match(repo[None], pats, opts)
71 > for f in ms:
72 > if not m(f):
73 > continue
74 > if not opts['unmark']:
75 > ms.mark(f, 'd')
76 > else:
77 > ms.mark(f, 'u')
78 > ms.commit()
79 > finally:
80 > wlock.release()
81 > EOF
82 $ hg --config extensions.markdriver=$TESTTMP/markdriver.py markdriver file1
83 $ hg resolve --list
84 D file1
85 U file2
86 $ hg resolve --mark file1
87 not marking file1 as it is driver-resolved
88 this should not print out file1
89 $ hg resolve --mark --all
90 (no more unresolved files -- run "hg resolve --all" to conclude)
91 $ hg resolve --mark 'glob:file*'
92 (no more unresolved files -- run "hg resolve --all" to conclude)
93 $ hg resolve --list
94 D file1
95 R file2
96 $ hg resolve --unmark file1
97 not unmarking file1 as it is driver-resolved
98 (no more unresolved files -- run "hg resolve --all" to conclude)
99 $ hg resolve --unmark --all
100 $ hg resolve --list
101 D file1
102 U file2
103 $ hg --config extensions.markdriver=$TESTTMP/markdriver.py markdriver --unmark file1
104 $ hg resolve --list
105 U file1
106 U file2
107
56 resolve the failure
108 resolve the failure
57
109
58 $ echo resolved > file1
110 $ echo resolved > file1
59 $ hg resolve -m file1
111 $ hg resolve -m file1
60
112
61 resolve -l should show resolved file as resolved
113 resolve -l should show resolved file as resolved
62
114
63 $ hg resolve -l
115 $ hg resolve -l
64 R file1
116 R file1
65 U file2
117 U file2
66
118
67 $ hg resolve -l -Tjson
119 $ hg resolve -l -Tjson
68 [
120 [
69 {
121 {
70 "path": "file1",
122 "path": "file1",
71 "status": "R"
123 "status": "R"
72 },
124 },
73 {
125 {
74 "path": "file2",
126 "path": "file2",
75 "status": "U"
127 "status": "U"
76 }
128 }
77 ]
129 ]
78
130
79 resolve -m without paths should mark all resolved
131 resolve -m without paths should mark all resolved
80
132
81 $ hg resolve -m
133 $ hg resolve -m
82 (no more unresolved files)
134 (no more unresolved files)
83 $ hg commit -m 'resolved'
135 $ hg commit -m 'resolved'
84
136
85 resolve -l should be empty after commit
137 resolve -l should be empty after commit
86
138
87 $ hg resolve -l
139 $ hg resolve -l
88
140
89 $ hg resolve -l -Tjson
141 $ hg resolve -l -Tjson
90 [
142 [
91 ]
143 ]
92
144
93 resolve --all should abort when no merge in progress
145 resolve --all should abort when no merge in progress
94
146
95 $ hg resolve --all
147 $ hg resolve --all
96 abort: resolve command not applicable when not merging
148 abort: resolve command not applicable when not merging
97 [255]
149 [255]
98
150
99 resolve -m should abort when no merge in progress
151 resolve -m should abort when no merge in progress
100
152
101 $ hg resolve -m
153 $ hg resolve -m
102 abort: resolve command not applicable when not merging
154 abort: resolve command not applicable when not merging
103 [255]
155 [255]
104
156
105 set up conflict-free merge
157 set up conflict-free merge
106
158
107 $ hg up -qC 3
159 $ hg up -qC 3
108 $ hg merge 1
160 $ hg merge 1
109 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
161 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
110 (branch merge, don't forget to commit)
162 (branch merge, don't forget to commit)
111
163
112 resolve --all should do nothing in merge without conflicts
164 resolve --all should do nothing in merge without conflicts
113 $ hg resolve --all
165 $ hg resolve --all
114 (no more unresolved files)
166 (no more unresolved files)
115
167
116 resolve -m should do nothing in merge without conflicts
168 resolve -m should do nothing in merge without conflicts
117
169
118 $ hg resolve -m
170 $ hg resolve -m
119 (no more unresolved files)
171 (no more unresolved files)
120
172
121 get back to conflicting state
173 get back to conflicting state
122
174
123 $ hg up -qC 2
175 $ hg up -qC 2
124 $ hg merge --tool=internal:fail 1
176 $ hg merge --tool=internal:fail 1
125 0 files updated, 0 files merged, 0 files removed, 2 files unresolved
177 0 files updated, 0 files merged, 0 files removed, 2 files unresolved
126 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
178 use 'hg resolve' to retry unresolved file merges or 'hg update -C .' to abandon
127 [1]
179 [1]
128
180
129 resolve without arguments should suggest --all
181 resolve without arguments should suggest --all
130 $ hg resolve
182 $ hg resolve
131 abort: no files or directories specified
183 abort: no files or directories specified
132 (use --all to re-merge all unresolved files)
184 (use --all to re-merge all unresolved files)
133 [255]
185 [255]
134
186
135 resolve --all should re-merge all unresolved files
187 resolve --all should re-merge all unresolved files
136 $ hg resolve --all
188 $ hg resolve --all
137 merging file1
189 merging file1
138 merging file2
190 merging file2
139 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
191 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
140 warning: conflicts while merging file2! (edit, then use 'hg resolve --mark')
192 warning: conflicts while merging file2! (edit, then use 'hg resolve --mark')
141 [1]
193 [1]
142 $ cat file1.orig
194 $ cat file1.orig
143 foo
195 foo
144 baz
196 baz
145 $ cat file2.orig
197 $ cat file2.orig
146 foo
198 foo
147 baz
199 baz
148 $ grep '<<<' file1 > /dev/null
200 $ grep '<<<' file1 > /dev/null
149 $ grep '<<<' file2 > /dev/null
201 $ grep '<<<' file2 > /dev/null
150
202
151 resolve <file> should re-merge file
203 resolve <file> should re-merge file
152 $ echo resolved > file1
204 $ echo resolved > file1
153 $ hg resolve -q file1
205 $ hg resolve -q file1
154 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
206 warning: conflicts while merging file1! (edit, then use 'hg resolve --mark')
155 [1]
207 [1]
156 $ grep '<<<' file1 > /dev/null
208 $ grep '<<<' file1 > /dev/null
157
209
158 resolve <file> should do nothing if 'file' was marked resolved
210 resolve <file> should do nothing if 'file' was marked resolved
159 $ echo resolved > file1
211 $ echo resolved > file1
160 $ hg resolve -m file1
212 $ hg resolve -m file1
161 $ hg resolve -q file1
213 $ hg resolve -q file1
162 $ cat file1
214 $ cat file1
163 resolved
215 resolved
164
216
165 test crashed merge with empty mergestate
217 test crashed merge with empty mergestate
166
218
167 $ hg up -qC 1
219 $ hg up -qC 1
168 $ mkdir .hg/merge
220 $ mkdir .hg/merge
169 $ touch .hg/merge/state
221 $ touch .hg/merge/state
170
222
171 resolve -l should be empty
223 resolve -l should be empty
172
224
173 $ hg resolve -l
225 $ hg resolve -l
174
226
175 $ cd ..
227 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now