##// END OF EJS Templates
grep: colorize all fields...
Idan Kamara -
r17806:dc7010ed default
parent child Browse files
Show More
@@ -1,503 +1,510 b''
1 # color.py color output for the status and qseries commands
1 # color.py color output for the status and qseries commands
2 #
2 #
3 # Copyright (C) 2007 Kevin Christen <kevin.christen@gmail.com>
3 # Copyright (C) 2007 Kevin Christen <kevin.christen@gmail.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 '''colorize output from some commands
8 '''colorize output from some commands
9
9
10 This extension modifies the status and resolve commands to add color
10 This extension modifies the status and resolve commands to add color
11 to their output to reflect file status, the qseries command to add
11 to their output to reflect file status, the qseries command to add
12 color to reflect patch status (applied, unapplied, missing), and to
12 color to reflect patch status (applied, unapplied, missing), and to
13 diff-related commands to highlight additions, removals, diff headers,
13 diff-related commands to highlight additions, removals, diff headers,
14 and trailing whitespace.
14 and trailing whitespace.
15
15
16 Other effects in addition to color, like bold and underlined text, are
16 Other effects in addition to color, like bold and underlined text, are
17 also available. By default, the terminfo database is used to find the
17 also available. By default, the terminfo database is used to find the
18 terminal codes used to change color and effect. If terminfo is not
18 terminal codes used to change color and effect. If terminfo is not
19 available, then effects are rendered with the ECMA-48 SGR control
19 available, then effects are rendered with the ECMA-48 SGR control
20 function (aka ANSI escape codes).
20 function (aka ANSI escape codes).
21
21
22 Default effects may be overridden from your configuration file::
22 Default effects may be overridden from your configuration file::
23
23
24 [color]
24 [color]
25 status.modified = blue bold underline red_background
25 status.modified = blue bold underline red_background
26 status.added = green bold
26 status.added = green bold
27 status.removed = red bold blue_background
27 status.removed = red bold blue_background
28 status.deleted = cyan bold underline
28 status.deleted = cyan bold underline
29 status.unknown = magenta bold underline
29 status.unknown = magenta bold underline
30 status.ignored = black bold
30 status.ignored = black bold
31
31
32 # 'none' turns off all effects
32 # 'none' turns off all effects
33 status.clean = none
33 status.clean = none
34 status.copied = none
34 status.copied = none
35
35
36 qseries.applied = blue bold underline
36 qseries.applied = blue bold underline
37 qseries.unapplied = black bold
37 qseries.unapplied = black bold
38 qseries.missing = red bold
38 qseries.missing = red bold
39
39
40 diff.diffline = bold
40 diff.diffline = bold
41 diff.extended = cyan bold
41 diff.extended = cyan bold
42 diff.file_a = red bold
42 diff.file_a = red bold
43 diff.file_b = green bold
43 diff.file_b = green bold
44 diff.hunk = magenta
44 diff.hunk = magenta
45 diff.deleted = red
45 diff.deleted = red
46 diff.inserted = green
46 diff.inserted = green
47 diff.changed = white
47 diff.changed = white
48 diff.trailingwhitespace = bold red_background
48 diff.trailingwhitespace = bold red_background
49
49
50 resolve.unresolved = red bold
50 resolve.unresolved = red bold
51 resolve.resolved = green bold
51 resolve.resolved = green bold
52
52
53 bookmarks.current = green
53 bookmarks.current = green
54
54
55 branches.active = none
55 branches.active = none
56 branches.closed = black bold
56 branches.closed = black bold
57 branches.current = green
57 branches.current = green
58 branches.inactive = none
58 branches.inactive = none
59
59
60 tags.normal = green
60 tags.normal = green
61 tags.local = black bold
61 tags.local = black bold
62
62
63 The available effects in terminfo mode are 'blink', 'bold', 'dim',
63 The available effects in terminfo mode are 'blink', 'bold', 'dim',
64 'inverse', 'invisible', 'italic', 'standout', and 'underline'; in
64 'inverse', 'invisible', 'italic', 'standout', and 'underline'; in
65 ECMA-48 mode, the options are 'bold', 'inverse', 'italic', and
65 ECMA-48 mode, the options are 'bold', 'inverse', 'italic', and
66 'underline'. How each is rendered depends on the terminal emulator.
66 'underline'. How each is rendered depends on the terminal emulator.
67 Some may not be available for a given terminal type, and will be
67 Some may not be available for a given terminal type, and will be
68 silently ignored.
68 silently ignored.
69
69
70 Note that on some systems, terminfo mode may cause problems when using
70 Note that on some systems, terminfo mode may cause problems when using
71 color with the pager extension and less -R. less with the -R option
71 color with the pager extension and less -R. less with the -R option
72 will only display ECMA-48 color codes, and terminfo mode may sometimes
72 will only display ECMA-48 color codes, and terminfo mode may sometimes
73 emit codes that less doesn't understand. You can work around this by
73 emit codes that less doesn't understand. You can work around this by
74 either using ansi mode (or auto mode), or by using less -r (which will
74 either using ansi mode (or auto mode), or by using less -r (which will
75 pass through all terminal control codes, not just color control
75 pass through all terminal control codes, not just color control
76 codes).
76 codes).
77
77
78 Because there are only eight standard colors, this module allows you
78 Because there are only eight standard colors, this module allows you
79 to define color names for other color slots which might be available
79 to define color names for other color slots which might be available
80 for your terminal type, assuming terminfo mode. For instance::
80 for your terminal type, assuming terminfo mode. For instance::
81
81
82 color.brightblue = 12
82 color.brightblue = 12
83 color.pink = 207
83 color.pink = 207
84 color.orange = 202
84 color.orange = 202
85
85
86 to set 'brightblue' to color slot 12 (useful for 16 color terminals
86 to set 'brightblue' to color slot 12 (useful for 16 color terminals
87 that have brighter colors defined in the upper eight) and, 'pink' and
87 that have brighter colors defined in the upper eight) and, 'pink' and
88 'orange' to colors in 256-color xterm's default color cube. These
88 'orange' to colors in 256-color xterm's default color cube. These
89 defined colors may then be used as any of the pre-defined eight,
89 defined colors may then be used as any of the pre-defined eight,
90 including appending '_background' to set the background to that color.
90 including appending '_background' to set the background to that color.
91
91
92 By default, the color extension will use ANSI mode (or win32 mode on
92 By default, the color extension will use ANSI mode (or win32 mode on
93 Windows) if it detects a terminal. To override auto mode (to enable
93 Windows) if it detects a terminal. To override auto mode (to enable
94 terminfo mode, for example), set the following configuration option::
94 terminfo mode, for example), set the following configuration option::
95
95
96 [color]
96 [color]
97 mode = terminfo
97 mode = terminfo
98
98
99 Any value other than 'ansi', 'win32', 'terminfo', or 'auto' will
99 Any value other than 'ansi', 'win32', 'terminfo', or 'auto' will
100 disable color.
100 disable color.
101 '''
101 '''
102
102
103 import os
103 import os
104
104
105 from mercurial import commands, dispatch, extensions, ui as uimod, util
105 from mercurial import commands, dispatch, extensions, ui as uimod, util
106 from mercurial.i18n import _
106 from mercurial.i18n import _
107
107
108 testedwith = 'internal'
108 testedwith = 'internal'
109
109
110 # start and stop parameters for effects
110 # start and stop parameters for effects
111 _effects = {'none': 0, 'black': 30, 'red': 31, 'green': 32, 'yellow': 33,
111 _effects = {'none': 0, 'black': 30, 'red': 31, 'green': 32, 'yellow': 33,
112 'blue': 34, 'magenta': 35, 'cyan': 36, 'white': 37, 'bold': 1,
112 'blue': 34, 'magenta': 35, 'cyan': 36, 'white': 37, 'bold': 1,
113 'italic': 3, 'underline': 4, 'inverse': 7,
113 'italic': 3, 'underline': 4, 'inverse': 7,
114 'black_background': 40, 'red_background': 41,
114 'black_background': 40, 'red_background': 41,
115 'green_background': 42, 'yellow_background': 43,
115 'green_background': 42, 'yellow_background': 43,
116 'blue_background': 44, 'purple_background': 45,
116 'blue_background': 44, 'purple_background': 45,
117 'cyan_background': 46, 'white_background': 47}
117 'cyan_background': 46, 'white_background': 47}
118
118
119 def _terminfosetup(ui, mode):
119 def _terminfosetup(ui, mode):
120 '''Initialize terminfo data and the terminal if we're in terminfo mode.'''
120 '''Initialize terminfo data and the terminal if we're in terminfo mode.'''
121
121
122 global _terminfo_params
122 global _terminfo_params
123 # If we failed to load curses, we go ahead and return.
123 # If we failed to load curses, we go ahead and return.
124 if not _terminfo_params:
124 if not _terminfo_params:
125 return
125 return
126 # Otherwise, see what the config file says.
126 # Otherwise, see what the config file says.
127 if mode not in ('auto', 'terminfo'):
127 if mode not in ('auto', 'terminfo'):
128 return
128 return
129
129
130 _terminfo_params.update((key[6:], (False, int(val)))
130 _terminfo_params.update((key[6:], (False, int(val)))
131 for key, val in ui.configitems('color')
131 for key, val in ui.configitems('color')
132 if key.startswith('color.'))
132 if key.startswith('color.'))
133
133
134 try:
134 try:
135 curses.setupterm()
135 curses.setupterm()
136 except curses.error, e:
136 except curses.error, e:
137 _terminfo_params = {}
137 _terminfo_params = {}
138 return
138 return
139
139
140 for key, (b, e) in _terminfo_params.items():
140 for key, (b, e) in _terminfo_params.items():
141 if not b:
141 if not b:
142 continue
142 continue
143 if not curses.tigetstr(e):
143 if not curses.tigetstr(e):
144 # Most terminals don't support dim, invis, etc, so don't be
144 # Most terminals don't support dim, invis, etc, so don't be
145 # noisy and use ui.debug().
145 # noisy and use ui.debug().
146 ui.debug("no terminfo entry for %s\n" % e)
146 ui.debug("no terminfo entry for %s\n" % e)
147 del _terminfo_params[key]
147 del _terminfo_params[key]
148 if not curses.tigetstr('setaf') or not curses.tigetstr('setab'):
148 if not curses.tigetstr('setaf') or not curses.tigetstr('setab'):
149 # Only warn about missing terminfo entries if we explicitly asked for
149 # Only warn about missing terminfo entries if we explicitly asked for
150 # terminfo mode.
150 # terminfo mode.
151 if mode == "terminfo":
151 if mode == "terminfo":
152 ui.warn(_("no terminfo entry for setab/setaf: reverting to "
152 ui.warn(_("no terminfo entry for setab/setaf: reverting to "
153 "ECMA-48 color\n"))
153 "ECMA-48 color\n"))
154 _terminfo_params = {}
154 _terminfo_params = {}
155
155
156 def _modesetup(ui, opts):
156 def _modesetup(ui, opts):
157 global _terminfo_params
157 global _terminfo_params
158
158
159 coloropt = opts['color']
159 coloropt = opts['color']
160 auto = coloropt == 'auto'
160 auto = coloropt == 'auto'
161 always = not auto and util.parsebool(coloropt)
161 always = not auto and util.parsebool(coloropt)
162 if not always and not auto:
162 if not always and not auto:
163 return None
163 return None
164
164
165 formatted = always or (os.environ.get('TERM') != 'dumb' and ui.formatted())
165 formatted = always or (os.environ.get('TERM') != 'dumb' and ui.formatted())
166
166
167 mode = ui.config('color', 'mode', 'auto')
167 mode = ui.config('color', 'mode', 'auto')
168 realmode = mode
168 realmode = mode
169 if mode == 'auto':
169 if mode == 'auto':
170 if os.name == 'nt' and 'TERM' not in os.environ:
170 if os.name == 'nt' and 'TERM' not in os.environ:
171 # looks line a cmd.exe console, use win32 API or nothing
171 # looks line a cmd.exe console, use win32 API or nothing
172 realmode = 'win32'
172 realmode = 'win32'
173 else:
173 else:
174 realmode = 'ansi'
174 realmode = 'ansi'
175
175
176 if realmode == 'win32':
176 if realmode == 'win32':
177 _terminfo_params = {}
177 _terminfo_params = {}
178 if not w32effects:
178 if not w32effects:
179 if mode == 'win32':
179 if mode == 'win32':
180 # only warn if color.mode is explicitly set to win32
180 # only warn if color.mode is explicitly set to win32
181 ui.warn(_('warning: failed to set color mode to %s\n') % mode)
181 ui.warn(_('warning: failed to set color mode to %s\n') % mode)
182 return None
182 return None
183 _effects.update(w32effects)
183 _effects.update(w32effects)
184 elif realmode == 'ansi':
184 elif realmode == 'ansi':
185 _terminfo_params = {}
185 _terminfo_params = {}
186 elif realmode == 'terminfo':
186 elif realmode == 'terminfo':
187 _terminfosetup(ui, mode)
187 _terminfosetup(ui, mode)
188 if not _terminfo_params:
188 if not _terminfo_params:
189 if mode == 'terminfo':
189 if mode == 'terminfo':
190 ## FIXME Shouldn't we return None in this case too?
190 ## FIXME Shouldn't we return None in this case too?
191 # only warn if color.mode is explicitly set to win32
191 # only warn if color.mode is explicitly set to win32
192 ui.warn(_('warning: failed to set color mode to %s\n') % mode)
192 ui.warn(_('warning: failed to set color mode to %s\n') % mode)
193 realmode = 'ansi'
193 realmode = 'ansi'
194 else:
194 else:
195 return None
195 return None
196
196
197 if always or (auto and formatted):
197 if always or (auto and formatted):
198 return realmode
198 return realmode
199 return None
199 return None
200
200
201 try:
201 try:
202 import curses
202 import curses
203 # Mapping from effect name to terminfo attribute name or color number.
203 # Mapping from effect name to terminfo attribute name or color number.
204 # This will also force-load the curses module.
204 # This will also force-load the curses module.
205 _terminfo_params = {'none': (True, 'sgr0'),
205 _terminfo_params = {'none': (True, 'sgr0'),
206 'standout': (True, 'smso'),
206 'standout': (True, 'smso'),
207 'underline': (True, 'smul'),
207 'underline': (True, 'smul'),
208 'reverse': (True, 'rev'),
208 'reverse': (True, 'rev'),
209 'inverse': (True, 'rev'),
209 'inverse': (True, 'rev'),
210 'blink': (True, 'blink'),
210 'blink': (True, 'blink'),
211 'dim': (True, 'dim'),
211 'dim': (True, 'dim'),
212 'bold': (True, 'bold'),
212 'bold': (True, 'bold'),
213 'invisible': (True, 'invis'),
213 'invisible': (True, 'invis'),
214 'italic': (True, 'sitm'),
214 'italic': (True, 'sitm'),
215 'black': (False, curses.COLOR_BLACK),
215 'black': (False, curses.COLOR_BLACK),
216 'red': (False, curses.COLOR_RED),
216 'red': (False, curses.COLOR_RED),
217 'green': (False, curses.COLOR_GREEN),
217 'green': (False, curses.COLOR_GREEN),
218 'yellow': (False, curses.COLOR_YELLOW),
218 'yellow': (False, curses.COLOR_YELLOW),
219 'blue': (False, curses.COLOR_BLUE),
219 'blue': (False, curses.COLOR_BLUE),
220 'magenta': (False, curses.COLOR_MAGENTA),
220 'magenta': (False, curses.COLOR_MAGENTA),
221 'cyan': (False, curses.COLOR_CYAN),
221 'cyan': (False, curses.COLOR_CYAN),
222 'white': (False, curses.COLOR_WHITE)}
222 'white': (False, curses.COLOR_WHITE)}
223 except ImportError:
223 except ImportError:
224 _terminfo_params = False
224 _terminfo_params = False
225
225
226 _styles = {'grep.match': 'red bold',
226 _styles = {'grep.match': 'red bold',
227 'grep.linenumber': 'green',
228 'grep.rev': 'green',
229 'grep.change': 'green',
230 'grep.sep': 'cyan',
231 'grep.filename': 'magenta',
232 'grep.user': 'magenta',
233 'grep.date': 'magenta',
227 'bookmarks.current': 'green',
234 'bookmarks.current': 'green',
228 'branches.active': 'none',
235 'branches.active': 'none',
229 'branches.closed': 'black bold',
236 'branches.closed': 'black bold',
230 'branches.current': 'green',
237 'branches.current': 'green',
231 'branches.inactive': 'none',
238 'branches.inactive': 'none',
232 'diff.changed': 'white',
239 'diff.changed': 'white',
233 'diff.deleted': 'red',
240 'diff.deleted': 'red',
234 'diff.diffline': 'bold',
241 'diff.diffline': 'bold',
235 'diff.extended': 'cyan bold',
242 'diff.extended': 'cyan bold',
236 'diff.file_a': 'red bold',
243 'diff.file_a': 'red bold',
237 'diff.file_b': 'green bold',
244 'diff.file_b': 'green bold',
238 'diff.hunk': 'magenta',
245 'diff.hunk': 'magenta',
239 'diff.inserted': 'green',
246 'diff.inserted': 'green',
240 'diff.trailingwhitespace': 'bold red_background',
247 'diff.trailingwhitespace': 'bold red_background',
241 'diffstat.deleted': 'red',
248 'diffstat.deleted': 'red',
242 'diffstat.inserted': 'green',
249 'diffstat.inserted': 'green',
243 'ui.prompt': 'yellow',
250 'ui.prompt': 'yellow',
244 'log.changeset': 'yellow',
251 'log.changeset': 'yellow',
245 'resolve.resolved': 'green bold',
252 'resolve.resolved': 'green bold',
246 'resolve.unresolved': 'red bold',
253 'resolve.unresolved': 'red bold',
247 'status.added': 'green bold',
254 'status.added': 'green bold',
248 'status.clean': 'none',
255 'status.clean': 'none',
249 'status.copied': 'none',
256 'status.copied': 'none',
250 'status.deleted': 'cyan bold underline',
257 'status.deleted': 'cyan bold underline',
251 'status.ignored': 'black bold',
258 'status.ignored': 'black bold',
252 'status.modified': 'blue bold',
259 'status.modified': 'blue bold',
253 'status.removed': 'red bold',
260 'status.removed': 'red bold',
254 'status.unknown': 'magenta bold underline',
261 'status.unknown': 'magenta bold underline',
255 'tags.normal': 'green',
262 'tags.normal': 'green',
256 'tags.local': 'black bold'}
263 'tags.local': 'black bold'}
257
264
258
265
259 def _effect_str(effect):
266 def _effect_str(effect):
260 '''Helper function for render_effects().'''
267 '''Helper function for render_effects().'''
261
268
262 bg = False
269 bg = False
263 if effect.endswith('_background'):
270 if effect.endswith('_background'):
264 bg = True
271 bg = True
265 effect = effect[:-11]
272 effect = effect[:-11]
266 attr, val = _terminfo_params[effect]
273 attr, val = _terminfo_params[effect]
267 if attr:
274 if attr:
268 return curses.tigetstr(val)
275 return curses.tigetstr(val)
269 elif bg:
276 elif bg:
270 return curses.tparm(curses.tigetstr('setab'), val)
277 return curses.tparm(curses.tigetstr('setab'), val)
271 else:
278 else:
272 return curses.tparm(curses.tigetstr('setaf'), val)
279 return curses.tparm(curses.tigetstr('setaf'), val)
273
280
274 def render_effects(text, effects):
281 def render_effects(text, effects):
275 'Wrap text in commands to turn on each effect.'
282 'Wrap text in commands to turn on each effect.'
276 if not text:
283 if not text:
277 return text
284 return text
278 if not _terminfo_params:
285 if not _terminfo_params:
279 start = [str(_effects[e]) for e in ['none'] + effects.split()]
286 start = [str(_effects[e]) for e in ['none'] + effects.split()]
280 start = '\033[' + ';'.join(start) + 'm'
287 start = '\033[' + ';'.join(start) + 'm'
281 stop = '\033[' + str(_effects['none']) + 'm'
288 stop = '\033[' + str(_effects['none']) + 'm'
282 else:
289 else:
283 start = ''.join(_effect_str(effect)
290 start = ''.join(_effect_str(effect)
284 for effect in ['none'] + effects.split())
291 for effect in ['none'] + effects.split())
285 stop = _effect_str('none')
292 stop = _effect_str('none')
286 return ''.join([start, text, stop])
293 return ''.join([start, text, stop])
287
294
288 def extstyles():
295 def extstyles():
289 for name, ext in extensions.extensions():
296 for name, ext in extensions.extensions():
290 _styles.update(getattr(ext, 'colortable', {}))
297 _styles.update(getattr(ext, 'colortable', {}))
291
298
292 def configstyles(ui):
299 def configstyles(ui):
293 for status, cfgeffects in ui.configitems('color'):
300 for status, cfgeffects in ui.configitems('color'):
294 if '.' not in status or status.startswith('color.'):
301 if '.' not in status or status.startswith('color.'):
295 continue
302 continue
296 cfgeffects = ui.configlist('color', status)
303 cfgeffects = ui.configlist('color', status)
297 if cfgeffects:
304 if cfgeffects:
298 good = []
305 good = []
299 for e in cfgeffects:
306 for e in cfgeffects:
300 if not _terminfo_params and e in _effects:
307 if not _terminfo_params and e in _effects:
301 good.append(e)
308 good.append(e)
302 elif e in _terminfo_params or e[:-11] in _terminfo_params:
309 elif e in _terminfo_params or e[:-11] in _terminfo_params:
303 good.append(e)
310 good.append(e)
304 else:
311 else:
305 ui.warn(_("ignoring unknown color/effect %r "
312 ui.warn(_("ignoring unknown color/effect %r "
306 "(configured in color.%s)\n")
313 "(configured in color.%s)\n")
307 % (e, status))
314 % (e, status))
308 _styles[status] = ' '.join(good)
315 _styles[status] = ' '.join(good)
309
316
310 class colorui(uimod.ui):
317 class colorui(uimod.ui):
311 def popbuffer(self, labeled=False):
318 def popbuffer(self, labeled=False):
312 if labeled:
319 if labeled:
313 return ''.join(self.label(a, label) for a, label
320 return ''.join(self.label(a, label) for a, label
314 in self._buffers.pop())
321 in self._buffers.pop())
315 return ''.join(a for a, label in self._buffers.pop())
322 return ''.join(a for a, label in self._buffers.pop())
316
323
317 _colormode = 'ansi'
324 _colormode = 'ansi'
318 def write(self, *args, **opts):
325 def write(self, *args, **opts):
319 label = opts.get('label', '')
326 label = opts.get('label', '')
320 if self._buffers:
327 if self._buffers:
321 self._buffers[-1].extend([(str(a), label) for a in args])
328 self._buffers[-1].extend([(str(a), label) for a in args])
322 elif self._colormode == 'win32':
329 elif self._colormode == 'win32':
323 for a in args:
330 for a in args:
324 win32print(a, super(colorui, self).write, **opts)
331 win32print(a, super(colorui, self).write, **opts)
325 else:
332 else:
326 return super(colorui, self).write(
333 return super(colorui, self).write(
327 *[self.label(str(a), label) for a in args], **opts)
334 *[self.label(str(a), label) for a in args], **opts)
328
335
329 def write_err(self, *args, **opts):
336 def write_err(self, *args, **opts):
330 label = opts.get('label', '')
337 label = opts.get('label', '')
331 if self._colormode == 'win32':
338 if self._colormode == 'win32':
332 for a in args:
339 for a in args:
333 win32print(a, super(colorui, self).write_err, **opts)
340 win32print(a, super(colorui, self).write_err, **opts)
334 else:
341 else:
335 return super(colorui, self).write_err(
342 return super(colorui, self).write_err(
336 *[self.label(str(a), label) for a in args], **opts)
343 *[self.label(str(a), label) for a in args], **opts)
337
344
338 def label(self, msg, label):
345 def label(self, msg, label):
339 effects = []
346 effects = []
340 for l in label.split():
347 for l in label.split():
341 s = _styles.get(l, '')
348 s = _styles.get(l, '')
342 if s:
349 if s:
343 effects.append(s)
350 effects.append(s)
344 effects = ' '.join(effects)
351 effects = ' '.join(effects)
345 if effects:
352 if effects:
346 return '\n'.join([render_effects(s, effects)
353 return '\n'.join([render_effects(s, effects)
347 for s in msg.split('\n')])
354 for s in msg.split('\n')])
348 return msg
355 return msg
349
356
350
357
351 def uisetup(ui):
358 def uisetup(ui):
352 global _terminfo_params
359 global _terminfo_params
353 if ui.plain():
360 if ui.plain():
354 return
361 return
355 def colorcmd(orig, ui_, opts, cmd, cmdfunc):
362 def colorcmd(orig, ui_, opts, cmd, cmdfunc):
356 mode = _modesetup(ui_, opts)
363 mode = _modesetup(ui_, opts)
357 if mode:
364 if mode:
358 colorui._colormode = mode
365 colorui._colormode = mode
359 if not issubclass(ui_.__class__, colorui):
366 if not issubclass(ui_.__class__, colorui):
360 colorui.__bases__ = (ui_.__class__,)
367 colorui.__bases__ = (ui_.__class__,)
361 ui_.__class__ = colorui
368 ui_.__class__ = colorui
362 extstyles()
369 extstyles()
363 configstyles(ui_)
370 configstyles(ui_)
364 return orig(ui_, opts, cmd, cmdfunc)
371 return orig(ui_, opts, cmd, cmdfunc)
365 extensions.wrapfunction(dispatch, '_runcommand', colorcmd)
372 extensions.wrapfunction(dispatch, '_runcommand', colorcmd)
366
373
367 def extsetup(ui):
374 def extsetup(ui):
368 commands.globalopts.append(
375 commands.globalopts.append(
369 ('', 'color', 'auto',
376 ('', 'color', 'auto',
370 # i18n: 'always', 'auto', and 'never' are keywords and should
377 # i18n: 'always', 'auto', and 'never' are keywords and should
371 # not be translated
378 # not be translated
372 _("when to colorize (boolean, always, auto, or never)"),
379 _("when to colorize (boolean, always, auto, or never)"),
373 _('TYPE')))
380 _('TYPE')))
374
381
375 if os.name != 'nt':
382 if os.name != 'nt':
376 w32effects = None
383 w32effects = None
377 else:
384 else:
378 import re, ctypes
385 import re, ctypes
379
386
380 _kernel32 = ctypes.windll.kernel32
387 _kernel32 = ctypes.windll.kernel32
381
388
382 _WORD = ctypes.c_ushort
389 _WORD = ctypes.c_ushort
383
390
384 _INVALID_HANDLE_VALUE = -1
391 _INVALID_HANDLE_VALUE = -1
385
392
386 class _COORD(ctypes.Structure):
393 class _COORD(ctypes.Structure):
387 _fields_ = [('X', ctypes.c_short),
394 _fields_ = [('X', ctypes.c_short),
388 ('Y', ctypes.c_short)]
395 ('Y', ctypes.c_short)]
389
396
390 class _SMALL_RECT(ctypes.Structure):
397 class _SMALL_RECT(ctypes.Structure):
391 _fields_ = [('Left', ctypes.c_short),
398 _fields_ = [('Left', ctypes.c_short),
392 ('Top', ctypes.c_short),
399 ('Top', ctypes.c_short),
393 ('Right', ctypes.c_short),
400 ('Right', ctypes.c_short),
394 ('Bottom', ctypes.c_short)]
401 ('Bottom', ctypes.c_short)]
395
402
396 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
403 class _CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
397 _fields_ = [('dwSize', _COORD),
404 _fields_ = [('dwSize', _COORD),
398 ('dwCursorPosition', _COORD),
405 ('dwCursorPosition', _COORD),
399 ('wAttributes', _WORD),
406 ('wAttributes', _WORD),
400 ('srWindow', _SMALL_RECT),
407 ('srWindow', _SMALL_RECT),
401 ('dwMaximumWindowSize', _COORD)]
408 ('dwMaximumWindowSize', _COORD)]
402
409
403 _STD_OUTPUT_HANDLE = 0xfffffff5L # (DWORD)-11
410 _STD_OUTPUT_HANDLE = 0xfffffff5L # (DWORD)-11
404 _STD_ERROR_HANDLE = 0xfffffff4L # (DWORD)-12
411 _STD_ERROR_HANDLE = 0xfffffff4L # (DWORD)-12
405
412
406 _FOREGROUND_BLUE = 0x0001
413 _FOREGROUND_BLUE = 0x0001
407 _FOREGROUND_GREEN = 0x0002
414 _FOREGROUND_GREEN = 0x0002
408 _FOREGROUND_RED = 0x0004
415 _FOREGROUND_RED = 0x0004
409 _FOREGROUND_INTENSITY = 0x0008
416 _FOREGROUND_INTENSITY = 0x0008
410
417
411 _BACKGROUND_BLUE = 0x0010
418 _BACKGROUND_BLUE = 0x0010
412 _BACKGROUND_GREEN = 0x0020
419 _BACKGROUND_GREEN = 0x0020
413 _BACKGROUND_RED = 0x0040
420 _BACKGROUND_RED = 0x0040
414 _BACKGROUND_INTENSITY = 0x0080
421 _BACKGROUND_INTENSITY = 0x0080
415
422
416 _COMMON_LVB_REVERSE_VIDEO = 0x4000
423 _COMMON_LVB_REVERSE_VIDEO = 0x4000
417 _COMMON_LVB_UNDERSCORE = 0x8000
424 _COMMON_LVB_UNDERSCORE = 0x8000
418
425
419 # http://msdn.microsoft.com/en-us/library/ms682088%28VS.85%29.aspx
426 # http://msdn.microsoft.com/en-us/library/ms682088%28VS.85%29.aspx
420 w32effects = {
427 w32effects = {
421 'none': -1,
428 'none': -1,
422 'black': 0,
429 'black': 0,
423 'red': _FOREGROUND_RED,
430 'red': _FOREGROUND_RED,
424 'green': _FOREGROUND_GREEN,
431 'green': _FOREGROUND_GREEN,
425 'yellow': _FOREGROUND_RED | _FOREGROUND_GREEN,
432 'yellow': _FOREGROUND_RED | _FOREGROUND_GREEN,
426 'blue': _FOREGROUND_BLUE,
433 'blue': _FOREGROUND_BLUE,
427 'magenta': _FOREGROUND_BLUE | _FOREGROUND_RED,
434 'magenta': _FOREGROUND_BLUE | _FOREGROUND_RED,
428 'cyan': _FOREGROUND_BLUE | _FOREGROUND_GREEN,
435 'cyan': _FOREGROUND_BLUE | _FOREGROUND_GREEN,
429 'white': _FOREGROUND_RED | _FOREGROUND_GREEN | _FOREGROUND_BLUE,
436 'white': _FOREGROUND_RED | _FOREGROUND_GREEN | _FOREGROUND_BLUE,
430 'bold': _FOREGROUND_INTENSITY,
437 'bold': _FOREGROUND_INTENSITY,
431 'black_background': 0x100, # unused value > 0x0f
438 'black_background': 0x100, # unused value > 0x0f
432 'red_background': _BACKGROUND_RED,
439 'red_background': _BACKGROUND_RED,
433 'green_background': _BACKGROUND_GREEN,
440 'green_background': _BACKGROUND_GREEN,
434 'yellow_background': _BACKGROUND_RED | _BACKGROUND_GREEN,
441 'yellow_background': _BACKGROUND_RED | _BACKGROUND_GREEN,
435 'blue_background': _BACKGROUND_BLUE,
442 'blue_background': _BACKGROUND_BLUE,
436 'purple_background': _BACKGROUND_BLUE | _BACKGROUND_RED,
443 'purple_background': _BACKGROUND_BLUE | _BACKGROUND_RED,
437 'cyan_background': _BACKGROUND_BLUE | _BACKGROUND_GREEN,
444 'cyan_background': _BACKGROUND_BLUE | _BACKGROUND_GREEN,
438 'white_background': (_BACKGROUND_RED | _BACKGROUND_GREEN |
445 'white_background': (_BACKGROUND_RED | _BACKGROUND_GREEN |
439 _BACKGROUND_BLUE),
446 _BACKGROUND_BLUE),
440 'bold_background': _BACKGROUND_INTENSITY,
447 'bold_background': _BACKGROUND_INTENSITY,
441 'underline': _COMMON_LVB_UNDERSCORE, # double-byte charsets only
448 'underline': _COMMON_LVB_UNDERSCORE, # double-byte charsets only
442 'inverse': _COMMON_LVB_REVERSE_VIDEO, # double-byte charsets only
449 'inverse': _COMMON_LVB_REVERSE_VIDEO, # double-byte charsets only
443 }
450 }
444
451
445 passthrough = set([_FOREGROUND_INTENSITY,
452 passthrough = set([_FOREGROUND_INTENSITY,
446 _BACKGROUND_INTENSITY,
453 _BACKGROUND_INTENSITY,
447 _COMMON_LVB_UNDERSCORE,
454 _COMMON_LVB_UNDERSCORE,
448 _COMMON_LVB_REVERSE_VIDEO])
455 _COMMON_LVB_REVERSE_VIDEO])
449
456
450 stdout = _kernel32.GetStdHandle(
457 stdout = _kernel32.GetStdHandle(
451 _STD_OUTPUT_HANDLE) # don't close the handle returned
458 _STD_OUTPUT_HANDLE) # don't close the handle returned
452 if stdout is None or stdout == _INVALID_HANDLE_VALUE:
459 if stdout is None or stdout == _INVALID_HANDLE_VALUE:
453 w32effects = None
460 w32effects = None
454 else:
461 else:
455 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
462 csbi = _CONSOLE_SCREEN_BUFFER_INFO()
456 if not _kernel32.GetConsoleScreenBufferInfo(
463 if not _kernel32.GetConsoleScreenBufferInfo(
457 stdout, ctypes.byref(csbi)):
464 stdout, ctypes.byref(csbi)):
458 # stdout may not support GetConsoleScreenBufferInfo()
465 # stdout may not support GetConsoleScreenBufferInfo()
459 # when called from subprocess or redirected
466 # when called from subprocess or redirected
460 w32effects = None
467 w32effects = None
461 else:
468 else:
462 origattr = csbi.wAttributes
469 origattr = csbi.wAttributes
463 ansire = re.compile('\033\[([^m]*)m([^\033]*)(.*)',
470 ansire = re.compile('\033\[([^m]*)m([^\033]*)(.*)',
464 re.MULTILINE | re.DOTALL)
471 re.MULTILINE | re.DOTALL)
465
472
466 def win32print(text, orig, **opts):
473 def win32print(text, orig, **opts):
467 label = opts.get('label', '')
474 label = opts.get('label', '')
468 attr = origattr
475 attr = origattr
469
476
470 def mapcolor(val, attr):
477 def mapcolor(val, attr):
471 if val == -1:
478 if val == -1:
472 return origattr
479 return origattr
473 elif val in passthrough:
480 elif val in passthrough:
474 return attr | val
481 return attr | val
475 elif val > 0x0f:
482 elif val > 0x0f:
476 return (val & 0x70) | (attr & 0x8f)
483 return (val & 0x70) | (attr & 0x8f)
477 else:
484 else:
478 return (val & 0x07) | (attr & 0xf8)
485 return (val & 0x07) | (attr & 0xf8)
479
486
480 # determine console attributes based on labels
487 # determine console attributes based on labels
481 for l in label.split():
488 for l in label.split():
482 style = _styles.get(l, '')
489 style = _styles.get(l, '')
483 for effect in style.split():
490 for effect in style.split():
484 attr = mapcolor(w32effects[effect], attr)
491 attr = mapcolor(w32effects[effect], attr)
485
492
486 # hack to ensure regexp finds data
493 # hack to ensure regexp finds data
487 if not text.startswith('\033['):
494 if not text.startswith('\033['):
488 text = '\033[m' + text
495 text = '\033[m' + text
489
496
490 # Look for ANSI-like codes embedded in text
497 # Look for ANSI-like codes embedded in text
491 m = re.match(ansire, text)
498 m = re.match(ansire, text)
492
499
493 try:
500 try:
494 while m:
501 while m:
495 for sattr in m.group(1).split(';'):
502 for sattr in m.group(1).split(';'):
496 if sattr:
503 if sattr:
497 attr = mapcolor(int(sattr), attr)
504 attr = mapcolor(int(sattr), attr)
498 _kernel32.SetConsoleTextAttribute(stdout, attr)
505 _kernel32.SetConsoleTextAttribute(stdout, attr)
499 orig(m.group(2), **opts)
506 orig(m.group(2), **opts)
500 m = re.match(ansire, m.group(3))
507 m = re.match(ansire, m.group(3))
501 finally:
508 finally:
502 # Explicitly reset original attributes
509 # Explicitly reset original attributes
503 _kernel32.SetConsoleTextAttribute(stdout, origattr)
510 _kernel32.SetConsoleTextAttribute(stdout, origattr)
@@ -1,5922 +1,5927 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 _, gettext
10 from i18n import _, gettext
11 import os, re, difflib, time, tempfile, errno
11 import os, re, difflib, time, tempfile, errno
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, url, encoding, templatekw, discovery
13 import patch, help, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, hbisect
14 import archival, changegroup, cmdutil, hbisect
15 import sshserver, hgweb, hgweb.server, commandserver
15 import sshserver, hgweb, hgweb.server, commandserver
16 import merge as mergemod
16 import merge as mergemod
17 import minirst, revset, fileset
17 import minirst, revset, fileset
18 import dagparser, context, simplemerge, graphmod
18 import dagparser, context, simplemerge, graphmod
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
19 import random, setdiscovery, treediscovery, dagutil, pvec, localrepo
20 import phases, obsolete
20 import phases, obsolete
21
21
22 table = {}
22 table = {}
23
23
24 command = cmdutil.command(table)
24 command = cmdutil.command(table)
25
25
26 # common command options
26 # common command options
27
27
28 globalopts = [
28 globalopts = [
29 ('R', 'repository', '',
29 ('R', 'repository', '',
30 _('repository root directory or name of overlay bundle file'),
30 _('repository root directory or name of overlay bundle file'),
31 _('REPO')),
31 _('REPO')),
32 ('', 'cwd', '',
32 ('', 'cwd', '',
33 _('change working directory'), _('DIR')),
33 _('change working directory'), _('DIR')),
34 ('y', 'noninteractive', None,
34 ('y', 'noninteractive', None,
35 _('do not prompt, automatically pick the first choice for all prompts')),
35 _('do not prompt, automatically pick the first choice for all prompts')),
36 ('q', 'quiet', None, _('suppress output')),
36 ('q', 'quiet', None, _('suppress output')),
37 ('v', 'verbose', None, _('enable additional output')),
37 ('v', 'verbose', None, _('enable additional output')),
38 ('', 'config', [],
38 ('', 'config', [],
39 _('set/override config option (use \'section.name=value\')'),
39 _('set/override config option (use \'section.name=value\')'),
40 _('CONFIG')),
40 _('CONFIG')),
41 ('', 'debug', None, _('enable debugging output')),
41 ('', 'debug', None, _('enable debugging output')),
42 ('', 'debugger', None, _('start debugger')),
42 ('', 'debugger', None, _('start debugger')),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
43 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
44 _('ENCODE')),
44 _('ENCODE')),
45 ('', 'encodingmode', encoding.encodingmode,
45 ('', 'encodingmode', encoding.encodingmode,
46 _('set the charset encoding mode'), _('MODE')),
46 _('set the charset encoding mode'), _('MODE')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
47 ('', 'traceback', None, _('always print a traceback on exception')),
48 ('', 'time', None, _('time how long the command takes')),
48 ('', 'time', None, _('time how long the command takes')),
49 ('', 'profile', None, _('print command execution profile')),
49 ('', 'profile', None, _('print command execution profile')),
50 ('', 'version', None, _('output version information and exit')),
50 ('', 'version', None, _('output version information and exit')),
51 ('h', 'help', None, _('display help and exit')),
51 ('h', 'help', None, _('display help and exit')),
52 ]
52 ]
53
53
54 dryrunopts = [('n', 'dry-run', None,
54 dryrunopts = [('n', 'dry-run', None,
55 _('do not perform actions, just print output'))]
55 _('do not perform actions, just print output'))]
56
56
57 remoteopts = [
57 remoteopts = [
58 ('e', 'ssh', '',
58 ('e', 'ssh', '',
59 _('specify ssh command to use'), _('CMD')),
59 _('specify ssh command to use'), _('CMD')),
60 ('', 'remotecmd', '',
60 ('', 'remotecmd', '',
61 _('specify hg command to run on the remote side'), _('CMD')),
61 _('specify hg command to run on the remote side'), _('CMD')),
62 ('', 'insecure', None,
62 ('', 'insecure', None,
63 _('do not verify server certificate (ignoring web.cacerts config)')),
63 _('do not verify server certificate (ignoring web.cacerts config)')),
64 ]
64 ]
65
65
66 walkopts = [
66 walkopts = [
67 ('I', 'include', [],
67 ('I', 'include', [],
68 _('include names matching the given patterns'), _('PATTERN')),
68 _('include names matching the given patterns'), _('PATTERN')),
69 ('X', 'exclude', [],
69 ('X', 'exclude', [],
70 _('exclude names matching the given patterns'), _('PATTERN')),
70 _('exclude names matching the given patterns'), _('PATTERN')),
71 ]
71 ]
72
72
73 commitopts = [
73 commitopts = [
74 ('m', 'message', '',
74 ('m', 'message', '',
75 _('use text as commit message'), _('TEXT')),
75 _('use text as commit message'), _('TEXT')),
76 ('l', 'logfile', '',
76 ('l', 'logfile', '',
77 _('read commit message from file'), _('FILE')),
77 _('read commit message from file'), _('FILE')),
78 ]
78 ]
79
79
80 commitopts2 = [
80 commitopts2 = [
81 ('d', 'date', '',
81 ('d', 'date', '',
82 _('record the specified date as commit date'), _('DATE')),
82 _('record the specified date as commit date'), _('DATE')),
83 ('u', 'user', '',
83 ('u', 'user', '',
84 _('record the specified user as committer'), _('USER')),
84 _('record the specified user as committer'), _('USER')),
85 ]
85 ]
86
86
87 templateopts = [
87 templateopts = [
88 ('', 'style', '',
88 ('', 'style', '',
89 _('display using template map file'), _('STYLE')),
89 _('display using template map file'), _('STYLE')),
90 ('', 'template', '',
90 ('', 'template', '',
91 _('display with template'), _('TEMPLATE')),
91 _('display with template'), _('TEMPLATE')),
92 ]
92 ]
93
93
94 logopts = [
94 logopts = [
95 ('p', 'patch', None, _('show patch')),
95 ('p', 'patch', None, _('show patch')),
96 ('g', 'git', None, _('use git extended diff format')),
96 ('g', 'git', None, _('use git extended diff format')),
97 ('l', 'limit', '',
97 ('l', 'limit', '',
98 _('limit number of changes displayed'), _('NUM')),
98 _('limit number of changes displayed'), _('NUM')),
99 ('M', 'no-merges', None, _('do not show merges')),
99 ('M', 'no-merges', None, _('do not show merges')),
100 ('', 'stat', None, _('output diffstat-style summary of changes')),
100 ('', 'stat', None, _('output diffstat-style summary of changes')),
101 ('G', 'graph', None, _("show the revision DAG")),
101 ('G', 'graph', None, _("show the revision DAG")),
102 ] + templateopts
102 ] + templateopts
103
103
104 diffopts = [
104 diffopts = [
105 ('a', 'text', None, _('treat all files as text')),
105 ('a', 'text', None, _('treat all files as text')),
106 ('g', 'git', None, _('use git extended diff format')),
106 ('g', 'git', None, _('use git extended diff format')),
107 ('', 'nodates', None, _('omit dates from diff headers'))
107 ('', 'nodates', None, _('omit dates from diff headers'))
108 ]
108 ]
109
109
110 diffwsopts = [
110 diffwsopts = [
111 ('w', 'ignore-all-space', None,
111 ('w', 'ignore-all-space', None,
112 _('ignore white space when comparing lines')),
112 _('ignore white space when comparing lines')),
113 ('b', 'ignore-space-change', None,
113 ('b', 'ignore-space-change', None,
114 _('ignore changes in the amount of white space')),
114 _('ignore changes in the amount of white space')),
115 ('B', 'ignore-blank-lines', None,
115 ('B', 'ignore-blank-lines', None,
116 _('ignore changes whose lines are all blank')),
116 _('ignore changes whose lines are all blank')),
117 ]
117 ]
118
118
119 diffopts2 = [
119 diffopts2 = [
120 ('p', 'show-function', None, _('show which function each change is in')),
120 ('p', 'show-function', None, _('show which function each change is in')),
121 ('', 'reverse', None, _('produce a diff that undoes the changes')),
121 ('', 'reverse', None, _('produce a diff that undoes the changes')),
122 ] + diffwsopts + [
122 ] + diffwsopts + [
123 ('U', 'unified', '',
123 ('U', 'unified', '',
124 _('number of lines of context to show'), _('NUM')),
124 _('number of lines of context to show'), _('NUM')),
125 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 ('', 'stat', None, _('output diffstat-style summary of changes')),
126 ]
126 ]
127
127
128 mergetoolopts = [
128 mergetoolopts = [
129 ('t', 'tool', '', _('specify merge tool')),
129 ('t', 'tool', '', _('specify merge tool')),
130 ]
130 ]
131
131
132 similarityopts = [
132 similarityopts = [
133 ('s', 'similarity', '',
133 ('s', 'similarity', '',
134 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
134 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
135 ]
135 ]
136
136
137 subrepoopts = [
137 subrepoopts = [
138 ('S', 'subrepos', None,
138 ('S', 'subrepos', None,
139 _('recurse into subrepositories'))
139 _('recurse into subrepositories'))
140 ]
140 ]
141
141
142 # Commands start here, listed alphabetically
142 # Commands start here, listed alphabetically
143
143
144 @command('^add',
144 @command('^add',
145 walkopts + subrepoopts + dryrunopts,
145 walkopts + subrepoopts + dryrunopts,
146 _('[OPTION]... [FILE]...'))
146 _('[OPTION]... [FILE]...'))
147 def add(ui, repo, *pats, **opts):
147 def add(ui, repo, *pats, **opts):
148 """add the specified files on the next commit
148 """add the specified files on the next commit
149
149
150 Schedule files to be version controlled and added to the
150 Schedule files to be version controlled and added to the
151 repository.
151 repository.
152
152
153 The files will be added to the repository at the next commit. To
153 The files will be added to the repository at the next commit. To
154 undo an add before that, see :hg:`forget`.
154 undo an add before that, see :hg:`forget`.
155
155
156 If no names are given, add all files to the repository.
156 If no names are given, add all files to the repository.
157
157
158 .. container:: verbose
158 .. container:: verbose
159
159
160 An example showing how new (unknown) files are added
160 An example showing how new (unknown) files are added
161 automatically by :hg:`add`::
161 automatically by :hg:`add`::
162
162
163 $ ls
163 $ ls
164 foo.c
164 foo.c
165 $ hg status
165 $ hg status
166 ? foo.c
166 ? foo.c
167 $ hg add
167 $ hg add
168 adding foo.c
168 adding foo.c
169 $ hg status
169 $ hg status
170 A foo.c
170 A foo.c
171
171
172 Returns 0 if all files are successfully added.
172 Returns 0 if all files are successfully added.
173 """
173 """
174
174
175 m = scmutil.match(repo[None], pats, opts)
175 m = scmutil.match(repo[None], pats, opts)
176 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
176 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
177 opts.get('subrepos'), prefix="", explicitonly=False)
177 opts.get('subrepos'), prefix="", explicitonly=False)
178 return rejected and 1 or 0
178 return rejected and 1 or 0
179
179
180 @command('addremove',
180 @command('addremove',
181 similarityopts + walkopts + dryrunopts,
181 similarityopts + walkopts + dryrunopts,
182 _('[OPTION]... [FILE]...'))
182 _('[OPTION]... [FILE]...'))
183 def addremove(ui, repo, *pats, **opts):
183 def addremove(ui, repo, *pats, **opts):
184 """add all new files, delete all missing files
184 """add all new files, delete all missing files
185
185
186 Add all new files and remove all missing files from the
186 Add all new files and remove all missing files from the
187 repository.
187 repository.
188
188
189 New files are ignored if they match any of the patterns in
189 New files are ignored if they match any of the patterns in
190 ``.hgignore``. As with add, these changes take effect at the next
190 ``.hgignore``. As with add, these changes take effect at the next
191 commit.
191 commit.
192
192
193 Use the -s/--similarity option to detect renamed files. This
193 Use the -s/--similarity option to detect renamed files. This
194 option takes a percentage between 0 (disabled) and 100 (files must
194 option takes a percentage between 0 (disabled) and 100 (files must
195 be identical) as its parameter. With a parameter greater than 0,
195 be identical) as its parameter. With a parameter greater than 0,
196 this compares every removed file with every added file and records
196 this compares every removed file with every added file and records
197 those similar enough as renames. Detecting renamed files this way
197 those similar enough as renames. Detecting renamed files this way
198 can be expensive. After using this option, :hg:`status -C` can be
198 can be expensive. After using this option, :hg:`status -C` can be
199 used to check which files were identified as moved or renamed. If
199 used to check which files were identified as moved or renamed. If
200 not specified, -s/--similarity defaults to 100 and only renames of
200 not specified, -s/--similarity defaults to 100 and only renames of
201 identical files are detected.
201 identical files are detected.
202
202
203 Returns 0 if all files are successfully added.
203 Returns 0 if all files are successfully added.
204 """
204 """
205 try:
205 try:
206 sim = float(opts.get('similarity') or 100)
206 sim = float(opts.get('similarity') or 100)
207 except ValueError:
207 except ValueError:
208 raise util.Abort(_('similarity must be a number'))
208 raise util.Abort(_('similarity must be a number'))
209 if sim < 0 or sim > 100:
209 if sim < 0 or sim > 100:
210 raise util.Abort(_('similarity must be between 0 and 100'))
210 raise util.Abort(_('similarity must be between 0 and 100'))
211 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
211 return scmutil.addremove(repo, pats, opts, similarity=sim / 100.0)
212
212
213 @command('^annotate|blame',
213 @command('^annotate|blame',
214 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
214 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
215 ('', 'follow', None,
215 ('', 'follow', None,
216 _('follow copies/renames and list the filename (DEPRECATED)')),
216 _('follow copies/renames and list the filename (DEPRECATED)')),
217 ('', 'no-follow', None, _("don't follow copies and renames")),
217 ('', 'no-follow', None, _("don't follow copies and renames")),
218 ('a', 'text', None, _('treat all files as text')),
218 ('a', 'text', None, _('treat all files as text')),
219 ('u', 'user', None, _('list the author (long with -v)')),
219 ('u', 'user', None, _('list the author (long with -v)')),
220 ('f', 'file', None, _('list the filename')),
220 ('f', 'file', None, _('list the filename')),
221 ('d', 'date', None, _('list the date (short with -q)')),
221 ('d', 'date', None, _('list the date (short with -q)')),
222 ('n', 'number', None, _('list the revision number (default)')),
222 ('n', 'number', None, _('list the revision number (default)')),
223 ('c', 'changeset', None, _('list the changeset')),
223 ('c', 'changeset', None, _('list the changeset')),
224 ('l', 'line-number', None, _('show line number at the first appearance'))
224 ('l', 'line-number', None, _('show line number at the first appearance'))
225 ] + diffwsopts + walkopts,
225 ] + diffwsopts + walkopts,
226 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
226 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'))
227 def annotate(ui, repo, *pats, **opts):
227 def annotate(ui, repo, *pats, **opts):
228 """show changeset information by line for each file
228 """show changeset information by line for each file
229
229
230 List changes in files, showing the revision id responsible for
230 List changes in files, showing the revision id responsible for
231 each line
231 each line
232
232
233 This command is useful for discovering when a change was made and
233 This command is useful for discovering when a change was made and
234 by whom.
234 by whom.
235
235
236 Without the -a/--text option, annotate will avoid processing files
236 Without the -a/--text option, annotate will avoid processing files
237 it detects as binary. With -a, annotate will annotate the file
237 it detects as binary. With -a, annotate will annotate the file
238 anyway, although the results will probably be neither useful
238 anyway, although the results will probably be neither useful
239 nor desirable.
239 nor desirable.
240
240
241 Returns 0 on success.
241 Returns 0 on success.
242 """
242 """
243 if opts.get('follow'):
243 if opts.get('follow'):
244 # --follow is deprecated and now just an alias for -f/--file
244 # --follow is deprecated and now just an alias for -f/--file
245 # to mimic the behavior of Mercurial before version 1.5
245 # to mimic the behavior of Mercurial before version 1.5
246 opts['file'] = True
246 opts['file'] = True
247
247
248 datefunc = ui.quiet and util.shortdate or util.datestr
248 datefunc = ui.quiet and util.shortdate or util.datestr
249 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
249 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
250
250
251 if not pats:
251 if not pats:
252 raise util.Abort(_('at least one filename or pattern is required'))
252 raise util.Abort(_('at least one filename or pattern is required'))
253
253
254 hexfn = ui.debugflag and hex or short
254 hexfn = ui.debugflag and hex or short
255
255
256 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
256 opmap = [('user', ' ', lambda x: ui.shortuser(x[0].user())),
257 ('number', ' ', lambda x: str(x[0].rev())),
257 ('number', ' ', lambda x: str(x[0].rev())),
258 ('changeset', ' ', lambda x: hexfn(x[0].node())),
258 ('changeset', ' ', lambda x: hexfn(x[0].node())),
259 ('date', ' ', getdate),
259 ('date', ' ', getdate),
260 ('file', ' ', lambda x: x[0].path()),
260 ('file', ' ', lambda x: x[0].path()),
261 ('line_number', ':', lambda x: str(x[1])),
261 ('line_number', ':', lambda x: str(x[1])),
262 ]
262 ]
263
263
264 if (not opts.get('user') and not opts.get('changeset')
264 if (not opts.get('user') and not opts.get('changeset')
265 and not opts.get('date') and not opts.get('file')):
265 and not opts.get('date') and not opts.get('file')):
266 opts['number'] = True
266 opts['number'] = True
267
267
268 linenumber = opts.get('line_number') is not None
268 linenumber = opts.get('line_number') is not None
269 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
269 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
270 raise util.Abort(_('at least one of -n/-c is required for -l'))
270 raise util.Abort(_('at least one of -n/-c is required for -l'))
271
271
272 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
272 funcmap = [(func, sep) for op, sep, func in opmap if opts.get(op)]
273 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
273 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
274
274
275 def bad(x, y):
275 def bad(x, y):
276 raise util.Abort("%s: %s" % (x, y))
276 raise util.Abort("%s: %s" % (x, y))
277
277
278 ctx = scmutil.revsingle(repo, opts.get('rev'))
278 ctx = scmutil.revsingle(repo, opts.get('rev'))
279 m = scmutil.match(ctx, pats, opts)
279 m = scmutil.match(ctx, pats, opts)
280 m.bad = bad
280 m.bad = bad
281 follow = not opts.get('no_follow')
281 follow = not opts.get('no_follow')
282 diffopts = patch.diffopts(ui, opts, section='annotate')
282 diffopts = patch.diffopts(ui, opts, section='annotate')
283 for abs in ctx.walk(m):
283 for abs in ctx.walk(m):
284 fctx = ctx[abs]
284 fctx = ctx[abs]
285 if not opts.get('text') and util.binary(fctx.data()):
285 if not opts.get('text') and util.binary(fctx.data()):
286 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
286 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
287 continue
287 continue
288
288
289 lines = fctx.annotate(follow=follow, linenumber=linenumber,
289 lines = fctx.annotate(follow=follow, linenumber=linenumber,
290 diffopts=diffopts)
290 diffopts=diffopts)
291 pieces = []
291 pieces = []
292
292
293 for f, sep in funcmap:
293 for f, sep in funcmap:
294 l = [f(n) for n, dummy in lines]
294 l = [f(n) for n, dummy in lines]
295 if l:
295 if l:
296 sized = [(x, encoding.colwidth(x)) for x in l]
296 sized = [(x, encoding.colwidth(x)) for x in l]
297 ml = max([w for x, w in sized])
297 ml = max([w for x, w in sized])
298 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
298 pieces.append(["%s%s%s" % (sep, ' ' * (ml - w), x)
299 for x, w in sized])
299 for x, w in sized])
300
300
301 if pieces:
301 if pieces:
302 for p, l in zip(zip(*pieces), lines):
302 for p, l in zip(zip(*pieces), lines):
303 ui.write("%s: %s" % ("".join(p), l[1]))
303 ui.write("%s: %s" % ("".join(p), l[1]))
304
304
305 if lines and not lines[-1][1].endswith('\n'):
305 if lines and not lines[-1][1].endswith('\n'):
306 ui.write('\n')
306 ui.write('\n')
307
307
308 @command('archive',
308 @command('archive',
309 [('', 'no-decode', None, _('do not pass files through decoders')),
309 [('', 'no-decode', None, _('do not pass files through decoders')),
310 ('p', 'prefix', '', _('directory prefix for files in archive'),
310 ('p', 'prefix', '', _('directory prefix for files in archive'),
311 _('PREFIX')),
311 _('PREFIX')),
312 ('r', 'rev', '', _('revision to distribute'), _('REV')),
312 ('r', 'rev', '', _('revision to distribute'), _('REV')),
313 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
313 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
314 ] + subrepoopts + walkopts,
314 ] + subrepoopts + walkopts,
315 _('[OPTION]... DEST'))
315 _('[OPTION]... DEST'))
316 def archive(ui, repo, dest, **opts):
316 def archive(ui, repo, dest, **opts):
317 '''create an unversioned archive of a repository revision
317 '''create an unversioned archive of a repository revision
318
318
319 By default, the revision used is the parent of the working
319 By default, the revision used is the parent of the working
320 directory; use -r/--rev to specify a different revision.
320 directory; use -r/--rev to specify a different revision.
321
321
322 The archive type is automatically detected based on file
322 The archive type is automatically detected based on file
323 extension (or override using -t/--type).
323 extension (or override using -t/--type).
324
324
325 .. container:: verbose
325 .. container:: verbose
326
326
327 Examples:
327 Examples:
328
328
329 - create a zip file containing the 1.0 release::
329 - create a zip file containing the 1.0 release::
330
330
331 hg archive -r 1.0 project-1.0.zip
331 hg archive -r 1.0 project-1.0.zip
332
332
333 - create a tarball excluding .hg files::
333 - create a tarball excluding .hg files::
334
334
335 hg archive project.tar.gz -X ".hg*"
335 hg archive project.tar.gz -X ".hg*"
336
336
337 Valid types are:
337 Valid types are:
338
338
339 :``files``: a directory full of files (default)
339 :``files``: a directory full of files (default)
340 :``tar``: tar archive, uncompressed
340 :``tar``: tar archive, uncompressed
341 :``tbz2``: tar archive, compressed using bzip2
341 :``tbz2``: tar archive, compressed using bzip2
342 :``tgz``: tar archive, compressed using gzip
342 :``tgz``: tar archive, compressed using gzip
343 :``uzip``: zip archive, uncompressed
343 :``uzip``: zip archive, uncompressed
344 :``zip``: zip archive, compressed using deflate
344 :``zip``: zip archive, compressed using deflate
345
345
346 The exact name of the destination archive or directory is given
346 The exact name of the destination archive or directory is given
347 using a format string; see :hg:`help export` for details.
347 using a format string; see :hg:`help export` for details.
348
348
349 Each member added to an archive file has a directory prefix
349 Each member added to an archive file has a directory prefix
350 prepended. Use -p/--prefix to specify a format string for the
350 prepended. Use -p/--prefix to specify a format string for the
351 prefix. The default is the basename of the archive, with suffixes
351 prefix. The default is the basename of the archive, with suffixes
352 removed.
352 removed.
353
353
354 Returns 0 on success.
354 Returns 0 on success.
355 '''
355 '''
356
356
357 ctx = scmutil.revsingle(repo, opts.get('rev'))
357 ctx = scmutil.revsingle(repo, opts.get('rev'))
358 if not ctx:
358 if not ctx:
359 raise util.Abort(_('no working directory: please specify a revision'))
359 raise util.Abort(_('no working directory: please specify a revision'))
360 node = ctx.node()
360 node = ctx.node()
361 dest = cmdutil.makefilename(repo, dest, node)
361 dest = cmdutil.makefilename(repo, dest, node)
362 if os.path.realpath(dest) == repo.root:
362 if os.path.realpath(dest) == repo.root:
363 raise util.Abort(_('repository root cannot be destination'))
363 raise util.Abort(_('repository root cannot be destination'))
364
364
365 kind = opts.get('type') or archival.guesskind(dest) or 'files'
365 kind = opts.get('type') or archival.guesskind(dest) or 'files'
366 prefix = opts.get('prefix')
366 prefix = opts.get('prefix')
367
367
368 if dest == '-':
368 if dest == '-':
369 if kind == 'files':
369 if kind == 'files':
370 raise util.Abort(_('cannot archive plain files to stdout'))
370 raise util.Abort(_('cannot archive plain files to stdout'))
371 dest = cmdutil.makefileobj(repo, dest)
371 dest = cmdutil.makefileobj(repo, dest)
372 if not prefix:
372 if not prefix:
373 prefix = os.path.basename(repo.root) + '-%h'
373 prefix = os.path.basename(repo.root) + '-%h'
374
374
375 prefix = cmdutil.makefilename(repo, prefix, node)
375 prefix = cmdutil.makefilename(repo, prefix, node)
376 matchfn = scmutil.match(ctx, [], opts)
376 matchfn = scmutil.match(ctx, [], opts)
377 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
377 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
378 matchfn, prefix, subrepos=opts.get('subrepos'))
378 matchfn, prefix, subrepos=opts.get('subrepos'))
379
379
380 @command('backout',
380 @command('backout',
381 [('', 'merge', None, _('merge with old dirstate parent after backout')),
381 [('', 'merge', None, _('merge with old dirstate parent after backout')),
382 ('', 'parent', '',
382 ('', 'parent', '',
383 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
383 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
384 ('r', 'rev', '', _('revision to backout'), _('REV')),
384 ('r', 'rev', '', _('revision to backout'), _('REV')),
385 ] + mergetoolopts + walkopts + commitopts + commitopts2,
385 ] + mergetoolopts + walkopts + commitopts + commitopts2,
386 _('[OPTION]... [-r] REV'))
386 _('[OPTION]... [-r] REV'))
387 def backout(ui, repo, node=None, rev=None, **opts):
387 def backout(ui, repo, node=None, rev=None, **opts):
388 '''reverse effect of earlier changeset
388 '''reverse effect of earlier changeset
389
389
390 Prepare a new changeset with the effect of REV undone in the
390 Prepare a new changeset with the effect of REV undone in the
391 current working directory.
391 current working directory.
392
392
393 If REV is the parent of the working directory, then this new changeset
393 If REV is the parent of the working directory, then this new changeset
394 is committed automatically. Otherwise, hg needs to merge the
394 is committed automatically. Otherwise, hg needs to merge the
395 changes and the merged result is left uncommitted.
395 changes and the merged result is left uncommitted.
396
396
397 .. note::
397 .. note::
398 backout cannot be used to fix either an unwanted or
398 backout cannot be used to fix either an unwanted or
399 incorrect merge.
399 incorrect merge.
400
400
401 .. container:: verbose
401 .. container:: verbose
402
402
403 By default, the pending changeset will have one parent,
403 By default, the pending changeset will have one parent,
404 maintaining a linear history. With --merge, the pending
404 maintaining a linear history. With --merge, the pending
405 changeset will instead have two parents: the old parent of the
405 changeset will instead have two parents: the old parent of the
406 working directory and a new child of REV that simply undoes REV.
406 working directory and a new child of REV that simply undoes REV.
407
407
408 Before version 1.7, the behavior without --merge was equivalent
408 Before version 1.7, the behavior without --merge was equivalent
409 to specifying --merge followed by :hg:`update --clean .` to
409 to specifying --merge followed by :hg:`update --clean .` to
410 cancel the merge and leave the child of REV as a head to be
410 cancel the merge and leave the child of REV as a head to be
411 merged separately.
411 merged separately.
412
412
413 See :hg:`help dates` for a list of formats valid for -d/--date.
413 See :hg:`help dates` for a list of formats valid for -d/--date.
414
414
415 Returns 0 on success.
415 Returns 0 on success.
416 '''
416 '''
417 if rev and node:
417 if rev and node:
418 raise util.Abort(_("please specify just one revision"))
418 raise util.Abort(_("please specify just one revision"))
419
419
420 if not rev:
420 if not rev:
421 rev = node
421 rev = node
422
422
423 if not rev:
423 if not rev:
424 raise util.Abort(_("please specify a revision to backout"))
424 raise util.Abort(_("please specify a revision to backout"))
425
425
426 date = opts.get('date')
426 date = opts.get('date')
427 if date:
427 if date:
428 opts['date'] = util.parsedate(date)
428 opts['date'] = util.parsedate(date)
429
429
430 cmdutil.bailifchanged(repo)
430 cmdutil.bailifchanged(repo)
431 node = scmutil.revsingle(repo, rev).node()
431 node = scmutil.revsingle(repo, rev).node()
432
432
433 op1, op2 = repo.dirstate.parents()
433 op1, op2 = repo.dirstate.parents()
434 a = repo.changelog.ancestor(op1, node)
434 a = repo.changelog.ancestor(op1, node)
435 if a != node:
435 if a != node:
436 raise util.Abort(_('cannot backout change on a different branch'))
436 raise util.Abort(_('cannot backout change on a different branch'))
437
437
438 p1, p2 = repo.changelog.parents(node)
438 p1, p2 = repo.changelog.parents(node)
439 if p1 == nullid:
439 if p1 == nullid:
440 raise util.Abort(_('cannot backout a change with no parents'))
440 raise util.Abort(_('cannot backout a change with no parents'))
441 if p2 != nullid:
441 if p2 != nullid:
442 if not opts.get('parent'):
442 if not opts.get('parent'):
443 raise util.Abort(_('cannot backout a merge changeset'))
443 raise util.Abort(_('cannot backout a merge changeset'))
444 p = repo.lookup(opts['parent'])
444 p = repo.lookup(opts['parent'])
445 if p not in (p1, p2):
445 if p not in (p1, p2):
446 raise util.Abort(_('%s is not a parent of %s') %
446 raise util.Abort(_('%s is not a parent of %s') %
447 (short(p), short(node)))
447 (short(p), short(node)))
448 parent = p
448 parent = p
449 else:
449 else:
450 if opts.get('parent'):
450 if opts.get('parent'):
451 raise util.Abort(_('cannot use --parent on non-merge changeset'))
451 raise util.Abort(_('cannot use --parent on non-merge changeset'))
452 parent = p1
452 parent = p1
453
453
454 # the backout should appear on the same branch
454 # the backout should appear on the same branch
455 wlock = repo.wlock()
455 wlock = repo.wlock()
456 try:
456 try:
457 branch = repo.dirstate.branch()
457 branch = repo.dirstate.branch()
458 hg.clean(repo, node, show_stats=False)
458 hg.clean(repo, node, show_stats=False)
459 repo.dirstate.setbranch(branch)
459 repo.dirstate.setbranch(branch)
460 revert_opts = opts.copy()
460 revert_opts = opts.copy()
461 revert_opts['date'] = None
461 revert_opts['date'] = None
462 revert_opts['all'] = True
462 revert_opts['all'] = True
463 revert_opts['rev'] = hex(parent)
463 revert_opts['rev'] = hex(parent)
464 revert_opts['no_backup'] = None
464 revert_opts['no_backup'] = None
465 revert(ui, repo, **revert_opts)
465 revert(ui, repo, **revert_opts)
466 if not opts.get('merge') and op1 != node:
466 if not opts.get('merge') and op1 != node:
467 try:
467 try:
468 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
468 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
469 return hg.update(repo, op1)
469 return hg.update(repo, op1)
470 finally:
470 finally:
471 ui.setconfig('ui', 'forcemerge', '')
471 ui.setconfig('ui', 'forcemerge', '')
472
472
473 commit_opts = opts.copy()
473 commit_opts = opts.copy()
474 commit_opts['addremove'] = False
474 commit_opts['addremove'] = False
475 if not commit_opts['message'] and not commit_opts['logfile']:
475 if not commit_opts['message'] and not commit_opts['logfile']:
476 # we don't translate commit messages
476 # we don't translate commit messages
477 commit_opts['message'] = "Backed out changeset %s" % short(node)
477 commit_opts['message'] = "Backed out changeset %s" % short(node)
478 commit_opts['force_editor'] = True
478 commit_opts['force_editor'] = True
479 commit(ui, repo, **commit_opts)
479 commit(ui, repo, **commit_opts)
480 def nice(node):
480 def nice(node):
481 return '%d:%s' % (repo.changelog.rev(node), short(node))
481 return '%d:%s' % (repo.changelog.rev(node), short(node))
482 ui.status(_('changeset %s backs out changeset %s\n') %
482 ui.status(_('changeset %s backs out changeset %s\n') %
483 (nice(repo.changelog.tip()), nice(node)))
483 (nice(repo.changelog.tip()), nice(node)))
484 if opts.get('merge') and op1 != node:
484 if opts.get('merge') and op1 != node:
485 hg.clean(repo, op1, show_stats=False)
485 hg.clean(repo, op1, show_stats=False)
486 ui.status(_('merging with changeset %s\n')
486 ui.status(_('merging with changeset %s\n')
487 % nice(repo.changelog.tip()))
487 % nice(repo.changelog.tip()))
488 try:
488 try:
489 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
489 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
490 return hg.merge(repo, hex(repo.changelog.tip()))
490 return hg.merge(repo, hex(repo.changelog.tip()))
491 finally:
491 finally:
492 ui.setconfig('ui', 'forcemerge', '')
492 ui.setconfig('ui', 'forcemerge', '')
493 finally:
493 finally:
494 wlock.release()
494 wlock.release()
495 return 0
495 return 0
496
496
497 @command('bisect',
497 @command('bisect',
498 [('r', 'reset', False, _('reset bisect state')),
498 [('r', 'reset', False, _('reset bisect state')),
499 ('g', 'good', False, _('mark changeset good')),
499 ('g', 'good', False, _('mark changeset good')),
500 ('b', 'bad', False, _('mark changeset bad')),
500 ('b', 'bad', False, _('mark changeset bad')),
501 ('s', 'skip', False, _('skip testing changeset')),
501 ('s', 'skip', False, _('skip testing changeset')),
502 ('e', 'extend', False, _('extend the bisect range')),
502 ('e', 'extend', False, _('extend the bisect range')),
503 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
503 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
504 ('U', 'noupdate', False, _('do not update to target'))],
504 ('U', 'noupdate', False, _('do not update to target'))],
505 _("[-gbsr] [-U] [-c CMD] [REV]"))
505 _("[-gbsr] [-U] [-c CMD] [REV]"))
506 def bisect(ui, repo, rev=None, extra=None, command=None,
506 def bisect(ui, repo, rev=None, extra=None, command=None,
507 reset=None, good=None, bad=None, skip=None, extend=None,
507 reset=None, good=None, bad=None, skip=None, extend=None,
508 noupdate=None):
508 noupdate=None):
509 """subdivision search of changesets
509 """subdivision search of changesets
510
510
511 This command helps to find changesets which introduce problems. To
511 This command helps to find changesets which introduce problems. To
512 use, mark the earliest changeset you know exhibits the problem as
512 use, mark the earliest changeset you know exhibits the problem as
513 bad, then mark the latest changeset which is free from the problem
513 bad, then mark the latest changeset which is free from the problem
514 as good. Bisect will update your working directory to a revision
514 as good. Bisect will update your working directory to a revision
515 for testing (unless the -U/--noupdate option is specified). Once
515 for testing (unless the -U/--noupdate option is specified). Once
516 you have performed tests, mark the working directory as good or
516 you have performed tests, mark the working directory as good or
517 bad, and bisect will either update to another candidate changeset
517 bad, and bisect will either update to another candidate changeset
518 or announce that it has found the bad revision.
518 or announce that it has found the bad revision.
519
519
520 As a shortcut, you can also use the revision argument to mark a
520 As a shortcut, you can also use the revision argument to mark a
521 revision as good or bad without checking it out first.
521 revision as good or bad without checking it out first.
522
522
523 If you supply a command, it will be used for automatic bisection.
523 If you supply a command, it will be used for automatic bisection.
524 The environment variable HG_NODE will contain the ID of the
524 The environment variable HG_NODE will contain the ID of the
525 changeset being tested. The exit status of the command will be
525 changeset being tested. The exit status of the command will be
526 used to mark revisions as good or bad: status 0 means good, 125
526 used to mark revisions as good or bad: status 0 means good, 125
527 means to skip the revision, 127 (command not found) will abort the
527 means to skip the revision, 127 (command not found) will abort the
528 bisection, and any other non-zero exit status means the revision
528 bisection, and any other non-zero exit status means the revision
529 is bad.
529 is bad.
530
530
531 .. container:: verbose
531 .. container:: verbose
532
532
533 Some examples:
533 Some examples:
534
534
535 - start a bisection with known bad revision 12, and good revision 34::
535 - start a bisection with known bad revision 12, and good revision 34::
536
536
537 hg bisect --bad 34
537 hg bisect --bad 34
538 hg bisect --good 12
538 hg bisect --good 12
539
539
540 - advance the current bisection by marking current revision as good or
540 - advance the current bisection by marking current revision as good or
541 bad::
541 bad::
542
542
543 hg bisect --good
543 hg bisect --good
544 hg bisect --bad
544 hg bisect --bad
545
545
546 - mark the current revision, or a known revision, to be skipped (e.g. if
546 - mark the current revision, or a known revision, to be skipped (e.g. if
547 that revision is not usable because of another issue)::
547 that revision is not usable because of another issue)::
548
548
549 hg bisect --skip
549 hg bisect --skip
550 hg bisect --skip 23
550 hg bisect --skip 23
551
551
552 - forget the current bisection::
552 - forget the current bisection::
553
553
554 hg bisect --reset
554 hg bisect --reset
555
555
556 - use 'make && make tests' to automatically find the first broken
556 - use 'make && make tests' to automatically find the first broken
557 revision::
557 revision::
558
558
559 hg bisect --reset
559 hg bisect --reset
560 hg bisect --bad 34
560 hg bisect --bad 34
561 hg bisect --good 12
561 hg bisect --good 12
562 hg bisect --command 'make && make tests'
562 hg bisect --command 'make && make tests'
563
563
564 - see all changesets whose states are already known in the current
564 - see all changesets whose states are already known in the current
565 bisection::
565 bisection::
566
566
567 hg log -r "bisect(pruned)"
567 hg log -r "bisect(pruned)"
568
568
569 - see the changeset currently being bisected (especially useful
569 - see the changeset currently being bisected (especially useful
570 if running with -U/--noupdate)::
570 if running with -U/--noupdate)::
571
571
572 hg log -r "bisect(current)"
572 hg log -r "bisect(current)"
573
573
574 - see all changesets that took part in the current bisection::
574 - see all changesets that took part in the current bisection::
575
575
576 hg log -r "bisect(range)"
576 hg log -r "bisect(range)"
577
577
578 - with the graphlog extension, you can even get a nice graph::
578 - with the graphlog extension, you can even get a nice graph::
579
579
580 hg log --graph -r "bisect(range)"
580 hg log --graph -r "bisect(range)"
581
581
582 See :hg:`help revsets` for more about the `bisect()` keyword.
582 See :hg:`help revsets` for more about the `bisect()` keyword.
583
583
584 Returns 0 on success.
584 Returns 0 on success.
585 """
585 """
586 def extendbisectrange(nodes, good):
586 def extendbisectrange(nodes, good):
587 # bisect is incomplete when it ends on a merge node and
587 # bisect is incomplete when it ends on a merge node and
588 # one of the parent was not checked.
588 # one of the parent was not checked.
589 parents = repo[nodes[0]].parents()
589 parents = repo[nodes[0]].parents()
590 if len(parents) > 1:
590 if len(parents) > 1:
591 side = good and state['bad'] or state['good']
591 side = good and state['bad'] or state['good']
592 num = len(set(i.node() for i in parents) & set(side))
592 num = len(set(i.node() for i in parents) & set(side))
593 if num == 1:
593 if num == 1:
594 return parents[0].ancestor(parents[1])
594 return parents[0].ancestor(parents[1])
595 return None
595 return None
596
596
597 def print_result(nodes, good):
597 def print_result(nodes, good):
598 displayer = cmdutil.show_changeset(ui, repo, {})
598 displayer = cmdutil.show_changeset(ui, repo, {})
599 if len(nodes) == 1:
599 if len(nodes) == 1:
600 # narrowed it down to a single revision
600 # narrowed it down to a single revision
601 if good:
601 if good:
602 ui.write(_("The first good revision is:\n"))
602 ui.write(_("The first good revision is:\n"))
603 else:
603 else:
604 ui.write(_("The first bad revision is:\n"))
604 ui.write(_("The first bad revision is:\n"))
605 displayer.show(repo[nodes[0]])
605 displayer.show(repo[nodes[0]])
606 extendnode = extendbisectrange(nodes, good)
606 extendnode = extendbisectrange(nodes, good)
607 if extendnode is not None:
607 if extendnode is not None:
608 ui.write(_('Not all ancestors of this changeset have been'
608 ui.write(_('Not all ancestors of this changeset have been'
609 ' checked.\nUse bisect --extend to continue the '
609 ' checked.\nUse bisect --extend to continue the '
610 'bisection from\nthe common ancestor, %s.\n')
610 'bisection from\nthe common ancestor, %s.\n')
611 % extendnode)
611 % extendnode)
612 else:
612 else:
613 # multiple possible revisions
613 # multiple possible revisions
614 if good:
614 if good:
615 ui.write(_("Due to skipped revisions, the first "
615 ui.write(_("Due to skipped revisions, the first "
616 "good revision could be any of:\n"))
616 "good revision could be any of:\n"))
617 else:
617 else:
618 ui.write(_("Due to skipped revisions, the first "
618 ui.write(_("Due to skipped revisions, the first "
619 "bad revision could be any of:\n"))
619 "bad revision could be any of:\n"))
620 for n in nodes:
620 for n in nodes:
621 displayer.show(repo[n])
621 displayer.show(repo[n])
622 displayer.close()
622 displayer.close()
623
623
624 def check_state(state, interactive=True):
624 def check_state(state, interactive=True):
625 if not state['good'] or not state['bad']:
625 if not state['good'] or not state['bad']:
626 if (good or bad or skip or reset) and interactive:
626 if (good or bad or skip or reset) and interactive:
627 return
627 return
628 if not state['good']:
628 if not state['good']:
629 raise util.Abort(_('cannot bisect (no known good revisions)'))
629 raise util.Abort(_('cannot bisect (no known good revisions)'))
630 else:
630 else:
631 raise util.Abort(_('cannot bisect (no known bad revisions)'))
631 raise util.Abort(_('cannot bisect (no known bad revisions)'))
632 return True
632 return True
633
633
634 # backward compatibility
634 # backward compatibility
635 if rev in "good bad reset init".split():
635 if rev in "good bad reset init".split():
636 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
636 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
637 cmd, rev, extra = rev, extra, None
637 cmd, rev, extra = rev, extra, None
638 if cmd == "good":
638 if cmd == "good":
639 good = True
639 good = True
640 elif cmd == "bad":
640 elif cmd == "bad":
641 bad = True
641 bad = True
642 else:
642 else:
643 reset = True
643 reset = True
644 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
644 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
645 raise util.Abort(_('incompatible arguments'))
645 raise util.Abort(_('incompatible arguments'))
646
646
647 if reset:
647 if reset:
648 p = repo.join("bisect.state")
648 p = repo.join("bisect.state")
649 if os.path.exists(p):
649 if os.path.exists(p):
650 os.unlink(p)
650 os.unlink(p)
651 return
651 return
652
652
653 state = hbisect.load_state(repo)
653 state = hbisect.load_state(repo)
654
654
655 if command:
655 if command:
656 changesets = 1
656 changesets = 1
657 try:
657 try:
658 node = state['current'][0]
658 node = state['current'][0]
659 except LookupError:
659 except LookupError:
660 if noupdate:
660 if noupdate:
661 raise util.Abort(_('current bisect revision is unknown - '
661 raise util.Abort(_('current bisect revision is unknown - '
662 'start a new bisect to fix'))
662 'start a new bisect to fix'))
663 node, p2 = repo.dirstate.parents()
663 node, p2 = repo.dirstate.parents()
664 if p2 != nullid:
664 if p2 != nullid:
665 raise util.Abort(_('current bisect revision is a merge'))
665 raise util.Abort(_('current bisect revision is a merge'))
666 try:
666 try:
667 while changesets:
667 while changesets:
668 # update state
668 # update state
669 state['current'] = [node]
669 state['current'] = [node]
670 hbisect.save_state(repo, state)
670 hbisect.save_state(repo, state)
671 status = util.system(command,
671 status = util.system(command,
672 environ={'HG_NODE': hex(node)},
672 environ={'HG_NODE': hex(node)},
673 out=ui.fout)
673 out=ui.fout)
674 if status == 125:
674 if status == 125:
675 transition = "skip"
675 transition = "skip"
676 elif status == 0:
676 elif status == 0:
677 transition = "good"
677 transition = "good"
678 # status < 0 means process was killed
678 # status < 0 means process was killed
679 elif status == 127:
679 elif status == 127:
680 raise util.Abort(_("failed to execute %s") % command)
680 raise util.Abort(_("failed to execute %s") % command)
681 elif status < 0:
681 elif status < 0:
682 raise util.Abort(_("%s killed") % command)
682 raise util.Abort(_("%s killed") % command)
683 else:
683 else:
684 transition = "bad"
684 transition = "bad"
685 ctx = scmutil.revsingle(repo, rev, node)
685 ctx = scmutil.revsingle(repo, rev, node)
686 rev = None # clear for future iterations
686 rev = None # clear for future iterations
687 state[transition].append(ctx.node())
687 state[transition].append(ctx.node())
688 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
688 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
689 check_state(state, interactive=False)
689 check_state(state, interactive=False)
690 # bisect
690 # bisect
691 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
691 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
692 # update to next check
692 # update to next check
693 node = nodes[0]
693 node = nodes[0]
694 if not noupdate:
694 if not noupdate:
695 cmdutil.bailifchanged(repo)
695 cmdutil.bailifchanged(repo)
696 hg.clean(repo, node, show_stats=False)
696 hg.clean(repo, node, show_stats=False)
697 finally:
697 finally:
698 state['current'] = [node]
698 state['current'] = [node]
699 hbisect.save_state(repo, state)
699 hbisect.save_state(repo, state)
700 print_result(nodes, good)
700 print_result(nodes, good)
701 return
701 return
702
702
703 # update state
703 # update state
704
704
705 if rev:
705 if rev:
706 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
706 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
707 else:
707 else:
708 nodes = [repo.lookup('.')]
708 nodes = [repo.lookup('.')]
709
709
710 if good or bad or skip:
710 if good or bad or skip:
711 if good:
711 if good:
712 state['good'] += nodes
712 state['good'] += nodes
713 elif bad:
713 elif bad:
714 state['bad'] += nodes
714 state['bad'] += nodes
715 elif skip:
715 elif skip:
716 state['skip'] += nodes
716 state['skip'] += nodes
717 hbisect.save_state(repo, state)
717 hbisect.save_state(repo, state)
718
718
719 if not check_state(state):
719 if not check_state(state):
720 return
720 return
721
721
722 # actually bisect
722 # actually bisect
723 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
723 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
724 if extend:
724 if extend:
725 if not changesets:
725 if not changesets:
726 extendnode = extendbisectrange(nodes, good)
726 extendnode = extendbisectrange(nodes, good)
727 if extendnode is not None:
727 if extendnode is not None:
728 ui.write(_("Extending search to changeset %d:%s\n"
728 ui.write(_("Extending search to changeset %d:%s\n"
729 % (extendnode.rev(), extendnode)))
729 % (extendnode.rev(), extendnode)))
730 state['current'] = [extendnode.node()]
730 state['current'] = [extendnode.node()]
731 hbisect.save_state(repo, state)
731 hbisect.save_state(repo, state)
732 if noupdate:
732 if noupdate:
733 return
733 return
734 cmdutil.bailifchanged(repo)
734 cmdutil.bailifchanged(repo)
735 return hg.clean(repo, extendnode.node())
735 return hg.clean(repo, extendnode.node())
736 raise util.Abort(_("nothing to extend"))
736 raise util.Abort(_("nothing to extend"))
737
737
738 if changesets == 0:
738 if changesets == 0:
739 print_result(nodes, good)
739 print_result(nodes, good)
740 else:
740 else:
741 assert len(nodes) == 1 # only a single node can be tested next
741 assert len(nodes) == 1 # only a single node can be tested next
742 node = nodes[0]
742 node = nodes[0]
743 # compute the approximate number of remaining tests
743 # compute the approximate number of remaining tests
744 tests, size = 0, 2
744 tests, size = 0, 2
745 while size <= changesets:
745 while size <= changesets:
746 tests, size = tests + 1, size * 2
746 tests, size = tests + 1, size * 2
747 rev = repo.changelog.rev(node)
747 rev = repo.changelog.rev(node)
748 ui.write(_("Testing changeset %d:%s "
748 ui.write(_("Testing changeset %d:%s "
749 "(%d changesets remaining, ~%d tests)\n")
749 "(%d changesets remaining, ~%d tests)\n")
750 % (rev, short(node), changesets, tests))
750 % (rev, short(node), changesets, tests))
751 state['current'] = [node]
751 state['current'] = [node]
752 hbisect.save_state(repo, state)
752 hbisect.save_state(repo, state)
753 if not noupdate:
753 if not noupdate:
754 cmdutil.bailifchanged(repo)
754 cmdutil.bailifchanged(repo)
755 return hg.clean(repo, node)
755 return hg.clean(repo, node)
756
756
757 @command('bookmarks',
757 @command('bookmarks',
758 [('f', 'force', False, _('force')),
758 [('f', 'force', False, _('force')),
759 ('r', 'rev', '', _('revision'), _('REV')),
759 ('r', 'rev', '', _('revision'), _('REV')),
760 ('d', 'delete', False, _('delete a given bookmark')),
760 ('d', 'delete', False, _('delete a given bookmark')),
761 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
761 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
762 ('i', 'inactive', False, _('mark a bookmark inactive'))],
762 ('i', 'inactive', False, _('mark a bookmark inactive'))],
763 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
763 _('hg bookmarks [-f] [-d] [-i] [-m NAME] [-r REV] [NAME]'))
764 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
764 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False,
765 rename=None, inactive=False):
765 rename=None, inactive=False):
766 '''track a line of development with movable markers
766 '''track a line of development with movable markers
767
767
768 Bookmarks are pointers to certain commits that move when committing.
768 Bookmarks are pointers to certain commits that move when committing.
769 Bookmarks are local. They can be renamed, copied and deleted. It is
769 Bookmarks are local. They can be renamed, copied and deleted. It is
770 possible to use :hg:`merge NAME` to merge from a given bookmark, and
770 possible to use :hg:`merge NAME` to merge from a given bookmark, and
771 :hg:`update NAME` to update to a given bookmark.
771 :hg:`update NAME` to update to a given bookmark.
772
772
773 You can use :hg:`bookmark NAME` to set a bookmark on the working
773 You can use :hg:`bookmark NAME` to set a bookmark on the working
774 directory's parent revision with the given name. If you specify
774 directory's parent revision with the given name. If you specify
775 a revision using -r REV (where REV may be an existing bookmark),
775 a revision using -r REV (where REV may be an existing bookmark),
776 the bookmark is assigned to that revision.
776 the bookmark is assigned to that revision.
777
777
778 Bookmarks can be pushed and pulled between repositories (see :hg:`help
778 Bookmarks can be pushed and pulled between repositories (see :hg:`help
779 push` and :hg:`help pull`). This requires both the local and remote
779 push` and :hg:`help pull`). This requires both the local and remote
780 repositories to support bookmarks. For versions prior to 1.8, this means
780 repositories to support bookmarks. For versions prior to 1.8, this means
781 the bookmarks extension must be enabled.
781 the bookmarks extension must be enabled.
782
782
783 With -i/--inactive, the new bookmark will not be made the active
783 With -i/--inactive, the new bookmark will not be made the active
784 bookmark. If -r/--rev is given, the new bookmark will not be made
784 bookmark. If -r/--rev is given, the new bookmark will not be made
785 active even if -i/--inactive is not given. If no NAME is given, the
785 active even if -i/--inactive is not given. If no NAME is given, the
786 current active bookmark will be marked inactive.
786 current active bookmark will be marked inactive.
787 '''
787 '''
788 hexfn = ui.debugflag and hex or short
788 hexfn = ui.debugflag and hex or short
789 marks = repo._bookmarks
789 marks = repo._bookmarks
790 cur = repo.changectx('.').node()
790 cur = repo.changectx('.').node()
791
791
792 def checkformat(mark):
792 def checkformat(mark):
793 if "\n" in mark:
793 if "\n" in mark:
794 raise util.Abort(_("bookmark name cannot contain newlines"))
794 raise util.Abort(_("bookmark name cannot contain newlines"))
795 mark = mark.strip()
795 mark = mark.strip()
796 if not mark:
796 if not mark:
797 raise util.Abort(_("bookmark names cannot consist entirely of "
797 raise util.Abort(_("bookmark names cannot consist entirely of "
798 "whitespace"))
798 "whitespace"))
799 return mark
799 return mark
800
800
801 def checkconflict(repo, mark, force=False):
801 def checkconflict(repo, mark, force=False):
802 if mark in marks and not force:
802 if mark in marks and not force:
803 raise util.Abort(_("bookmark '%s' already exists "
803 raise util.Abort(_("bookmark '%s' already exists "
804 "(use -f to force)") % mark)
804 "(use -f to force)") % mark)
805 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
805 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
806 and not force):
806 and not force):
807 raise util.Abort(
807 raise util.Abort(
808 _("a bookmark cannot have the name of an existing branch"))
808 _("a bookmark cannot have the name of an existing branch"))
809
809
810 if delete and rename:
810 if delete and rename:
811 raise util.Abort(_("--delete and --rename are incompatible"))
811 raise util.Abort(_("--delete and --rename are incompatible"))
812 if delete and rev:
812 if delete and rev:
813 raise util.Abort(_("--rev is incompatible with --delete"))
813 raise util.Abort(_("--rev is incompatible with --delete"))
814 if rename and rev:
814 if rename and rev:
815 raise util.Abort(_("--rev is incompatible with --rename"))
815 raise util.Abort(_("--rev is incompatible with --rename"))
816 if mark is None and (delete or rev):
816 if mark is None and (delete or rev):
817 raise util.Abort(_("bookmark name required"))
817 raise util.Abort(_("bookmark name required"))
818
818
819 if delete:
819 if delete:
820 if mark not in marks:
820 if mark not in marks:
821 raise util.Abort(_("bookmark '%s' does not exist") % mark)
821 raise util.Abort(_("bookmark '%s' does not exist") % mark)
822 if mark == repo._bookmarkcurrent:
822 if mark == repo._bookmarkcurrent:
823 bookmarks.setcurrent(repo, None)
823 bookmarks.setcurrent(repo, None)
824 del marks[mark]
824 del marks[mark]
825 bookmarks.write(repo)
825 bookmarks.write(repo)
826
826
827 elif rename:
827 elif rename:
828 if mark is None:
828 if mark is None:
829 raise util.Abort(_("new bookmark name required"))
829 raise util.Abort(_("new bookmark name required"))
830 mark = checkformat(mark)
830 mark = checkformat(mark)
831 if rename not in marks:
831 if rename not in marks:
832 raise util.Abort(_("bookmark '%s' does not exist") % rename)
832 raise util.Abort(_("bookmark '%s' does not exist") % rename)
833 checkconflict(repo, mark, force)
833 checkconflict(repo, mark, force)
834 marks[mark] = marks[rename]
834 marks[mark] = marks[rename]
835 if repo._bookmarkcurrent == rename and not inactive:
835 if repo._bookmarkcurrent == rename and not inactive:
836 bookmarks.setcurrent(repo, mark)
836 bookmarks.setcurrent(repo, mark)
837 del marks[rename]
837 del marks[rename]
838 bookmarks.write(repo)
838 bookmarks.write(repo)
839
839
840 elif mark is not None:
840 elif mark is not None:
841 mark = checkformat(mark)
841 mark = checkformat(mark)
842 if inactive and mark == repo._bookmarkcurrent:
842 if inactive and mark == repo._bookmarkcurrent:
843 bookmarks.setcurrent(repo, None)
843 bookmarks.setcurrent(repo, None)
844 return
844 return
845 checkconflict(repo, mark, force)
845 checkconflict(repo, mark, force)
846 if rev:
846 if rev:
847 marks[mark] = scmutil.revsingle(repo, rev).node()
847 marks[mark] = scmutil.revsingle(repo, rev).node()
848 else:
848 else:
849 marks[mark] = cur
849 marks[mark] = cur
850 if not inactive and cur == marks[mark]:
850 if not inactive and cur == marks[mark]:
851 bookmarks.setcurrent(repo, mark)
851 bookmarks.setcurrent(repo, mark)
852 bookmarks.write(repo)
852 bookmarks.write(repo)
853 return
853 return
854
854
855 else: # mark is None
855 else: # mark is None
856 if len(marks) == 0:
856 if len(marks) == 0:
857 ui.status(_("no bookmarks set\n"))
857 ui.status(_("no bookmarks set\n"))
858 elif inactive:
858 elif inactive:
859 if not repo._bookmarkcurrent:
859 if not repo._bookmarkcurrent:
860 ui.status(_("no active bookmark\n"))
860 ui.status(_("no active bookmark\n"))
861 else:
861 else:
862 bookmarks.setcurrent(repo, None)
862 bookmarks.setcurrent(repo, None)
863 else:
863 else:
864 for bmark, n in sorted(marks.iteritems()):
864 for bmark, n in sorted(marks.iteritems()):
865 current = repo._bookmarkcurrent
865 current = repo._bookmarkcurrent
866 if bmark == current and n == cur:
866 if bmark == current and n == cur:
867 prefix, label = '*', 'bookmarks.current'
867 prefix, label = '*', 'bookmarks.current'
868 else:
868 else:
869 prefix, label = ' ', ''
869 prefix, label = ' ', ''
870
870
871 if ui.quiet:
871 if ui.quiet:
872 ui.write("%s\n" % bmark, label=label)
872 ui.write("%s\n" % bmark, label=label)
873 else:
873 else:
874 ui.write(" %s %-25s %d:%s\n" % (
874 ui.write(" %s %-25s %d:%s\n" % (
875 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
875 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
876 label=label)
876 label=label)
877
877
878 @command('branch',
878 @command('branch',
879 [('f', 'force', None,
879 [('f', 'force', None,
880 _('set branch name even if it shadows an existing branch')),
880 _('set branch name even if it shadows an existing branch')),
881 ('C', 'clean', None, _('reset branch name to parent branch name'))],
881 ('C', 'clean', None, _('reset branch name to parent branch name'))],
882 _('[-fC] [NAME]'))
882 _('[-fC] [NAME]'))
883 def branch(ui, repo, label=None, **opts):
883 def branch(ui, repo, label=None, **opts):
884 """set or show the current branch name
884 """set or show the current branch name
885
885
886 .. note::
886 .. note::
887 Branch names are permanent and global. Use :hg:`bookmark` to create a
887 Branch names are permanent and global. Use :hg:`bookmark` to create a
888 light-weight bookmark instead. See :hg:`help glossary` for more
888 light-weight bookmark instead. See :hg:`help glossary` for more
889 information about named branches and bookmarks.
889 information about named branches and bookmarks.
890
890
891 With no argument, show the current branch name. With one argument,
891 With no argument, show the current branch name. With one argument,
892 set the working directory branch name (the branch will not exist
892 set the working directory branch name (the branch will not exist
893 in the repository until the next commit). Standard practice
893 in the repository until the next commit). Standard practice
894 recommends that primary development take place on the 'default'
894 recommends that primary development take place on the 'default'
895 branch.
895 branch.
896
896
897 Unless -f/--force is specified, branch will not let you set a
897 Unless -f/--force is specified, branch will not let you set a
898 branch name that already exists, even if it's inactive.
898 branch name that already exists, even if it's inactive.
899
899
900 Use -C/--clean to reset the working directory branch to that of
900 Use -C/--clean to reset the working directory branch to that of
901 the parent of the working directory, negating a previous branch
901 the parent of the working directory, negating a previous branch
902 change.
902 change.
903
903
904 Use the command :hg:`update` to switch to an existing branch. Use
904 Use the command :hg:`update` to switch to an existing branch. Use
905 :hg:`commit --close-branch` to mark this branch as closed.
905 :hg:`commit --close-branch` to mark this branch as closed.
906
906
907 Returns 0 on success.
907 Returns 0 on success.
908 """
908 """
909 if not opts.get('clean') and not label:
909 if not opts.get('clean') and not label:
910 ui.write("%s\n" % repo.dirstate.branch())
910 ui.write("%s\n" % repo.dirstate.branch())
911 return
911 return
912
912
913 wlock = repo.wlock()
913 wlock = repo.wlock()
914 try:
914 try:
915 if opts.get('clean'):
915 if opts.get('clean'):
916 label = repo[None].p1().branch()
916 label = repo[None].p1().branch()
917 repo.dirstate.setbranch(label)
917 repo.dirstate.setbranch(label)
918 ui.status(_('reset working directory to branch %s\n') % label)
918 ui.status(_('reset working directory to branch %s\n') % label)
919 elif label:
919 elif label:
920 if not opts.get('force') and label in repo.branchmap():
920 if not opts.get('force') and label in repo.branchmap():
921 if label not in [p.branch() for p in repo.parents()]:
921 if label not in [p.branch() for p in repo.parents()]:
922 raise util.Abort(_('a branch of the same name already'
922 raise util.Abort(_('a branch of the same name already'
923 ' exists'),
923 ' exists'),
924 # i18n: "it" refers to an existing branch
924 # i18n: "it" refers to an existing branch
925 hint=_("use 'hg update' to switch to it"))
925 hint=_("use 'hg update' to switch to it"))
926 repo.dirstate.setbranch(label)
926 repo.dirstate.setbranch(label)
927 ui.status(_('marked working directory as branch %s\n') % label)
927 ui.status(_('marked working directory as branch %s\n') % label)
928 ui.status(_('(branches are permanent and global, '
928 ui.status(_('(branches are permanent and global, '
929 'did you want a bookmark?)\n'))
929 'did you want a bookmark?)\n'))
930 finally:
930 finally:
931 wlock.release()
931 wlock.release()
932
932
933 @command('branches',
933 @command('branches',
934 [('a', 'active', False, _('show only branches that have unmerged heads')),
934 [('a', 'active', False, _('show only branches that have unmerged heads')),
935 ('c', 'closed', False, _('show normal and closed branches'))],
935 ('c', 'closed', False, _('show normal and closed branches'))],
936 _('[-ac]'))
936 _('[-ac]'))
937 def branches(ui, repo, active=False, closed=False):
937 def branches(ui, repo, active=False, closed=False):
938 """list repository named branches
938 """list repository named branches
939
939
940 List the repository's named branches, indicating which ones are
940 List the repository's named branches, indicating which ones are
941 inactive. If -c/--closed is specified, also list branches which have
941 inactive. If -c/--closed is specified, also list branches which have
942 been marked closed (see :hg:`commit --close-branch`).
942 been marked closed (see :hg:`commit --close-branch`).
943
943
944 If -a/--active is specified, only show active branches. A branch
944 If -a/--active is specified, only show active branches. A branch
945 is considered active if it contains repository heads.
945 is considered active if it contains repository heads.
946
946
947 Use the command :hg:`update` to switch to an existing branch.
947 Use the command :hg:`update` to switch to an existing branch.
948
948
949 Returns 0.
949 Returns 0.
950 """
950 """
951
951
952 hexfunc = ui.debugflag and hex or short
952 hexfunc = ui.debugflag and hex or short
953
953
954 activebranches = set([repo[n].branch() for n in repo.heads()])
954 activebranches = set([repo[n].branch() for n in repo.heads()])
955 branches = []
955 branches = []
956 for tag, heads in repo.branchmap().iteritems():
956 for tag, heads in repo.branchmap().iteritems():
957 for h in reversed(heads):
957 for h in reversed(heads):
958 ctx = repo[h]
958 ctx = repo[h]
959 isopen = not ctx.closesbranch()
959 isopen = not ctx.closesbranch()
960 if isopen:
960 if isopen:
961 tip = ctx
961 tip = ctx
962 break
962 break
963 else:
963 else:
964 tip = repo[heads[-1]]
964 tip = repo[heads[-1]]
965 isactive = tag in activebranches and isopen
965 isactive = tag in activebranches and isopen
966 branches.append((tip, isactive, isopen))
966 branches.append((tip, isactive, isopen))
967 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
967 branches.sort(key=lambda i: (i[1], i[0].rev(), i[0].branch(), i[2]),
968 reverse=True)
968 reverse=True)
969
969
970 for ctx, isactive, isopen in branches:
970 for ctx, isactive, isopen in branches:
971 if (not active) or isactive:
971 if (not active) or isactive:
972 if isactive:
972 if isactive:
973 label = 'branches.active'
973 label = 'branches.active'
974 notice = ''
974 notice = ''
975 elif not isopen:
975 elif not isopen:
976 if not closed:
976 if not closed:
977 continue
977 continue
978 label = 'branches.closed'
978 label = 'branches.closed'
979 notice = _(' (closed)')
979 notice = _(' (closed)')
980 else:
980 else:
981 label = 'branches.inactive'
981 label = 'branches.inactive'
982 notice = _(' (inactive)')
982 notice = _(' (inactive)')
983 if ctx.branch() == repo.dirstate.branch():
983 if ctx.branch() == repo.dirstate.branch():
984 label = 'branches.current'
984 label = 'branches.current'
985 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
985 rev = str(ctx.rev()).rjust(31 - encoding.colwidth(ctx.branch()))
986 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
986 rev = ui.label('%s:%s' % (rev, hexfunc(ctx.node())),
987 'log.changeset changeset.%s' % ctx.phasestr())
987 'log.changeset changeset.%s' % ctx.phasestr())
988 tag = ui.label(ctx.branch(), label)
988 tag = ui.label(ctx.branch(), label)
989 if ui.quiet:
989 if ui.quiet:
990 ui.write("%s\n" % tag)
990 ui.write("%s\n" % tag)
991 else:
991 else:
992 ui.write("%s %s%s\n" % (tag, rev, notice))
992 ui.write("%s %s%s\n" % (tag, rev, notice))
993
993
994 @command('bundle',
994 @command('bundle',
995 [('f', 'force', None, _('run even when the destination is unrelated')),
995 [('f', 'force', None, _('run even when the destination is unrelated')),
996 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
996 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
997 _('REV')),
997 _('REV')),
998 ('b', 'branch', [], _('a specific branch you would like to bundle'),
998 ('b', 'branch', [], _('a specific branch you would like to bundle'),
999 _('BRANCH')),
999 _('BRANCH')),
1000 ('', 'base', [],
1000 ('', 'base', [],
1001 _('a base changeset assumed to be available at the destination'),
1001 _('a base changeset assumed to be available at the destination'),
1002 _('REV')),
1002 _('REV')),
1003 ('a', 'all', None, _('bundle all changesets in the repository')),
1003 ('a', 'all', None, _('bundle all changesets in the repository')),
1004 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1004 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1005 ] + remoteopts,
1005 ] + remoteopts,
1006 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1006 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1007 def bundle(ui, repo, fname, dest=None, **opts):
1007 def bundle(ui, repo, fname, dest=None, **opts):
1008 """create a changegroup file
1008 """create a changegroup file
1009
1009
1010 Generate a compressed changegroup file collecting changesets not
1010 Generate a compressed changegroup file collecting changesets not
1011 known to be in another repository.
1011 known to be in another repository.
1012
1012
1013 If you omit the destination repository, then hg assumes the
1013 If you omit the destination repository, then hg assumes the
1014 destination will have all the nodes you specify with --base
1014 destination will have all the nodes you specify with --base
1015 parameters. To create a bundle containing all changesets, use
1015 parameters. To create a bundle containing all changesets, use
1016 -a/--all (or --base null).
1016 -a/--all (or --base null).
1017
1017
1018 You can change compression method with the -t/--type option.
1018 You can change compression method with the -t/--type option.
1019 The available compression methods are: none, bzip2, and
1019 The available compression methods are: none, bzip2, and
1020 gzip (by default, bundles are compressed using bzip2).
1020 gzip (by default, bundles are compressed using bzip2).
1021
1021
1022 The bundle file can then be transferred using conventional means
1022 The bundle file can then be transferred using conventional means
1023 and applied to another repository with the unbundle or pull
1023 and applied to another repository with the unbundle or pull
1024 command. This is useful when direct push and pull are not
1024 command. This is useful when direct push and pull are not
1025 available or when exporting an entire repository is undesirable.
1025 available or when exporting an entire repository is undesirable.
1026
1026
1027 Applying bundles preserves all changeset contents including
1027 Applying bundles preserves all changeset contents including
1028 permissions, copy/rename information, and revision history.
1028 permissions, copy/rename information, and revision history.
1029
1029
1030 Returns 0 on success, 1 if no changes found.
1030 Returns 0 on success, 1 if no changes found.
1031 """
1031 """
1032 revs = None
1032 revs = None
1033 if 'rev' in opts:
1033 if 'rev' in opts:
1034 revs = scmutil.revrange(repo, opts['rev'])
1034 revs = scmutil.revrange(repo, opts['rev'])
1035
1035
1036 bundletype = opts.get('type', 'bzip2').lower()
1036 bundletype = opts.get('type', 'bzip2').lower()
1037 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1037 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1038 bundletype = btypes.get(bundletype)
1038 bundletype = btypes.get(bundletype)
1039 if bundletype not in changegroup.bundletypes:
1039 if bundletype not in changegroup.bundletypes:
1040 raise util.Abort(_('unknown bundle type specified with --type'))
1040 raise util.Abort(_('unknown bundle type specified with --type'))
1041
1041
1042 if opts.get('all'):
1042 if opts.get('all'):
1043 base = ['null']
1043 base = ['null']
1044 else:
1044 else:
1045 base = scmutil.revrange(repo, opts.get('base'))
1045 base = scmutil.revrange(repo, opts.get('base'))
1046 if base:
1046 if base:
1047 if dest:
1047 if dest:
1048 raise util.Abort(_("--base is incompatible with specifying "
1048 raise util.Abort(_("--base is incompatible with specifying "
1049 "a destination"))
1049 "a destination"))
1050 common = [repo.lookup(rev) for rev in base]
1050 common = [repo.lookup(rev) for rev in base]
1051 heads = revs and map(repo.lookup, revs) or revs
1051 heads = revs and map(repo.lookup, revs) or revs
1052 cg = repo.getbundle('bundle', heads=heads, common=common)
1052 cg = repo.getbundle('bundle', heads=heads, common=common)
1053 outgoing = None
1053 outgoing = None
1054 else:
1054 else:
1055 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1055 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1056 dest, branches = hg.parseurl(dest, opts.get('branch'))
1056 dest, branches = hg.parseurl(dest, opts.get('branch'))
1057 other = hg.peer(repo, opts, dest)
1057 other = hg.peer(repo, opts, dest)
1058 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1058 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
1059 heads = revs and map(repo.lookup, revs) or revs
1059 heads = revs and map(repo.lookup, revs) or revs
1060 outgoing = discovery.findcommonoutgoing(repo, other,
1060 outgoing = discovery.findcommonoutgoing(repo, other,
1061 onlyheads=heads,
1061 onlyheads=heads,
1062 force=opts.get('force'),
1062 force=opts.get('force'),
1063 portable=True)
1063 portable=True)
1064 cg = repo.getlocalbundle('bundle', outgoing)
1064 cg = repo.getlocalbundle('bundle', outgoing)
1065 if not cg:
1065 if not cg:
1066 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1066 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1067 return 1
1067 return 1
1068
1068
1069 changegroup.writebundle(cg, fname, bundletype)
1069 changegroup.writebundle(cg, fname, bundletype)
1070
1070
1071 @command('cat',
1071 @command('cat',
1072 [('o', 'output', '',
1072 [('o', 'output', '',
1073 _('print output to file with formatted name'), _('FORMAT')),
1073 _('print output to file with formatted name'), _('FORMAT')),
1074 ('r', 'rev', '', _('print the given revision'), _('REV')),
1074 ('r', 'rev', '', _('print the given revision'), _('REV')),
1075 ('', 'decode', None, _('apply any matching decode filter')),
1075 ('', 'decode', None, _('apply any matching decode filter')),
1076 ] + walkopts,
1076 ] + walkopts,
1077 _('[OPTION]... FILE...'))
1077 _('[OPTION]... FILE...'))
1078 def cat(ui, repo, file1, *pats, **opts):
1078 def cat(ui, repo, file1, *pats, **opts):
1079 """output the current or given revision of files
1079 """output the current or given revision of files
1080
1080
1081 Print the specified files as they were at the given revision. If
1081 Print the specified files as they were at the given revision. If
1082 no revision is given, the parent of the working directory is used,
1082 no revision is given, the parent of the working directory is used,
1083 or tip if no revision is checked out.
1083 or tip if no revision is checked out.
1084
1084
1085 Output may be to a file, in which case the name of the file is
1085 Output may be to a file, in which case the name of the file is
1086 given using a format string. The formatting rules are the same as
1086 given using a format string. The formatting rules are the same as
1087 for the export command, with the following additions:
1087 for the export command, with the following additions:
1088
1088
1089 :``%s``: basename of file being printed
1089 :``%s``: basename of file being printed
1090 :``%d``: dirname of file being printed, or '.' if in repository root
1090 :``%d``: dirname of file being printed, or '.' if in repository root
1091 :``%p``: root-relative path name of file being printed
1091 :``%p``: root-relative path name of file being printed
1092
1092
1093 Returns 0 on success.
1093 Returns 0 on success.
1094 """
1094 """
1095 ctx = scmutil.revsingle(repo, opts.get('rev'))
1095 ctx = scmutil.revsingle(repo, opts.get('rev'))
1096 err = 1
1096 err = 1
1097 m = scmutil.match(ctx, (file1,) + pats, opts)
1097 m = scmutil.match(ctx, (file1,) + pats, opts)
1098 for abs in ctx.walk(m):
1098 for abs in ctx.walk(m):
1099 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1099 fp = cmdutil.makefileobj(repo, opts.get('output'), ctx.node(),
1100 pathname=abs)
1100 pathname=abs)
1101 data = ctx[abs].data()
1101 data = ctx[abs].data()
1102 if opts.get('decode'):
1102 if opts.get('decode'):
1103 data = repo.wwritedata(abs, data)
1103 data = repo.wwritedata(abs, data)
1104 fp.write(data)
1104 fp.write(data)
1105 fp.close()
1105 fp.close()
1106 err = 0
1106 err = 0
1107 return err
1107 return err
1108
1108
1109 @command('^clone',
1109 @command('^clone',
1110 [('U', 'noupdate', None,
1110 [('U', 'noupdate', None,
1111 _('the clone will include an empty working copy (only a repository)')),
1111 _('the clone will include an empty working copy (only a repository)')),
1112 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1112 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1113 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1113 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1114 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1114 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1115 ('', 'pull', None, _('use pull protocol to copy metadata')),
1115 ('', 'pull', None, _('use pull protocol to copy metadata')),
1116 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1116 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1117 ] + remoteopts,
1117 ] + remoteopts,
1118 _('[OPTION]... SOURCE [DEST]'))
1118 _('[OPTION]... SOURCE [DEST]'))
1119 def clone(ui, source, dest=None, **opts):
1119 def clone(ui, source, dest=None, **opts):
1120 """make a copy of an existing repository
1120 """make a copy of an existing repository
1121
1121
1122 Create a copy of an existing repository in a new directory.
1122 Create a copy of an existing repository in a new directory.
1123
1123
1124 If no destination directory name is specified, it defaults to the
1124 If no destination directory name is specified, it defaults to the
1125 basename of the source.
1125 basename of the source.
1126
1126
1127 The location of the source is added to the new repository's
1127 The location of the source is added to the new repository's
1128 ``.hg/hgrc`` file, as the default to be used for future pulls.
1128 ``.hg/hgrc`` file, as the default to be used for future pulls.
1129
1129
1130 Only local paths and ``ssh://`` URLs are supported as
1130 Only local paths and ``ssh://`` URLs are supported as
1131 destinations. For ``ssh://`` destinations, no working directory or
1131 destinations. For ``ssh://`` destinations, no working directory or
1132 ``.hg/hgrc`` will be created on the remote side.
1132 ``.hg/hgrc`` will be created on the remote side.
1133
1133
1134 To pull only a subset of changesets, specify one or more revisions
1134 To pull only a subset of changesets, specify one or more revisions
1135 identifiers with -r/--rev or branches with -b/--branch. The
1135 identifiers with -r/--rev or branches with -b/--branch. The
1136 resulting clone will contain only the specified changesets and
1136 resulting clone will contain only the specified changesets and
1137 their ancestors. These options (or 'clone src#rev dest') imply
1137 their ancestors. These options (or 'clone src#rev dest') imply
1138 --pull, even for local source repositories. Note that specifying a
1138 --pull, even for local source repositories. Note that specifying a
1139 tag will include the tagged changeset but not the changeset
1139 tag will include the tagged changeset but not the changeset
1140 containing the tag.
1140 containing the tag.
1141
1141
1142 To check out a particular version, use -u/--update, or
1142 To check out a particular version, use -u/--update, or
1143 -U/--noupdate to create a clone with no working directory.
1143 -U/--noupdate to create a clone with no working directory.
1144
1144
1145 .. container:: verbose
1145 .. container:: verbose
1146
1146
1147 For efficiency, hardlinks are used for cloning whenever the
1147 For efficiency, hardlinks are used for cloning whenever the
1148 source and destination are on the same filesystem (note this
1148 source and destination are on the same filesystem (note this
1149 applies only to the repository data, not to the working
1149 applies only to the repository data, not to the working
1150 directory). Some filesystems, such as AFS, implement hardlinking
1150 directory). Some filesystems, such as AFS, implement hardlinking
1151 incorrectly, but do not report errors. In these cases, use the
1151 incorrectly, but do not report errors. In these cases, use the
1152 --pull option to avoid hardlinking.
1152 --pull option to avoid hardlinking.
1153
1153
1154 In some cases, you can clone repositories and the working
1154 In some cases, you can clone repositories and the working
1155 directory using full hardlinks with ::
1155 directory using full hardlinks with ::
1156
1156
1157 $ cp -al REPO REPOCLONE
1157 $ cp -al REPO REPOCLONE
1158
1158
1159 This is the fastest way to clone, but it is not always safe. The
1159 This is the fastest way to clone, but it is not always safe. The
1160 operation is not atomic (making sure REPO is not modified during
1160 operation is not atomic (making sure REPO is not modified during
1161 the operation is up to you) and you have to make sure your
1161 the operation is up to you) and you have to make sure your
1162 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1162 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1163 so). Also, this is not compatible with certain extensions that
1163 so). Also, this is not compatible with certain extensions that
1164 place their metadata under the .hg directory, such as mq.
1164 place their metadata under the .hg directory, such as mq.
1165
1165
1166 Mercurial will update the working directory to the first applicable
1166 Mercurial will update the working directory to the first applicable
1167 revision from this list:
1167 revision from this list:
1168
1168
1169 a) null if -U or the source repository has no changesets
1169 a) null if -U or the source repository has no changesets
1170 b) if -u . and the source repository is local, the first parent of
1170 b) if -u . and the source repository is local, the first parent of
1171 the source repository's working directory
1171 the source repository's working directory
1172 c) the changeset specified with -u (if a branch name, this means the
1172 c) the changeset specified with -u (if a branch name, this means the
1173 latest head of that branch)
1173 latest head of that branch)
1174 d) the changeset specified with -r
1174 d) the changeset specified with -r
1175 e) the tipmost head specified with -b
1175 e) the tipmost head specified with -b
1176 f) the tipmost head specified with the url#branch source syntax
1176 f) the tipmost head specified with the url#branch source syntax
1177 g) the tipmost head of the default branch
1177 g) the tipmost head of the default branch
1178 h) tip
1178 h) tip
1179
1179
1180 Examples:
1180 Examples:
1181
1181
1182 - clone a remote repository to a new directory named hg/::
1182 - clone a remote repository to a new directory named hg/::
1183
1183
1184 hg clone http://selenic.com/hg
1184 hg clone http://selenic.com/hg
1185
1185
1186 - create a lightweight local clone::
1186 - create a lightweight local clone::
1187
1187
1188 hg clone project/ project-feature/
1188 hg clone project/ project-feature/
1189
1189
1190 - clone from an absolute path on an ssh server (note double-slash)::
1190 - clone from an absolute path on an ssh server (note double-slash)::
1191
1191
1192 hg clone ssh://user@server//home/projects/alpha/
1192 hg clone ssh://user@server//home/projects/alpha/
1193
1193
1194 - do a high-speed clone over a LAN while checking out a
1194 - do a high-speed clone over a LAN while checking out a
1195 specified version::
1195 specified version::
1196
1196
1197 hg clone --uncompressed http://server/repo -u 1.5
1197 hg clone --uncompressed http://server/repo -u 1.5
1198
1198
1199 - create a repository without changesets after a particular revision::
1199 - create a repository without changesets after a particular revision::
1200
1200
1201 hg clone -r 04e544 experimental/ good/
1201 hg clone -r 04e544 experimental/ good/
1202
1202
1203 - clone (and track) a particular named branch::
1203 - clone (and track) a particular named branch::
1204
1204
1205 hg clone http://selenic.com/hg#stable
1205 hg clone http://selenic.com/hg#stable
1206
1206
1207 See :hg:`help urls` for details on specifying URLs.
1207 See :hg:`help urls` for details on specifying URLs.
1208
1208
1209 Returns 0 on success.
1209 Returns 0 on success.
1210 """
1210 """
1211 if opts.get('noupdate') and opts.get('updaterev'):
1211 if opts.get('noupdate') and opts.get('updaterev'):
1212 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1212 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1213
1213
1214 r = hg.clone(ui, opts, source, dest,
1214 r = hg.clone(ui, opts, source, dest,
1215 pull=opts.get('pull'),
1215 pull=opts.get('pull'),
1216 stream=opts.get('uncompressed'),
1216 stream=opts.get('uncompressed'),
1217 rev=opts.get('rev'),
1217 rev=opts.get('rev'),
1218 update=opts.get('updaterev') or not opts.get('noupdate'),
1218 update=opts.get('updaterev') or not opts.get('noupdate'),
1219 branch=opts.get('branch'))
1219 branch=opts.get('branch'))
1220
1220
1221 return r is None
1221 return r is None
1222
1222
1223 @command('^commit|ci',
1223 @command('^commit|ci',
1224 [('A', 'addremove', None,
1224 [('A', 'addremove', None,
1225 _('mark new/missing files as added/removed before committing')),
1225 _('mark new/missing files as added/removed before committing')),
1226 ('', 'close-branch', None,
1226 ('', 'close-branch', None,
1227 _('mark a branch as closed, hiding it from the branch list')),
1227 _('mark a branch as closed, hiding it from the branch list')),
1228 ('', 'amend', None, _('amend the parent of the working dir')),
1228 ('', 'amend', None, _('amend the parent of the working dir')),
1229 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1229 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1230 _('[OPTION]... [FILE]...'))
1230 _('[OPTION]... [FILE]...'))
1231 def commit(ui, repo, *pats, **opts):
1231 def commit(ui, repo, *pats, **opts):
1232 """commit the specified files or all outstanding changes
1232 """commit the specified files or all outstanding changes
1233
1233
1234 Commit changes to the given files into the repository. Unlike a
1234 Commit changes to the given files into the repository. Unlike a
1235 centralized SCM, this operation is a local operation. See
1235 centralized SCM, this operation is a local operation. See
1236 :hg:`push` for a way to actively distribute your changes.
1236 :hg:`push` for a way to actively distribute your changes.
1237
1237
1238 If a list of files is omitted, all changes reported by :hg:`status`
1238 If a list of files is omitted, all changes reported by :hg:`status`
1239 will be committed.
1239 will be committed.
1240
1240
1241 If you are committing the result of a merge, do not provide any
1241 If you are committing the result of a merge, do not provide any
1242 filenames or -I/-X filters.
1242 filenames or -I/-X filters.
1243
1243
1244 If no commit message is specified, Mercurial starts your
1244 If no commit message is specified, Mercurial starts your
1245 configured editor where you can enter a message. In case your
1245 configured editor where you can enter a message. In case your
1246 commit fails, you will find a backup of your message in
1246 commit fails, you will find a backup of your message in
1247 ``.hg/last-message.txt``.
1247 ``.hg/last-message.txt``.
1248
1248
1249 The --amend flag can be used to amend the parent of the
1249 The --amend flag can be used to amend the parent of the
1250 working directory with a new commit that contains the changes
1250 working directory with a new commit that contains the changes
1251 in the parent in addition to those currently reported by :hg:`status`,
1251 in the parent in addition to those currently reported by :hg:`status`,
1252 if there are any. The old commit is stored in a backup bundle in
1252 if there are any. The old commit is stored in a backup bundle in
1253 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1253 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1254 on how to restore it).
1254 on how to restore it).
1255
1255
1256 Message, user and date are taken from the amended commit unless
1256 Message, user and date are taken from the amended commit unless
1257 specified. When a message isn't specified on the command line,
1257 specified. When a message isn't specified on the command line,
1258 the editor will open with the message of the amended commit.
1258 the editor will open with the message of the amended commit.
1259
1259
1260 It is not possible to amend public changesets (see :hg:`help phases`)
1260 It is not possible to amend public changesets (see :hg:`help phases`)
1261 or changesets that have children.
1261 or changesets that have children.
1262
1262
1263 See :hg:`help dates` for a list of formats valid for -d/--date.
1263 See :hg:`help dates` for a list of formats valid for -d/--date.
1264
1264
1265 Returns 0 on success, 1 if nothing changed.
1265 Returns 0 on success, 1 if nothing changed.
1266 """
1266 """
1267 if opts.get('subrepos'):
1267 if opts.get('subrepos'):
1268 # Let --subrepos on the command line override config setting.
1268 # Let --subrepos on the command line override config setting.
1269 ui.setconfig('ui', 'commitsubrepos', True)
1269 ui.setconfig('ui', 'commitsubrepos', True)
1270
1270
1271 extra = {}
1271 extra = {}
1272 if opts.get('close_branch'):
1272 if opts.get('close_branch'):
1273 if repo['.'].node() not in repo.branchheads():
1273 if repo['.'].node() not in repo.branchheads():
1274 # The topo heads set is included in the branch heads set of the
1274 # The topo heads set is included in the branch heads set of the
1275 # current branch, so it's sufficient to test branchheads
1275 # current branch, so it's sufficient to test branchheads
1276 raise util.Abort(_('can only close branch heads'))
1276 raise util.Abort(_('can only close branch heads'))
1277 extra['close'] = 1
1277 extra['close'] = 1
1278
1278
1279 branch = repo[None].branch()
1279 branch = repo[None].branch()
1280 bheads = repo.branchheads(branch)
1280 bheads = repo.branchheads(branch)
1281
1281
1282 if opts.get('amend'):
1282 if opts.get('amend'):
1283 if ui.configbool('ui', 'commitsubrepos'):
1283 if ui.configbool('ui', 'commitsubrepos'):
1284 raise util.Abort(_('cannot amend recursively'))
1284 raise util.Abort(_('cannot amend recursively'))
1285
1285
1286 old = repo['.']
1286 old = repo['.']
1287 if old.phase() == phases.public:
1287 if old.phase() == phases.public:
1288 raise util.Abort(_('cannot amend public changesets'))
1288 raise util.Abort(_('cannot amend public changesets'))
1289 if len(old.parents()) > 1:
1289 if len(old.parents()) > 1:
1290 raise util.Abort(_('cannot amend merge changesets'))
1290 raise util.Abort(_('cannot amend merge changesets'))
1291 if len(repo[None].parents()) > 1:
1291 if len(repo[None].parents()) > 1:
1292 raise util.Abort(_('cannot amend while merging'))
1292 raise util.Abort(_('cannot amend while merging'))
1293 if old.children():
1293 if old.children():
1294 raise util.Abort(_('cannot amend changeset with children'))
1294 raise util.Abort(_('cannot amend changeset with children'))
1295
1295
1296 e = cmdutil.commiteditor
1296 e = cmdutil.commiteditor
1297 if opts.get('force_editor'):
1297 if opts.get('force_editor'):
1298 e = cmdutil.commitforceeditor
1298 e = cmdutil.commitforceeditor
1299
1299
1300 def commitfunc(ui, repo, message, match, opts):
1300 def commitfunc(ui, repo, message, match, opts):
1301 editor = e
1301 editor = e
1302 # message contains text from -m or -l, if it's empty,
1302 # message contains text from -m or -l, if it's empty,
1303 # open the editor with the old message
1303 # open the editor with the old message
1304 if not message:
1304 if not message:
1305 message = old.description()
1305 message = old.description()
1306 editor = cmdutil.commitforceeditor
1306 editor = cmdutil.commitforceeditor
1307 return repo.commit(message,
1307 return repo.commit(message,
1308 opts.get('user') or old.user(),
1308 opts.get('user') or old.user(),
1309 opts.get('date') or old.date(),
1309 opts.get('date') or old.date(),
1310 match,
1310 match,
1311 editor=editor,
1311 editor=editor,
1312 extra=extra)
1312 extra=extra)
1313
1313
1314 current = repo._bookmarkcurrent
1314 current = repo._bookmarkcurrent
1315 marks = old.bookmarks()
1315 marks = old.bookmarks()
1316 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1316 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1317 if node == old.node():
1317 if node == old.node():
1318 ui.status(_("nothing changed\n"))
1318 ui.status(_("nothing changed\n"))
1319 return 1
1319 return 1
1320 elif marks:
1320 elif marks:
1321 ui.debug('moving bookmarks %r from %s to %s\n' %
1321 ui.debug('moving bookmarks %r from %s to %s\n' %
1322 (marks, old.hex(), hex(node)))
1322 (marks, old.hex(), hex(node)))
1323 for bm in marks:
1323 for bm in marks:
1324 repo._bookmarks[bm] = node
1324 repo._bookmarks[bm] = node
1325 if bm == current:
1325 if bm == current:
1326 bookmarks.setcurrent(repo, bm)
1326 bookmarks.setcurrent(repo, bm)
1327 bookmarks.write(repo)
1327 bookmarks.write(repo)
1328 else:
1328 else:
1329 e = cmdutil.commiteditor
1329 e = cmdutil.commiteditor
1330 if opts.get('force_editor'):
1330 if opts.get('force_editor'):
1331 e = cmdutil.commitforceeditor
1331 e = cmdutil.commitforceeditor
1332
1332
1333 def commitfunc(ui, repo, message, match, opts):
1333 def commitfunc(ui, repo, message, match, opts):
1334 return repo.commit(message, opts.get('user'), opts.get('date'),
1334 return repo.commit(message, opts.get('user'), opts.get('date'),
1335 match, editor=e, extra=extra)
1335 match, editor=e, extra=extra)
1336
1336
1337 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1337 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1338
1338
1339 if not node:
1339 if not node:
1340 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1340 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1341 if stat[3]:
1341 if stat[3]:
1342 ui.status(_("nothing changed (%d missing files, see "
1342 ui.status(_("nothing changed (%d missing files, see "
1343 "'hg status')\n") % len(stat[3]))
1343 "'hg status')\n") % len(stat[3]))
1344 else:
1344 else:
1345 ui.status(_("nothing changed\n"))
1345 ui.status(_("nothing changed\n"))
1346 return 1
1346 return 1
1347
1347
1348 ctx = repo[node]
1348 ctx = repo[node]
1349 parents = ctx.parents()
1349 parents = ctx.parents()
1350
1350
1351 if (not opts.get('amend') and bheads and node not in bheads and not
1351 if (not opts.get('amend') and bheads and node not in bheads and not
1352 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1352 [x for x in parents if x.node() in bheads and x.branch() == branch]):
1353 ui.status(_('created new head\n'))
1353 ui.status(_('created new head\n'))
1354 # The message is not printed for initial roots. For the other
1354 # The message is not printed for initial roots. For the other
1355 # changesets, it is printed in the following situations:
1355 # changesets, it is printed in the following situations:
1356 #
1356 #
1357 # Par column: for the 2 parents with ...
1357 # Par column: for the 2 parents with ...
1358 # N: null or no parent
1358 # N: null or no parent
1359 # B: parent is on another named branch
1359 # B: parent is on another named branch
1360 # C: parent is a regular non head changeset
1360 # C: parent is a regular non head changeset
1361 # H: parent was a branch head of the current branch
1361 # H: parent was a branch head of the current branch
1362 # Msg column: whether we print "created new head" message
1362 # Msg column: whether we print "created new head" message
1363 # In the following, it is assumed that there already exists some
1363 # In the following, it is assumed that there already exists some
1364 # initial branch heads of the current branch, otherwise nothing is
1364 # initial branch heads of the current branch, otherwise nothing is
1365 # printed anyway.
1365 # printed anyway.
1366 #
1366 #
1367 # Par Msg Comment
1367 # Par Msg Comment
1368 # N N y additional topo root
1368 # N N y additional topo root
1369 #
1369 #
1370 # B N y additional branch root
1370 # B N y additional branch root
1371 # C N y additional topo head
1371 # C N y additional topo head
1372 # H N n usual case
1372 # H N n usual case
1373 #
1373 #
1374 # B B y weird additional branch root
1374 # B B y weird additional branch root
1375 # C B y branch merge
1375 # C B y branch merge
1376 # H B n merge with named branch
1376 # H B n merge with named branch
1377 #
1377 #
1378 # C C y additional head from merge
1378 # C C y additional head from merge
1379 # C H n merge with a head
1379 # C H n merge with a head
1380 #
1380 #
1381 # H H n head merge: head count decreases
1381 # H H n head merge: head count decreases
1382
1382
1383 if not opts.get('close_branch'):
1383 if not opts.get('close_branch'):
1384 for r in parents:
1384 for r in parents:
1385 if r.closesbranch() and r.branch() == branch:
1385 if r.closesbranch() and r.branch() == branch:
1386 ui.status(_('reopening closed branch head %d\n') % r)
1386 ui.status(_('reopening closed branch head %d\n') % r)
1387
1387
1388 if ui.debugflag:
1388 if ui.debugflag:
1389 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1389 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
1390 elif ui.verbose:
1390 elif ui.verbose:
1391 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1391 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
1392
1392
1393 @command('copy|cp',
1393 @command('copy|cp',
1394 [('A', 'after', None, _('record a copy that has already occurred')),
1394 [('A', 'after', None, _('record a copy that has already occurred')),
1395 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1395 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1396 ] + walkopts + dryrunopts,
1396 ] + walkopts + dryrunopts,
1397 _('[OPTION]... [SOURCE]... DEST'))
1397 _('[OPTION]... [SOURCE]... DEST'))
1398 def copy(ui, repo, *pats, **opts):
1398 def copy(ui, repo, *pats, **opts):
1399 """mark files as copied for the next commit
1399 """mark files as copied for the next commit
1400
1400
1401 Mark dest as having copies of source files. If dest is a
1401 Mark dest as having copies of source files. If dest is a
1402 directory, copies are put in that directory. If dest is a file,
1402 directory, copies are put in that directory. If dest is a file,
1403 the source must be a single file.
1403 the source must be a single file.
1404
1404
1405 By default, this command copies the contents of files as they
1405 By default, this command copies the contents of files as they
1406 exist in the working directory. If invoked with -A/--after, the
1406 exist in the working directory. If invoked with -A/--after, the
1407 operation is recorded, but no copying is performed.
1407 operation is recorded, but no copying is performed.
1408
1408
1409 This command takes effect with the next commit. To undo a copy
1409 This command takes effect with the next commit. To undo a copy
1410 before that, see :hg:`revert`.
1410 before that, see :hg:`revert`.
1411
1411
1412 Returns 0 on success, 1 if errors are encountered.
1412 Returns 0 on success, 1 if errors are encountered.
1413 """
1413 """
1414 wlock = repo.wlock(False)
1414 wlock = repo.wlock(False)
1415 try:
1415 try:
1416 return cmdutil.copy(ui, repo, pats, opts)
1416 return cmdutil.copy(ui, repo, pats, opts)
1417 finally:
1417 finally:
1418 wlock.release()
1418 wlock.release()
1419
1419
1420 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1420 @command('debugancestor', [], _('[INDEX] REV1 REV2'))
1421 def debugancestor(ui, repo, *args):
1421 def debugancestor(ui, repo, *args):
1422 """find the ancestor revision of two revisions in a given index"""
1422 """find the ancestor revision of two revisions in a given index"""
1423 if len(args) == 3:
1423 if len(args) == 3:
1424 index, rev1, rev2 = args
1424 index, rev1, rev2 = args
1425 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1425 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1426 lookup = r.lookup
1426 lookup = r.lookup
1427 elif len(args) == 2:
1427 elif len(args) == 2:
1428 if not repo:
1428 if not repo:
1429 raise util.Abort(_("there is no Mercurial repository here "
1429 raise util.Abort(_("there is no Mercurial repository here "
1430 "(.hg not found)"))
1430 "(.hg not found)"))
1431 rev1, rev2 = args
1431 rev1, rev2 = args
1432 r = repo.changelog
1432 r = repo.changelog
1433 lookup = repo.lookup
1433 lookup = repo.lookup
1434 else:
1434 else:
1435 raise util.Abort(_('either two or three arguments required'))
1435 raise util.Abort(_('either two or three arguments required'))
1436 a = r.ancestor(lookup(rev1), lookup(rev2))
1436 a = r.ancestor(lookup(rev1), lookup(rev2))
1437 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1437 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1438
1438
1439 @command('debugbuilddag',
1439 @command('debugbuilddag',
1440 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1440 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1441 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1441 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1442 ('n', 'new-file', None, _('add new file at each rev'))],
1442 ('n', 'new-file', None, _('add new file at each rev'))],
1443 _('[OPTION]... [TEXT]'))
1443 _('[OPTION]... [TEXT]'))
1444 def debugbuilddag(ui, repo, text=None,
1444 def debugbuilddag(ui, repo, text=None,
1445 mergeable_file=False,
1445 mergeable_file=False,
1446 overwritten_file=False,
1446 overwritten_file=False,
1447 new_file=False):
1447 new_file=False):
1448 """builds a repo with a given DAG from scratch in the current empty repo
1448 """builds a repo with a given DAG from scratch in the current empty repo
1449
1449
1450 The description of the DAG is read from stdin if not given on the
1450 The description of the DAG is read from stdin if not given on the
1451 command line.
1451 command line.
1452
1452
1453 Elements:
1453 Elements:
1454
1454
1455 - "+n" is a linear run of n nodes based on the current default parent
1455 - "+n" is a linear run of n nodes based on the current default parent
1456 - "." is a single node based on the current default parent
1456 - "." is a single node based on the current default parent
1457 - "$" resets the default parent to null (implied at the start);
1457 - "$" resets the default parent to null (implied at the start);
1458 otherwise the default parent is always the last node created
1458 otherwise the default parent is always the last node created
1459 - "<p" sets the default parent to the backref p
1459 - "<p" sets the default parent to the backref p
1460 - "*p" is a fork at parent p, which is a backref
1460 - "*p" is a fork at parent p, which is a backref
1461 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1461 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1462 - "/p2" is a merge of the preceding node and p2
1462 - "/p2" is a merge of the preceding node and p2
1463 - ":tag" defines a local tag for the preceding node
1463 - ":tag" defines a local tag for the preceding node
1464 - "@branch" sets the named branch for subsequent nodes
1464 - "@branch" sets the named branch for subsequent nodes
1465 - "#...\\n" is a comment up to the end of the line
1465 - "#...\\n" is a comment up to the end of the line
1466
1466
1467 Whitespace between the above elements is ignored.
1467 Whitespace between the above elements is ignored.
1468
1468
1469 A backref is either
1469 A backref is either
1470
1470
1471 - a number n, which references the node curr-n, where curr is the current
1471 - a number n, which references the node curr-n, where curr is the current
1472 node, or
1472 node, or
1473 - the name of a local tag you placed earlier using ":tag", or
1473 - the name of a local tag you placed earlier using ":tag", or
1474 - empty to denote the default parent.
1474 - empty to denote the default parent.
1475
1475
1476 All string valued-elements are either strictly alphanumeric, or must
1476 All string valued-elements are either strictly alphanumeric, or must
1477 be enclosed in double quotes ("..."), with "\\" as escape character.
1477 be enclosed in double quotes ("..."), with "\\" as escape character.
1478 """
1478 """
1479
1479
1480 if text is None:
1480 if text is None:
1481 ui.status(_("reading DAG from stdin\n"))
1481 ui.status(_("reading DAG from stdin\n"))
1482 text = ui.fin.read()
1482 text = ui.fin.read()
1483
1483
1484 cl = repo.changelog
1484 cl = repo.changelog
1485 if len(cl) > 0:
1485 if len(cl) > 0:
1486 raise util.Abort(_('repository is not empty'))
1486 raise util.Abort(_('repository is not empty'))
1487
1487
1488 # determine number of revs in DAG
1488 # determine number of revs in DAG
1489 total = 0
1489 total = 0
1490 for type, data in dagparser.parsedag(text):
1490 for type, data in dagparser.parsedag(text):
1491 if type == 'n':
1491 if type == 'n':
1492 total += 1
1492 total += 1
1493
1493
1494 if mergeable_file:
1494 if mergeable_file:
1495 linesperrev = 2
1495 linesperrev = 2
1496 # make a file with k lines per rev
1496 # make a file with k lines per rev
1497 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1497 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1498 initialmergedlines.append("")
1498 initialmergedlines.append("")
1499
1499
1500 tags = []
1500 tags = []
1501
1501
1502 lock = tr = None
1502 lock = tr = None
1503 try:
1503 try:
1504 lock = repo.lock()
1504 lock = repo.lock()
1505 tr = repo.transaction("builddag")
1505 tr = repo.transaction("builddag")
1506
1506
1507 at = -1
1507 at = -1
1508 atbranch = 'default'
1508 atbranch = 'default'
1509 nodeids = []
1509 nodeids = []
1510 id = 0
1510 id = 0
1511 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1511 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1512 for type, data in dagparser.parsedag(text):
1512 for type, data in dagparser.parsedag(text):
1513 if type == 'n':
1513 if type == 'n':
1514 ui.note('node %s\n' % str(data))
1514 ui.note('node %s\n' % str(data))
1515 id, ps = data
1515 id, ps = data
1516
1516
1517 files = []
1517 files = []
1518 fctxs = {}
1518 fctxs = {}
1519
1519
1520 p2 = None
1520 p2 = None
1521 if mergeable_file:
1521 if mergeable_file:
1522 fn = "mf"
1522 fn = "mf"
1523 p1 = repo[ps[0]]
1523 p1 = repo[ps[0]]
1524 if len(ps) > 1:
1524 if len(ps) > 1:
1525 p2 = repo[ps[1]]
1525 p2 = repo[ps[1]]
1526 pa = p1.ancestor(p2)
1526 pa = p1.ancestor(p2)
1527 base, local, other = [x[fn].data() for x in pa, p1, p2]
1527 base, local, other = [x[fn].data() for x in pa, p1, p2]
1528 m3 = simplemerge.Merge3Text(base, local, other)
1528 m3 = simplemerge.Merge3Text(base, local, other)
1529 ml = [l.strip() for l in m3.merge_lines()]
1529 ml = [l.strip() for l in m3.merge_lines()]
1530 ml.append("")
1530 ml.append("")
1531 elif at > 0:
1531 elif at > 0:
1532 ml = p1[fn].data().split("\n")
1532 ml = p1[fn].data().split("\n")
1533 else:
1533 else:
1534 ml = initialmergedlines
1534 ml = initialmergedlines
1535 ml[id * linesperrev] += " r%i" % id
1535 ml[id * linesperrev] += " r%i" % id
1536 mergedtext = "\n".join(ml)
1536 mergedtext = "\n".join(ml)
1537 files.append(fn)
1537 files.append(fn)
1538 fctxs[fn] = context.memfilectx(fn, mergedtext)
1538 fctxs[fn] = context.memfilectx(fn, mergedtext)
1539
1539
1540 if overwritten_file:
1540 if overwritten_file:
1541 fn = "of"
1541 fn = "of"
1542 files.append(fn)
1542 files.append(fn)
1543 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1543 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1544
1544
1545 if new_file:
1545 if new_file:
1546 fn = "nf%i" % id
1546 fn = "nf%i" % id
1547 files.append(fn)
1547 files.append(fn)
1548 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1548 fctxs[fn] = context.memfilectx(fn, "r%i\n" % id)
1549 if len(ps) > 1:
1549 if len(ps) > 1:
1550 if not p2:
1550 if not p2:
1551 p2 = repo[ps[1]]
1551 p2 = repo[ps[1]]
1552 for fn in p2:
1552 for fn in p2:
1553 if fn.startswith("nf"):
1553 if fn.startswith("nf"):
1554 files.append(fn)
1554 files.append(fn)
1555 fctxs[fn] = p2[fn]
1555 fctxs[fn] = p2[fn]
1556
1556
1557 def fctxfn(repo, cx, path):
1557 def fctxfn(repo, cx, path):
1558 return fctxs.get(path)
1558 return fctxs.get(path)
1559
1559
1560 if len(ps) == 0 or ps[0] < 0:
1560 if len(ps) == 0 or ps[0] < 0:
1561 pars = [None, None]
1561 pars = [None, None]
1562 elif len(ps) == 1:
1562 elif len(ps) == 1:
1563 pars = [nodeids[ps[0]], None]
1563 pars = [nodeids[ps[0]], None]
1564 else:
1564 else:
1565 pars = [nodeids[p] for p in ps]
1565 pars = [nodeids[p] for p in ps]
1566 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1566 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1567 date=(id, 0),
1567 date=(id, 0),
1568 user="debugbuilddag",
1568 user="debugbuilddag",
1569 extra={'branch': atbranch})
1569 extra={'branch': atbranch})
1570 nodeid = repo.commitctx(cx)
1570 nodeid = repo.commitctx(cx)
1571 nodeids.append(nodeid)
1571 nodeids.append(nodeid)
1572 at = id
1572 at = id
1573 elif type == 'l':
1573 elif type == 'l':
1574 id, name = data
1574 id, name = data
1575 ui.note('tag %s\n' % name)
1575 ui.note('tag %s\n' % name)
1576 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1576 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1577 elif type == 'a':
1577 elif type == 'a':
1578 ui.note('branch %s\n' % data)
1578 ui.note('branch %s\n' % data)
1579 atbranch = data
1579 atbranch = data
1580 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1580 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1581 tr.close()
1581 tr.close()
1582
1582
1583 if tags:
1583 if tags:
1584 repo.opener.write("localtags", "".join(tags))
1584 repo.opener.write("localtags", "".join(tags))
1585 finally:
1585 finally:
1586 ui.progress(_('building'), None)
1586 ui.progress(_('building'), None)
1587 release(tr, lock)
1587 release(tr, lock)
1588
1588
1589 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1589 @command('debugbundle', [('a', 'all', None, _('show all details'))], _('FILE'))
1590 def debugbundle(ui, bundlepath, all=None, **opts):
1590 def debugbundle(ui, bundlepath, all=None, **opts):
1591 """lists the contents of a bundle"""
1591 """lists the contents of a bundle"""
1592 f = url.open(ui, bundlepath)
1592 f = url.open(ui, bundlepath)
1593 try:
1593 try:
1594 gen = changegroup.readbundle(f, bundlepath)
1594 gen = changegroup.readbundle(f, bundlepath)
1595 if all:
1595 if all:
1596 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1596 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1597
1597
1598 def showchunks(named):
1598 def showchunks(named):
1599 ui.write("\n%s\n" % named)
1599 ui.write("\n%s\n" % named)
1600 chain = None
1600 chain = None
1601 while True:
1601 while True:
1602 chunkdata = gen.deltachunk(chain)
1602 chunkdata = gen.deltachunk(chain)
1603 if not chunkdata:
1603 if not chunkdata:
1604 break
1604 break
1605 node = chunkdata['node']
1605 node = chunkdata['node']
1606 p1 = chunkdata['p1']
1606 p1 = chunkdata['p1']
1607 p2 = chunkdata['p2']
1607 p2 = chunkdata['p2']
1608 cs = chunkdata['cs']
1608 cs = chunkdata['cs']
1609 deltabase = chunkdata['deltabase']
1609 deltabase = chunkdata['deltabase']
1610 delta = chunkdata['delta']
1610 delta = chunkdata['delta']
1611 ui.write("%s %s %s %s %s %s\n" %
1611 ui.write("%s %s %s %s %s %s\n" %
1612 (hex(node), hex(p1), hex(p2),
1612 (hex(node), hex(p1), hex(p2),
1613 hex(cs), hex(deltabase), len(delta)))
1613 hex(cs), hex(deltabase), len(delta)))
1614 chain = node
1614 chain = node
1615
1615
1616 chunkdata = gen.changelogheader()
1616 chunkdata = gen.changelogheader()
1617 showchunks("changelog")
1617 showchunks("changelog")
1618 chunkdata = gen.manifestheader()
1618 chunkdata = gen.manifestheader()
1619 showchunks("manifest")
1619 showchunks("manifest")
1620 while True:
1620 while True:
1621 chunkdata = gen.filelogheader()
1621 chunkdata = gen.filelogheader()
1622 if not chunkdata:
1622 if not chunkdata:
1623 break
1623 break
1624 fname = chunkdata['filename']
1624 fname = chunkdata['filename']
1625 showchunks(fname)
1625 showchunks(fname)
1626 else:
1626 else:
1627 chunkdata = gen.changelogheader()
1627 chunkdata = gen.changelogheader()
1628 chain = None
1628 chain = None
1629 while True:
1629 while True:
1630 chunkdata = gen.deltachunk(chain)
1630 chunkdata = gen.deltachunk(chain)
1631 if not chunkdata:
1631 if not chunkdata:
1632 break
1632 break
1633 node = chunkdata['node']
1633 node = chunkdata['node']
1634 ui.write("%s\n" % hex(node))
1634 ui.write("%s\n" % hex(node))
1635 chain = node
1635 chain = node
1636 finally:
1636 finally:
1637 f.close()
1637 f.close()
1638
1638
1639 @command('debugcheckstate', [], '')
1639 @command('debugcheckstate', [], '')
1640 def debugcheckstate(ui, repo):
1640 def debugcheckstate(ui, repo):
1641 """validate the correctness of the current dirstate"""
1641 """validate the correctness of the current dirstate"""
1642 parent1, parent2 = repo.dirstate.parents()
1642 parent1, parent2 = repo.dirstate.parents()
1643 m1 = repo[parent1].manifest()
1643 m1 = repo[parent1].manifest()
1644 m2 = repo[parent2].manifest()
1644 m2 = repo[parent2].manifest()
1645 errors = 0
1645 errors = 0
1646 for f in repo.dirstate:
1646 for f in repo.dirstate:
1647 state = repo.dirstate[f]
1647 state = repo.dirstate[f]
1648 if state in "nr" and f not in m1:
1648 if state in "nr" and f not in m1:
1649 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1649 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1650 errors += 1
1650 errors += 1
1651 if state in "a" and f in m1:
1651 if state in "a" and f in m1:
1652 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1652 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1653 errors += 1
1653 errors += 1
1654 if state in "m" and f not in m1 and f not in m2:
1654 if state in "m" and f not in m1 and f not in m2:
1655 ui.warn(_("%s in state %s, but not in either manifest\n") %
1655 ui.warn(_("%s in state %s, but not in either manifest\n") %
1656 (f, state))
1656 (f, state))
1657 errors += 1
1657 errors += 1
1658 for f in m1:
1658 for f in m1:
1659 state = repo.dirstate[f]
1659 state = repo.dirstate[f]
1660 if state not in "nrm":
1660 if state not in "nrm":
1661 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1661 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1662 errors += 1
1662 errors += 1
1663 if errors:
1663 if errors:
1664 error = _(".hg/dirstate inconsistent with current parent's manifest")
1664 error = _(".hg/dirstate inconsistent with current parent's manifest")
1665 raise util.Abort(error)
1665 raise util.Abort(error)
1666
1666
1667 @command('debugcommands', [], _('[COMMAND]'))
1667 @command('debugcommands', [], _('[COMMAND]'))
1668 def debugcommands(ui, cmd='', *args):
1668 def debugcommands(ui, cmd='', *args):
1669 """list all available commands and options"""
1669 """list all available commands and options"""
1670 for cmd, vals in sorted(table.iteritems()):
1670 for cmd, vals in sorted(table.iteritems()):
1671 cmd = cmd.split('|')[0].strip('^')
1671 cmd = cmd.split('|')[0].strip('^')
1672 opts = ', '.join([i[1] for i in vals[1]])
1672 opts = ', '.join([i[1] for i in vals[1]])
1673 ui.write('%s: %s\n' % (cmd, opts))
1673 ui.write('%s: %s\n' % (cmd, opts))
1674
1674
1675 @command('debugcomplete',
1675 @command('debugcomplete',
1676 [('o', 'options', None, _('show the command options'))],
1676 [('o', 'options', None, _('show the command options'))],
1677 _('[-o] CMD'))
1677 _('[-o] CMD'))
1678 def debugcomplete(ui, cmd='', **opts):
1678 def debugcomplete(ui, cmd='', **opts):
1679 """returns the completion list associated with the given command"""
1679 """returns the completion list associated with the given command"""
1680
1680
1681 if opts.get('options'):
1681 if opts.get('options'):
1682 options = []
1682 options = []
1683 otables = [globalopts]
1683 otables = [globalopts]
1684 if cmd:
1684 if cmd:
1685 aliases, entry = cmdutil.findcmd(cmd, table, False)
1685 aliases, entry = cmdutil.findcmd(cmd, table, False)
1686 otables.append(entry[1])
1686 otables.append(entry[1])
1687 for t in otables:
1687 for t in otables:
1688 for o in t:
1688 for o in t:
1689 if "(DEPRECATED)" in o[3]:
1689 if "(DEPRECATED)" in o[3]:
1690 continue
1690 continue
1691 if o[0]:
1691 if o[0]:
1692 options.append('-%s' % o[0])
1692 options.append('-%s' % o[0])
1693 options.append('--%s' % o[1])
1693 options.append('--%s' % o[1])
1694 ui.write("%s\n" % "\n".join(options))
1694 ui.write("%s\n" % "\n".join(options))
1695 return
1695 return
1696
1696
1697 cmdlist = cmdutil.findpossible(cmd, table)
1697 cmdlist = cmdutil.findpossible(cmd, table)
1698 if ui.verbose:
1698 if ui.verbose:
1699 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1699 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1700 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1700 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1701
1701
1702 @command('debugdag',
1702 @command('debugdag',
1703 [('t', 'tags', None, _('use tags as labels')),
1703 [('t', 'tags', None, _('use tags as labels')),
1704 ('b', 'branches', None, _('annotate with branch names')),
1704 ('b', 'branches', None, _('annotate with branch names')),
1705 ('', 'dots', None, _('use dots for runs')),
1705 ('', 'dots', None, _('use dots for runs')),
1706 ('s', 'spaces', None, _('separate elements by spaces'))],
1706 ('s', 'spaces', None, _('separate elements by spaces'))],
1707 _('[OPTION]... [FILE [REV]...]'))
1707 _('[OPTION]... [FILE [REV]...]'))
1708 def debugdag(ui, repo, file_=None, *revs, **opts):
1708 def debugdag(ui, repo, file_=None, *revs, **opts):
1709 """format the changelog or an index DAG as a concise textual description
1709 """format the changelog or an index DAG as a concise textual description
1710
1710
1711 If you pass a revlog index, the revlog's DAG is emitted. If you list
1711 If you pass a revlog index, the revlog's DAG is emitted. If you list
1712 revision numbers, they get labeled in the output as rN.
1712 revision numbers, they get labeled in the output as rN.
1713
1713
1714 Otherwise, the changelog DAG of the current repo is emitted.
1714 Otherwise, the changelog DAG of the current repo is emitted.
1715 """
1715 """
1716 spaces = opts.get('spaces')
1716 spaces = opts.get('spaces')
1717 dots = opts.get('dots')
1717 dots = opts.get('dots')
1718 if file_:
1718 if file_:
1719 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1719 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1720 revs = set((int(r) for r in revs))
1720 revs = set((int(r) for r in revs))
1721 def events():
1721 def events():
1722 for r in rlog:
1722 for r in rlog:
1723 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1723 yield 'n', (r, list(set(p for p in rlog.parentrevs(r)
1724 if p != -1)))
1724 if p != -1)))
1725 if r in revs:
1725 if r in revs:
1726 yield 'l', (r, "r%i" % r)
1726 yield 'l', (r, "r%i" % r)
1727 elif repo:
1727 elif repo:
1728 cl = repo.changelog
1728 cl = repo.changelog
1729 tags = opts.get('tags')
1729 tags = opts.get('tags')
1730 branches = opts.get('branches')
1730 branches = opts.get('branches')
1731 if tags:
1731 if tags:
1732 labels = {}
1732 labels = {}
1733 for l, n in repo.tags().items():
1733 for l, n in repo.tags().items():
1734 labels.setdefault(cl.rev(n), []).append(l)
1734 labels.setdefault(cl.rev(n), []).append(l)
1735 def events():
1735 def events():
1736 b = "default"
1736 b = "default"
1737 for r in cl:
1737 for r in cl:
1738 if branches:
1738 if branches:
1739 newb = cl.read(cl.node(r))[5]['branch']
1739 newb = cl.read(cl.node(r))[5]['branch']
1740 if newb != b:
1740 if newb != b:
1741 yield 'a', newb
1741 yield 'a', newb
1742 b = newb
1742 b = newb
1743 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1743 yield 'n', (r, list(set(p for p in cl.parentrevs(r)
1744 if p != -1)))
1744 if p != -1)))
1745 if tags:
1745 if tags:
1746 ls = labels.get(r)
1746 ls = labels.get(r)
1747 if ls:
1747 if ls:
1748 for l in ls:
1748 for l in ls:
1749 yield 'l', (r, l)
1749 yield 'l', (r, l)
1750 else:
1750 else:
1751 raise util.Abort(_('need repo for changelog dag'))
1751 raise util.Abort(_('need repo for changelog dag'))
1752
1752
1753 for line in dagparser.dagtextlines(events(),
1753 for line in dagparser.dagtextlines(events(),
1754 addspaces=spaces,
1754 addspaces=spaces,
1755 wraplabels=True,
1755 wraplabels=True,
1756 wrapannotations=True,
1756 wrapannotations=True,
1757 wrapnonlinear=dots,
1757 wrapnonlinear=dots,
1758 usedots=dots,
1758 usedots=dots,
1759 maxlinewidth=70):
1759 maxlinewidth=70):
1760 ui.write(line)
1760 ui.write(line)
1761 ui.write("\n")
1761 ui.write("\n")
1762
1762
1763 @command('debugdata',
1763 @command('debugdata',
1764 [('c', 'changelog', False, _('open changelog')),
1764 [('c', 'changelog', False, _('open changelog')),
1765 ('m', 'manifest', False, _('open manifest'))],
1765 ('m', 'manifest', False, _('open manifest'))],
1766 _('-c|-m|FILE REV'))
1766 _('-c|-m|FILE REV'))
1767 def debugdata(ui, repo, file_, rev = None, **opts):
1767 def debugdata(ui, repo, file_, rev = None, **opts):
1768 """dump the contents of a data file revision"""
1768 """dump the contents of a data file revision"""
1769 if opts.get('changelog') or opts.get('manifest'):
1769 if opts.get('changelog') or opts.get('manifest'):
1770 file_, rev = None, file_
1770 file_, rev = None, file_
1771 elif rev is None:
1771 elif rev is None:
1772 raise error.CommandError('debugdata', _('invalid arguments'))
1772 raise error.CommandError('debugdata', _('invalid arguments'))
1773 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1773 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
1774 try:
1774 try:
1775 ui.write(r.revision(r.lookup(rev)))
1775 ui.write(r.revision(r.lookup(rev)))
1776 except KeyError:
1776 except KeyError:
1777 raise util.Abort(_('invalid revision identifier %s') % rev)
1777 raise util.Abort(_('invalid revision identifier %s') % rev)
1778
1778
1779 @command('debugdate',
1779 @command('debugdate',
1780 [('e', 'extended', None, _('try extended date formats'))],
1780 [('e', 'extended', None, _('try extended date formats'))],
1781 _('[-e] DATE [RANGE]'))
1781 _('[-e] DATE [RANGE]'))
1782 def debugdate(ui, date, range=None, **opts):
1782 def debugdate(ui, date, range=None, **opts):
1783 """parse and display a date"""
1783 """parse and display a date"""
1784 if opts["extended"]:
1784 if opts["extended"]:
1785 d = util.parsedate(date, util.extendeddateformats)
1785 d = util.parsedate(date, util.extendeddateformats)
1786 else:
1786 else:
1787 d = util.parsedate(date)
1787 d = util.parsedate(date)
1788 ui.write("internal: %s %s\n" % d)
1788 ui.write("internal: %s %s\n" % d)
1789 ui.write("standard: %s\n" % util.datestr(d))
1789 ui.write("standard: %s\n" % util.datestr(d))
1790 if range:
1790 if range:
1791 m = util.matchdate(range)
1791 m = util.matchdate(range)
1792 ui.write("match: %s\n" % m(d[0]))
1792 ui.write("match: %s\n" % m(d[0]))
1793
1793
1794 @command('debugdiscovery',
1794 @command('debugdiscovery',
1795 [('', 'old', None, _('use old-style discovery')),
1795 [('', 'old', None, _('use old-style discovery')),
1796 ('', 'nonheads', None,
1796 ('', 'nonheads', None,
1797 _('use old-style discovery with non-heads included')),
1797 _('use old-style discovery with non-heads included')),
1798 ] + remoteopts,
1798 ] + remoteopts,
1799 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1799 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
1800 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1800 def debugdiscovery(ui, repo, remoteurl="default", **opts):
1801 """runs the changeset discovery protocol in isolation"""
1801 """runs the changeset discovery protocol in isolation"""
1802 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1802 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
1803 opts.get('branch'))
1803 opts.get('branch'))
1804 remote = hg.peer(repo, opts, remoteurl)
1804 remote = hg.peer(repo, opts, remoteurl)
1805 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1805 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
1806
1806
1807 # make sure tests are repeatable
1807 # make sure tests are repeatable
1808 random.seed(12323)
1808 random.seed(12323)
1809
1809
1810 def doit(localheads, remoteheads, remote=remote):
1810 def doit(localheads, remoteheads, remote=remote):
1811 if opts.get('old'):
1811 if opts.get('old'):
1812 if localheads:
1812 if localheads:
1813 raise util.Abort('cannot use localheads with old style '
1813 raise util.Abort('cannot use localheads with old style '
1814 'discovery')
1814 'discovery')
1815 if not util.safehasattr(remote, 'branches'):
1815 if not util.safehasattr(remote, 'branches'):
1816 # enable in-client legacy support
1816 # enable in-client legacy support
1817 remote = localrepo.locallegacypeer(remote.local())
1817 remote = localrepo.locallegacypeer(remote.local())
1818 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1818 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
1819 force=True)
1819 force=True)
1820 common = set(common)
1820 common = set(common)
1821 if not opts.get('nonheads'):
1821 if not opts.get('nonheads'):
1822 ui.write("unpruned common: %s\n" % " ".join([short(n)
1822 ui.write("unpruned common: %s\n" % " ".join([short(n)
1823 for n in common]))
1823 for n in common]))
1824 dag = dagutil.revlogdag(repo.changelog)
1824 dag = dagutil.revlogdag(repo.changelog)
1825 all = dag.ancestorset(dag.internalizeall(common))
1825 all = dag.ancestorset(dag.internalizeall(common))
1826 common = dag.externalizeall(dag.headsetofconnecteds(all))
1826 common = dag.externalizeall(dag.headsetofconnecteds(all))
1827 else:
1827 else:
1828 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1828 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
1829 common = set(common)
1829 common = set(common)
1830 rheads = set(hds)
1830 rheads = set(hds)
1831 lheads = set(repo.heads())
1831 lheads = set(repo.heads())
1832 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1832 ui.write("common heads: %s\n" % " ".join([short(n) for n in common]))
1833 if lheads <= common:
1833 if lheads <= common:
1834 ui.write("local is subset\n")
1834 ui.write("local is subset\n")
1835 elif rheads <= common:
1835 elif rheads <= common:
1836 ui.write("remote is subset\n")
1836 ui.write("remote is subset\n")
1837
1837
1838 serverlogs = opts.get('serverlog')
1838 serverlogs = opts.get('serverlog')
1839 if serverlogs:
1839 if serverlogs:
1840 for filename in serverlogs:
1840 for filename in serverlogs:
1841 logfile = open(filename, 'r')
1841 logfile = open(filename, 'r')
1842 try:
1842 try:
1843 line = logfile.readline()
1843 line = logfile.readline()
1844 while line:
1844 while line:
1845 parts = line.strip().split(';')
1845 parts = line.strip().split(';')
1846 op = parts[1]
1846 op = parts[1]
1847 if op == 'cg':
1847 if op == 'cg':
1848 pass
1848 pass
1849 elif op == 'cgss':
1849 elif op == 'cgss':
1850 doit(parts[2].split(' '), parts[3].split(' '))
1850 doit(parts[2].split(' '), parts[3].split(' '))
1851 elif op == 'unb':
1851 elif op == 'unb':
1852 doit(parts[3].split(' '), parts[2].split(' '))
1852 doit(parts[3].split(' '), parts[2].split(' '))
1853 line = logfile.readline()
1853 line = logfile.readline()
1854 finally:
1854 finally:
1855 logfile.close()
1855 logfile.close()
1856
1856
1857 else:
1857 else:
1858 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1858 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
1859 opts.get('remote_head'))
1859 opts.get('remote_head'))
1860 localrevs = opts.get('local_head')
1860 localrevs = opts.get('local_head')
1861 doit(localrevs, remoterevs)
1861 doit(localrevs, remoterevs)
1862
1862
1863 @command('debugfileset',
1863 @command('debugfileset',
1864 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1864 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
1865 _('[-r REV] FILESPEC'))
1865 _('[-r REV] FILESPEC'))
1866 def debugfileset(ui, repo, expr, **opts):
1866 def debugfileset(ui, repo, expr, **opts):
1867 '''parse and apply a fileset specification'''
1867 '''parse and apply a fileset specification'''
1868 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1868 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
1869 if ui.verbose:
1869 if ui.verbose:
1870 tree = fileset.parse(expr)[0]
1870 tree = fileset.parse(expr)[0]
1871 ui.note(tree, "\n")
1871 ui.note(tree, "\n")
1872
1872
1873 for f in fileset.getfileset(ctx, expr):
1873 for f in fileset.getfileset(ctx, expr):
1874 ui.write("%s\n" % f)
1874 ui.write("%s\n" % f)
1875
1875
1876 @command('debugfsinfo', [], _('[PATH]'))
1876 @command('debugfsinfo', [], _('[PATH]'))
1877 def debugfsinfo(ui, path = "."):
1877 def debugfsinfo(ui, path = "."):
1878 """show information detected about current filesystem"""
1878 """show information detected about current filesystem"""
1879 util.writefile('.debugfsinfo', '')
1879 util.writefile('.debugfsinfo', '')
1880 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1880 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1881 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1881 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1882 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1882 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1883 and 'yes' or 'no'))
1883 and 'yes' or 'no'))
1884 os.unlink('.debugfsinfo')
1884 os.unlink('.debugfsinfo')
1885
1885
1886 @command('debuggetbundle',
1886 @command('debuggetbundle',
1887 [('H', 'head', [], _('id of head node'), _('ID')),
1887 [('H', 'head', [], _('id of head node'), _('ID')),
1888 ('C', 'common', [], _('id of common node'), _('ID')),
1888 ('C', 'common', [], _('id of common node'), _('ID')),
1889 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1889 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
1890 _('REPO FILE [-H|-C ID]...'))
1890 _('REPO FILE [-H|-C ID]...'))
1891 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1891 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1892 """retrieves a bundle from a repo
1892 """retrieves a bundle from a repo
1893
1893
1894 Every ID must be a full-length hex node id string. Saves the bundle to the
1894 Every ID must be a full-length hex node id string. Saves the bundle to the
1895 given file.
1895 given file.
1896 """
1896 """
1897 repo = hg.peer(ui, opts, repopath)
1897 repo = hg.peer(ui, opts, repopath)
1898 if not repo.capable('getbundle'):
1898 if not repo.capable('getbundle'):
1899 raise util.Abort("getbundle() not supported by target repository")
1899 raise util.Abort("getbundle() not supported by target repository")
1900 args = {}
1900 args = {}
1901 if common:
1901 if common:
1902 args['common'] = [bin(s) for s in common]
1902 args['common'] = [bin(s) for s in common]
1903 if head:
1903 if head:
1904 args['heads'] = [bin(s) for s in head]
1904 args['heads'] = [bin(s) for s in head]
1905 bundle = repo.getbundle('debug', **args)
1905 bundle = repo.getbundle('debug', **args)
1906
1906
1907 bundletype = opts.get('type', 'bzip2').lower()
1907 bundletype = opts.get('type', 'bzip2').lower()
1908 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1908 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1909 bundletype = btypes.get(bundletype)
1909 bundletype = btypes.get(bundletype)
1910 if bundletype not in changegroup.bundletypes:
1910 if bundletype not in changegroup.bundletypes:
1911 raise util.Abort(_('unknown bundle type specified with --type'))
1911 raise util.Abort(_('unknown bundle type specified with --type'))
1912 changegroup.writebundle(bundle, bundlepath, bundletype)
1912 changegroup.writebundle(bundle, bundlepath, bundletype)
1913
1913
1914 @command('debugignore', [], '')
1914 @command('debugignore', [], '')
1915 def debugignore(ui, repo, *values, **opts):
1915 def debugignore(ui, repo, *values, **opts):
1916 """display the combined ignore pattern"""
1916 """display the combined ignore pattern"""
1917 ignore = repo.dirstate._ignore
1917 ignore = repo.dirstate._ignore
1918 includepat = getattr(ignore, 'includepat', None)
1918 includepat = getattr(ignore, 'includepat', None)
1919 if includepat is not None:
1919 if includepat is not None:
1920 ui.write("%s\n" % includepat)
1920 ui.write("%s\n" % includepat)
1921 else:
1921 else:
1922 raise util.Abort(_("no ignore patterns found"))
1922 raise util.Abort(_("no ignore patterns found"))
1923
1923
1924 @command('debugindex',
1924 @command('debugindex',
1925 [('c', 'changelog', False, _('open changelog')),
1925 [('c', 'changelog', False, _('open changelog')),
1926 ('m', 'manifest', False, _('open manifest')),
1926 ('m', 'manifest', False, _('open manifest')),
1927 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1927 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
1928 _('[-f FORMAT] -c|-m|FILE'))
1928 _('[-f FORMAT] -c|-m|FILE'))
1929 def debugindex(ui, repo, file_ = None, **opts):
1929 def debugindex(ui, repo, file_ = None, **opts):
1930 """dump the contents of an index file"""
1930 """dump the contents of an index file"""
1931 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1931 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
1932 format = opts.get('format', 0)
1932 format = opts.get('format', 0)
1933 if format not in (0, 1):
1933 if format not in (0, 1):
1934 raise util.Abort(_("unknown format %d") % format)
1934 raise util.Abort(_("unknown format %d") % format)
1935
1935
1936 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1936 generaldelta = r.version & revlog.REVLOGGENERALDELTA
1937 if generaldelta:
1937 if generaldelta:
1938 basehdr = ' delta'
1938 basehdr = ' delta'
1939 else:
1939 else:
1940 basehdr = ' base'
1940 basehdr = ' base'
1941
1941
1942 if format == 0:
1942 if format == 0:
1943 ui.write(" rev offset length " + basehdr + " linkrev"
1943 ui.write(" rev offset length " + basehdr + " linkrev"
1944 " nodeid p1 p2\n")
1944 " nodeid p1 p2\n")
1945 elif format == 1:
1945 elif format == 1:
1946 ui.write(" rev flag offset length"
1946 ui.write(" rev flag offset length"
1947 " size " + basehdr + " link p1 p2"
1947 " size " + basehdr + " link p1 p2"
1948 " nodeid\n")
1948 " nodeid\n")
1949
1949
1950 for i in r:
1950 for i in r:
1951 node = r.node(i)
1951 node = r.node(i)
1952 if generaldelta:
1952 if generaldelta:
1953 base = r.deltaparent(i)
1953 base = r.deltaparent(i)
1954 else:
1954 else:
1955 base = r.chainbase(i)
1955 base = r.chainbase(i)
1956 if format == 0:
1956 if format == 0:
1957 try:
1957 try:
1958 pp = r.parents(node)
1958 pp = r.parents(node)
1959 except Exception:
1959 except Exception:
1960 pp = [nullid, nullid]
1960 pp = [nullid, nullid]
1961 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1961 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1962 i, r.start(i), r.length(i), base, r.linkrev(i),
1962 i, r.start(i), r.length(i), base, r.linkrev(i),
1963 short(node), short(pp[0]), short(pp[1])))
1963 short(node), short(pp[0]), short(pp[1])))
1964 elif format == 1:
1964 elif format == 1:
1965 pr = r.parentrevs(i)
1965 pr = r.parentrevs(i)
1966 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1966 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1967 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1967 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1968 base, r.linkrev(i), pr[0], pr[1], short(node)))
1968 base, r.linkrev(i), pr[0], pr[1], short(node)))
1969
1969
1970 @command('debugindexdot', [], _('FILE'))
1970 @command('debugindexdot', [], _('FILE'))
1971 def debugindexdot(ui, repo, file_):
1971 def debugindexdot(ui, repo, file_):
1972 """dump an index DAG as a graphviz dot file"""
1972 """dump an index DAG as a graphviz dot file"""
1973 r = None
1973 r = None
1974 if repo:
1974 if repo:
1975 filelog = repo.file(file_)
1975 filelog = repo.file(file_)
1976 if len(filelog):
1976 if len(filelog):
1977 r = filelog
1977 r = filelog
1978 if not r:
1978 if not r:
1979 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1979 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1980 ui.write("digraph G {\n")
1980 ui.write("digraph G {\n")
1981 for i in r:
1981 for i in r:
1982 node = r.node(i)
1982 node = r.node(i)
1983 pp = r.parents(node)
1983 pp = r.parents(node)
1984 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1984 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1985 if pp[1] != nullid:
1985 if pp[1] != nullid:
1986 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1986 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1987 ui.write("}\n")
1987 ui.write("}\n")
1988
1988
1989 @command('debuginstall', [], '')
1989 @command('debuginstall', [], '')
1990 def debuginstall(ui):
1990 def debuginstall(ui):
1991 '''test Mercurial installation
1991 '''test Mercurial installation
1992
1992
1993 Returns 0 on success.
1993 Returns 0 on success.
1994 '''
1994 '''
1995
1995
1996 def writetemp(contents):
1996 def writetemp(contents):
1997 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1997 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1998 f = os.fdopen(fd, "wb")
1998 f = os.fdopen(fd, "wb")
1999 f.write(contents)
1999 f.write(contents)
2000 f.close()
2000 f.close()
2001 return name
2001 return name
2002
2002
2003 problems = 0
2003 problems = 0
2004
2004
2005 # encoding
2005 # encoding
2006 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2006 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2007 try:
2007 try:
2008 encoding.fromlocal("test")
2008 encoding.fromlocal("test")
2009 except util.Abort, inst:
2009 except util.Abort, inst:
2010 ui.write(" %s\n" % inst)
2010 ui.write(" %s\n" % inst)
2011 ui.write(_(" (check that your locale is properly set)\n"))
2011 ui.write(_(" (check that your locale is properly set)\n"))
2012 problems += 1
2012 problems += 1
2013
2013
2014 # Python lib
2014 # Python lib
2015 ui.status(_("checking Python lib (%s)...\n")
2015 ui.status(_("checking Python lib (%s)...\n")
2016 % os.path.dirname(os.__file__))
2016 % os.path.dirname(os.__file__))
2017
2017
2018 # compiled modules
2018 # compiled modules
2019 ui.status(_("checking installed modules (%s)...\n")
2019 ui.status(_("checking installed modules (%s)...\n")
2020 % os.path.dirname(__file__))
2020 % os.path.dirname(__file__))
2021 try:
2021 try:
2022 import bdiff, mpatch, base85, osutil
2022 import bdiff, mpatch, base85, osutil
2023 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2023 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2024 except Exception, inst:
2024 except Exception, inst:
2025 ui.write(" %s\n" % inst)
2025 ui.write(" %s\n" % inst)
2026 ui.write(_(" One or more extensions could not be found"))
2026 ui.write(_(" One or more extensions could not be found"))
2027 ui.write(_(" (check that you compiled the extensions)\n"))
2027 ui.write(_(" (check that you compiled the extensions)\n"))
2028 problems += 1
2028 problems += 1
2029
2029
2030 # templates
2030 # templates
2031 import templater
2031 import templater
2032 p = templater.templatepath()
2032 p = templater.templatepath()
2033 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2033 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2034 try:
2034 try:
2035 templater.templater(templater.templatepath("map-cmdline.default"))
2035 templater.templater(templater.templatepath("map-cmdline.default"))
2036 except Exception, inst:
2036 except Exception, inst:
2037 ui.write(" %s\n" % inst)
2037 ui.write(" %s\n" % inst)
2038 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2038 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2039 problems += 1
2039 problems += 1
2040
2040
2041 # editor
2041 # editor
2042 ui.status(_("checking commit editor...\n"))
2042 ui.status(_("checking commit editor...\n"))
2043 editor = ui.geteditor()
2043 editor = ui.geteditor()
2044 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2044 cmdpath = util.findexe(editor) or util.findexe(editor.split()[0])
2045 if not cmdpath:
2045 if not cmdpath:
2046 if editor == 'vi':
2046 if editor == 'vi':
2047 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2047 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2048 ui.write(_(" (specify a commit editor in your configuration"
2048 ui.write(_(" (specify a commit editor in your configuration"
2049 " file)\n"))
2049 " file)\n"))
2050 else:
2050 else:
2051 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2051 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2052 ui.write(_(" (specify a commit editor in your configuration"
2052 ui.write(_(" (specify a commit editor in your configuration"
2053 " file)\n"))
2053 " file)\n"))
2054 problems += 1
2054 problems += 1
2055
2055
2056 # check username
2056 # check username
2057 ui.status(_("checking username...\n"))
2057 ui.status(_("checking username...\n"))
2058 try:
2058 try:
2059 ui.username()
2059 ui.username()
2060 except util.Abort, e:
2060 except util.Abort, e:
2061 ui.write(" %s\n" % e)
2061 ui.write(" %s\n" % e)
2062 ui.write(_(" (specify a username in your configuration file)\n"))
2062 ui.write(_(" (specify a username in your configuration file)\n"))
2063 problems += 1
2063 problems += 1
2064
2064
2065 if not problems:
2065 if not problems:
2066 ui.status(_("no problems detected\n"))
2066 ui.status(_("no problems detected\n"))
2067 else:
2067 else:
2068 ui.write(_("%s problems detected,"
2068 ui.write(_("%s problems detected,"
2069 " please check your install!\n") % problems)
2069 " please check your install!\n") % problems)
2070
2070
2071 return problems
2071 return problems
2072
2072
2073 @command('debugknown', [], _('REPO ID...'))
2073 @command('debugknown', [], _('REPO ID...'))
2074 def debugknown(ui, repopath, *ids, **opts):
2074 def debugknown(ui, repopath, *ids, **opts):
2075 """test whether node ids are known to a repo
2075 """test whether node ids are known to a repo
2076
2076
2077 Every ID must be a full-length hex node id string. Returns a list of 0s
2077 Every ID must be a full-length hex node id string. Returns a list of 0s
2078 and 1s indicating unknown/known.
2078 and 1s indicating unknown/known.
2079 """
2079 """
2080 repo = hg.peer(ui, opts, repopath)
2080 repo = hg.peer(ui, opts, repopath)
2081 if not repo.capable('known'):
2081 if not repo.capable('known'):
2082 raise util.Abort("known() not supported by target repository")
2082 raise util.Abort("known() not supported by target repository")
2083 flags = repo.known([bin(s) for s in ids])
2083 flags = repo.known([bin(s) for s in ids])
2084 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2084 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2085
2085
2086 @command('debugobsolete', [] + commitopts2,
2086 @command('debugobsolete', [] + commitopts2,
2087 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2087 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2088 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2088 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2089 """create arbitrary obsolete marker"""
2089 """create arbitrary obsolete marker"""
2090 def parsenodeid(s):
2090 def parsenodeid(s):
2091 try:
2091 try:
2092 # We do not use revsingle/revrange functions here to accept
2092 # We do not use revsingle/revrange functions here to accept
2093 # arbitrary node identifiers, possibly not present in the
2093 # arbitrary node identifiers, possibly not present in the
2094 # local repository.
2094 # local repository.
2095 n = bin(s)
2095 n = bin(s)
2096 if len(n) != len(nullid):
2096 if len(n) != len(nullid):
2097 raise TypeError()
2097 raise TypeError()
2098 return n
2098 return n
2099 except TypeError:
2099 except TypeError:
2100 raise util.Abort('changeset references must be full hexadecimal '
2100 raise util.Abort('changeset references must be full hexadecimal '
2101 'node identifiers')
2101 'node identifiers')
2102
2102
2103 if precursor is not None:
2103 if precursor is not None:
2104 metadata = {}
2104 metadata = {}
2105 if 'date' in opts:
2105 if 'date' in opts:
2106 metadata['date'] = opts['date']
2106 metadata['date'] = opts['date']
2107 metadata['user'] = opts['user'] or ui.username()
2107 metadata['user'] = opts['user'] or ui.username()
2108 succs = tuple(parsenodeid(succ) for succ in successors)
2108 succs = tuple(parsenodeid(succ) for succ in successors)
2109 l = repo.lock()
2109 l = repo.lock()
2110 try:
2110 try:
2111 tr = repo.transaction('debugobsolete')
2111 tr = repo.transaction('debugobsolete')
2112 try:
2112 try:
2113 repo.obsstore.create(tr, parsenodeid(precursor), succs, 0,
2113 repo.obsstore.create(tr, parsenodeid(precursor), succs, 0,
2114 metadata)
2114 metadata)
2115 tr.close()
2115 tr.close()
2116 finally:
2116 finally:
2117 tr.release()
2117 tr.release()
2118 finally:
2118 finally:
2119 l.release()
2119 l.release()
2120 else:
2120 else:
2121 for m in obsolete.allmarkers(repo):
2121 for m in obsolete.allmarkers(repo):
2122 ui.write(hex(m.precnode()))
2122 ui.write(hex(m.precnode()))
2123 for repl in m.succnodes():
2123 for repl in m.succnodes():
2124 ui.write(' ')
2124 ui.write(' ')
2125 ui.write(hex(repl))
2125 ui.write(hex(repl))
2126 ui.write(' %X ' % m._data[2])
2126 ui.write(' %X ' % m._data[2])
2127 ui.write(m.metadata())
2127 ui.write(m.metadata())
2128 ui.write('\n')
2128 ui.write('\n')
2129
2129
2130 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2130 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'))
2131 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2131 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2132 '''access the pushkey key/value protocol
2132 '''access the pushkey key/value protocol
2133
2133
2134 With two args, list the keys in the given namespace.
2134 With two args, list the keys in the given namespace.
2135
2135
2136 With five args, set a key to new if it currently is set to old.
2136 With five args, set a key to new if it currently is set to old.
2137 Reports success or failure.
2137 Reports success or failure.
2138 '''
2138 '''
2139
2139
2140 target = hg.peer(ui, {}, repopath)
2140 target = hg.peer(ui, {}, repopath)
2141 if keyinfo:
2141 if keyinfo:
2142 key, old, new = keyinfo
2142 key, old, new = keyinfo
2143 r = target.pushkey(namespace, key, old, new)
2143 r = target.pushkey(namespace, key, old, new)
2144 ui.status(str(r) + '\n')
2144 ui.status(str(r) + '\n')
2145 return not r
2145 return not r
2146 else:
2146 else:
2147 for k, v in target.listkeys(namespace).iteritems():
2147 for k, v in target.listkeys(namespace).iteritems():
2148 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2148 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2149 v.encode('string-escape')))
2149 v.encode('string-escape')))
2150
2150
2151 @command('debugpvec', [], _('A B'))
2151 @command('debugpvec', [], _('A B'))
2152 def debugpvec(ui, repo, a, b=None):
2152 def debugpvec(ui, repo, a, b=None):
2153 ca = scmutil.revsingle(repo, a)
2153 ca = scmutil.revsingle(repo, a)
2154 cb = scmutil.revsingle(repo, b)
2154 cb = scmutil.revsingle(repo, b)
2155 pa = pvec.ctxpvec(ca)
2155 pa = pvec.ctxpvec(ca)
2156 pb = pvec.ctxpvec(cb)
2156 pb = pvec.ctxpvec(cb)
2157 if pa == pb:
2157 if pa == pb:
2158 rel = "="
2158 rel = "="
2159 elif pa > pb:
2159 elif pa > pb:
2160 rel = ">"
2160 rel = ">"
2161 elif pa < pb:
2161 elif pa < pb:
2162 rel = "<"
2162 rel = "<"
2163 elif pa | pb:
2163 elif pa | pb:
2164 rel = "|"
2164 rel = "|"
2165 ui.write(_("a: %s\n") % pa)
2165 ui.write(_("a: %s\n") % pa)
2166 ui.write(_("b: %s\n") % pb)
2166 ui.write(_("b: %s\n") % pb)
2167 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2167 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2168 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2168 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2169 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2169 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2170 pa.distance(pb), rel))
2170 pa.distance(pb), rel))
2171
2171
2172 @command('debugrebuildstate',
2172 @command('debugrebuildstate',
2173 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2173 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2174 _('[-r REV] [REV]'))
2174 _('[-r REV] [REV]'))
2175 def debugrebuildstate(ui, repo, rev="tip"):
2175 def debugrebuildstate(ui, repo, rev="tip"):
2176 """rebuild the dirstate as it would look like for the given revision"""
2176 """rebuild the dirstate as it would look like for the given revision"""
2177 ctx = scmutil.revsingle(repo, rev)
2177 ctx = scmutil.revsingle(repo, rev)
2178 wlock = repo.wlock()
2178 wlock = repo.wlock()
2179 try:
2179 try:
2180 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2180 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2181 finally:
2181 finally:
2182 wlock.release()
2182 wlock.release()
2183
2183
2184 @command('debugrename',
2184 @command('debugrename',
2185 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2185 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2186 _('[-r REV] FILE'))
2186 _('[-r REV] FILE'))
2187 def debugrename(ui, repo, file1, *pats, **opts):
2187 def debugrename(ui, repo, file1, *pats, **opts):
2188 """dump rename information"""
2188 """dump rename information"""
2189
2189
2190 ctx = scmutil.revsingle(repo, opts.get('rev'))
2190 ctx = scmutil.revsingle(repo, opts.get('rev'))
2191 m = scmutil.match(ctx, (file1,) + pats, opts)
2191 m = scmutil.match(ctx, (file1,) + pats, opts)
2192 for abs in ctx.walk(m):
2192 for abs in ctx.walk(m):
2193 fctx = ctx[abs]
2193 fctx = ctx[abs]
2194 o = fctx.filelog().renamed(fctx.filenode())
2194 o = fctx.filelog().renamed(fctx.filenode())
2195 rel = m.rel(abs)
2195 rel = m.rel(abs)
2196 if o:
2196 if o:
2197 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2197 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2198 else:
2198 else:
2199 ui.write(_("%s not renamed\n") % rel)
2199 ui.write(_("%s not renamed\n") % rel)
2200
2200
2201 @command('debugrevlog',
2201 @command('debugrevlog',
2202 [('c', 'changelog', False, _('open changelog')),
2202 [('c', 'changelog', False, _('open changelog')),
2203 ('m', 'manifest', False, _('open manifest')),
2203 ('m', 'manifest', False, _('open manifest')),
2204 ('d', 'dump', False, _('dump index data'))],
2204 ('d', 'dump', False, _('dump index data'))],
2205 _('-c|-m|FILE'))
2205 _('-c|-m|FILE'))
2206 def debugrevlog(ui, repo, file_ = None, **opts):
2206 def debugrevlog(ui, repo, file_ = None, **opts):
2207 """show data and statistics about a revlog"""
2207 """show data and statistics about a revlog"""
2208 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2208 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2209
2209
2210 if opts.get("dump"):
2210 if opts.get("dump"):
2211 numrevs = len(r)
2211 numrevs = len(r)
2212 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2212 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2213 " rawsize totalsize compression heads\n")
2213 " rawsize totalsize compression heads\n")
2214 ts = 0
2214 ts = 0
2215 heads = set()
2215 heads = set()
2216 for rev in xrange(numrevs):
2216 for rev in xrange(numrevs):
2217 dbase = r.deltaparent(rev)
2217 dbase = r.deltaparent(rev)
2218 if dbase == -1:
2218 if dbase == -1:
2219 dbase = rev
2219 dbase = rev
2220 cbase = r.chainbase(rev)
2220 cbase = r.chainbase(rev)
2221 p1, p2 = r.parentrevs(rev)
2221 p1, p2 = r.parentrevs(rev)
2222 rs = r.rawsize(rev)
2222 rs = r.rawsize(rev)
2223 ts = ts + rs
2223 ts = ts + rs
2224 heads -= set(r.parentrevs(rev))
2224 heads -= set(r.parentrevs(rev))
2225 heads.add(rev)
2225 heads.add(rev)
2226 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2226 ui.write("%d %d %d %d %d %d %d %d %d %d %d %d %d\n" %
2227 (rev, p1, p2, r.start(rev), r.end(rev),
2227 (rev, p1, p2, r.start(rev), r.end(rev),
2228 r.start(dbase), r.start(cbase),
2228 r.start(dbase), r.start(cbase),
2229 r.start(p1), r.start(p2),
2229 r.start(p1), r.start(p2),
2230 rs, ts, ts / r.end(rev), len(heads)))
2230 rs, ts, ts / r.end(rev), len(heads)))
2231 return 0
2231 return 0
2232
2232
2233 v = r.version
2233 v = r.version
2234 format = v & 0xFFFF
2234 format = v & 0xFFFF
2235 flags = []
2235 flags = []
2236 gdelta = False
2236 gdelta = False
2237 if v & revlog.REVLOGNGINLINEDATA:
2237 if v & revlog.REVLOGNGINLINEDATA:
2238 flags.append('inline')
2238 flags.append('inline')
2239 if v & revlog.REVLOGGENERALDELTA:
2239 if v & revlog.REVLOGGENERALDELTA:
2240 gdelta = True
2240 gdelta = True
2241 flags.append('generaldelta')
2241 flags.append('generaldelta')
2242 if not flags:
2242 if not flags:
2243 flags = ['(none)']
2243 flags = ['(none)']
2244
2244
2245 nummerges = 0
2245 nummerges = 0
2246 numfull = 0
2246 numfull = 0
2247 numprev = 0
2247 numprev = 0
2248 nump1 = 0
2248 nump1 = 0
2249 nump2 = 0
2249 nump2 = 0
2250 numother = 0
2250 numother = 0
2251 nump1prev = 0
2251 nump1prev = 0
2252 nump2prev = 0
2252 nump2prev = 0
2253 chainlengths = []
2253 chainlengths = []
2254
2254
2255 datasize = [None, 0, 0L]
2255 datasize = [None, 0, 0L]
2256 fullsize = [None, 0, 0L]
2256 fullsize = [None, 0, 0L]
2257 deltasize = [None, 0, 0L]
2257 deltasize = [None, 0, 0L]
2258
2258
2259 def addsize(size, l):
2259 def addsize(size, l):
2260 if l[0] is None or size < l[0]:
2260 if l[0] is None or size < l[0]:
2261 l[0] = size
2261 l[0] = size
2262 if size > l[1]:
2262 if size > l[1]:
2263 l[1] = size
2263 l[1] = size
2264 l[2] += size
2264 l[2] += size
2265
2265
2266 numrevs = len(r)
2266 numrevs = len(r)
2267 for rev in xrange(numrevs):
2267 for rev in xrange(numrevs):
2268 p1, p2 = r.parentrevs(rev)
2268 p1, p2 = r.parentrevs(rev)
2269 delta = r.deltaparent(rev)
2269 delta = r.deltaparent(rev)
2270 if format > 0:
2270 if format > 0:
2271 addsize(r.rawsize(rev), datasize)
2271 addsize(r.rawsize(rev), datasize)
2272 if p2 != nullrev:
2272 if p2 != nullrev:
2273 nummerges += 1
2273 nummerges += 1
2274 size = r.length(rev)
2274 size = r.length(rev)
2275 if delta == nullrev:
2275 if delta == nullrev:
2276 chainlengths.append(0)
2276 chainlengths.append(0)
2277 numfull += 1
2277 numfull += 1
2278 addsize(size, fullsize)
2278 addsize(size, fullsize)
2279 else:
2279 else:
2280 chainlengths.append(chainlengths[delta] + 1)
2280 chainlengths.append(chainlengths[delta] + 1)
2281 addsize(size, deltasize)
2281 addsize(size, deltasize)
2282 if delta == rev - 1:
2282 if delta == rev - 1:
2283 numprev += 1
2283 numprev += 1
2284 if delta == p1:
2284 if delta == p1:
2285 nump1prev += 1
2285 nump1prev += 1
2286 elif delta == p2:
2286 elif delta == p2:
2287 nump2prev += 1
2287 nump2prev += 1
2288 elif delta == p1:
2288 elif delta == p1:
2289 nump1 += 1
2289 nump1 += 1
2290 elif delta == p2:
2290 elif delta == p2:
2291 nump2 += 1
2291 nump2 += 1
2292 elif delta != nullrev:
2292 elif delta != nullrev:
2293 numother += 1
2293 numother += 1
2294
2294
2295 # Adjust size min value for empty cases
2295 # Adjust size min value for empty cases
2296 for size in (datasize, fullsize, deltasize):
2296 for size in (datasize, fullsize, deltasize):
2297 if size[0] is None:
2297 if size[0] is None:
2298 size[0] = 0
2298 size[0] = 0
2299
2299
2300 numdeltas = numrevs - numfull
2300 numdeltas = numrevs - numfull
2301 numoprev = numprev - nump1prev - nump2prev
2301 numoprev = numprev - nump1prev - nump2prev
2302 totalrawsize = datasize[2]
2302 totalrawsize = datasize[2]
2303 datasize[2] /= numrevs
2303 datasize[2] /= numrevs
2304 fulltotal = fullsize[2]
2304 fulltotal = fullsize[2]
2305 fullsize[2] /= numfull
2305 fullsize[2] /= numfull
2306 deltatotal = deltasize[2]
2306 deltatotal = deltasize[2]
2307 if numrevs - numfull > 0:
2307 if numrevs - numfull > 0:
2308 deltasize[2] /= numrevs - numfull
2308 deltasize[2] /= numrevs - numfull
2309 totalsize = fulltotal + deltatotal
2309 totalsize = fulltotal + deltatotal
2310 avgchainlen = sum(chainlengths) / numrevs
2310 avgchainlen = sum(chainlengths) / numrevs
2311 compratio = totalrawsize / totalsize
2311 compratio = totalrawsize / totalsize
2312
2312
2313 basedfmtstr = '%%%dd\n'
2313 basedfmtstr = '%%%dd\n'
2314 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2314 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2315
2315
2316 def dfmtstr(max):
2316 def dfmtstr(max):
2317 return basedfmtstr % len(str(max))
2317 return basedfmtstr % len(str(max))
2318 def pcfmtstr(max, padding=0):
2318 def pcfmtstr(max, padding=0):
2319 return basepcfmtstr % (len(str(max)), ' ' * padding)
2319 return basepcfmtstr % (len(str(max)), ' ' * padding)
2320
2320
2321 def pcfmt(value, total):
2321 def pcfmt(value, total):
2322 return (value, 100 * float(value) / total)
2322 return (value, 100 * float(value) / total)
2323
2323
2324 ui.write('format : %d\n' % format)
2324 ui.write('format : %d\n' % format)
2325 ui.write('flags : %s\n' % ', '.join(flags))
2325 ui.write('flags : %s\n' % ', '.join(flags))
2326
2326
2327 ui.write('\n')
2327 ui.write('\n')
2328 fmt = pcfmtstr(totalsize)
2328 fmt = pcfmtstr(totalsize)
2329 fmt2 = dfmtstr(totalsize)
2329 fmt2 = dfmtstr(totalsize)
2330 ui.write('revisions : ' + fmt2 % numrevs)
2330 ui.write('revisions : ' + fmt2 % numrevs)
2331 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2331 ui.write(' merges : ' + fmt % pcfmt(nummerges, numrevs))
2332 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2332 ui.write(' normal : ' + fmt % pcfmt(numrevs - nummerges, numrevs))
2333 ui.write('revisions : ' + fmt2 % numrevs)
2333 ui.write('revisions : ' + fmt2 % numrevs)
2334 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2334 ui.write(' full : ' + fmt % pcfmt(numfull, numrevs))
2335 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2335 ui.write(' deltas : ' + fmt % pcfmt(numdeltas, numrevs))
2336 ui.write('revision size : ' + fmt2 % totalsize)
2336 ui.write('revision size : ' + fmt2 % totalsize)
2337 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2337 ui.write(' full : ' + fmt % pcfmt(fulltotal, totalsize))
2338 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2338 ui.write(' deltas : ' + fmt % pcfmt(deltatotal, totalsize))
2339
2339
2340 ui.write('\n')
2340 ui.write('\n')
2341 fmt = dfmtstr(max(avgchainlen, compratio))
2341 fmt = dfmtstr(max(avgchainlen, compratio))
2342 ui.write('avg chain length : ' + fmt % avgchainlen)
2342 ui.write('avg chain length : ' + fmt % avgchainlen)
2343 ui.write('compression ratio : ' + fmt % compratio)
2343 ui.write('compression ratio : ' + fmt % compratio)
2344
2344
2345 if format > 0:
2345 if format > 0:
2346 ui.write('\n')
2346 ui.write('\n')
2347 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2347 ui.write('uncompressed data size (min/max/avg) : %d / %d / %d\n'
2348 % tuple(datasize))
2348 % tuple(datasize))
2349 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2349 ui.write('full revision size (min/max/avg) : %d / %d / %d\n'
2350 % tuple(fullsize))
2350 % tuple(fullsize))
2351 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2351 ui.write('delta size (min/max/avg) : %d / %d / %d\n'
2352 % tuple(deltasize))
2352 % tuple(deltasize))
2353
2353
2354 if numdeltas > 0:
2354 if numdeltas > 0:
2355 ui.write('\n')
2355 ui.write('\n')
2356 fmt = pcfmtstr(numdeltas)
2356 fmt = pcfmtstr(numdeltas)
2357 fmt2 = pcfmtstr(numdeltas, 4)
2357 fmt2 = pcfmtstr(numdeltas, 4)
2358 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2358 ui.write('deltas against prev : ' + fmt % pcfmt(numprev, numdeltas))
2359 if numprev > 0:
2359 if numprev > 0:
2360 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev,
2360 ui.write(' where prev = p1 : ' + fmt2 % pcfmt(nump1prev,
2361 numprev))
2361 numprev))
2362 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev,
2362 ui.write(' where prev = p2 : ' + fmt2 % pcfmt(nump2prev,
2363 numprev))
2363 numprev))
2364 ui.write(' other : ' + fmt2 % pcfmt(numoprev,
2364 ui.write(' other : ' + fmt2 % pcfmt(numoprev,
2365 numprev))
2365 numprev))
2366 if gdelta:
2366 if gdelta:
2367 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2367 ui.write('deltas against p1 : ' + fmt % pcfmt(nump1, numdeltas))
2368 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2368 ui.write('deltas against p2 : ' + fmt % pcfmt(nump2, numdeltas))
2369 ui.write('deltas against other : ' + fmt % pcfmt(numother,
2369 ui.write('deltas against other : ' + fmt % pcfmt(numother,
2370 numdeltas))
2370 numdeltas))
2371
2371
2372 @command('debugrevspec', [], ('REVSPEC'))
2372 @command('debugrevspec', [], ('REVSPEC'))
2373 def debugrevspec(ui, repo, expr):
2373 def debugrevspec(ui, repo, expr):
2374 """parse and apply a revision specification
2374 """parse and apply a revision specification
2375
2375
2376 Use --verbose to print the parsed tree before and after aliases
2376 Use --verbose to print the parsed tree before and after aliases
2377 expansion.
2377 expansion.
2378 """
2378 """
2379 if ui.verbose:
2379 if ui.verbose:
2380 tree = revset.parse(expr)[0]
2380 tree = revset.parse(expr)[0]
2381 ui.note(revset.prettyformat(tree), "\n")
2381 ui.note(revset.prettyformat(tree), "\n")
2382 newtree = revset.findaliases(ui, tree)
2382 newtree = revset.findaliases(ui, tree)
2383 if newtree != tree:
2383 if newtree != tree:
2384 ui.note(revset.prettyformat(newtree), "\n")
2384 ui.note(revset.prettyformat(newtree), "\n")
2385 func = revset.match(ui, expr)
2385 func = revset.match(ui, expr)
2386 for c in func(repo, range(len(repo))):
2386 for c in func(repo, range(len(repo))):
2387 ui.write("%s\n" % c)
2387 ui.write("%s\n" % c)
2388
2388
2389 @command('debugsetparents', [], _('REV1 [REV2]'))
2389 @command('debugsetparents', [], _('REV1 [REV2]'))
2390 def debugsetparents(ui, repo, rev1, rev2=None):
2390 def debugsetparents(ui, repo, rev1, rev2=None):
2391 """manually set the parents of the current working directory
2391 """manually set the parents of the current working directory
2392
2392
2393 This is useful for writing repository conversion tools, but should
2393 This is useful for writing repository conversion tools, but should
2394 be used with care.
2394 be used with care.
2395
2395
2396 Returns 0 on success.
2396 Returns 0 on success.
2397 """
2397 """
2398
2398
2399 r1 = scmutil.revsingle(repo, rev1).node()
2399 r1 = scmutil.revsingle(repo, rev1).node()
2400 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2400 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2401
2401
2402 wlock = repo.wlock()
2402 wlock = repo.wlock()
2403 try:
2403 try:
2404 repo.setparents(r1, r2)
2404 repo.setparents(r1, r2)
2405 finally:
2405 finally:
2406 wlock.release()
2406 wlock.release()
2407
2407
2408 @command('debugstate',
2408 @command('debugstate',
2409 [('', 'nodates', None, _('do not display the saved mtime')),
2409 [('', 'nodates', None, _('do not display the saved mtime')),
2410 ('', 'datesort', None, _('sort by saved mtime'))],
2410 ('', 'datesort', None, _('sort by saved mtime'))],
2411 _('[OPTION]...'))
2411 _('[OPTION]...'))
2412 def debugstate(ui, repo, nodates=None, datesort=None):
2412 def debugstate(ui, repo, nodates=None, datesort=None):
2413 """show the contents of the current dirstate"""
2413 """show the contents of the current dirstate"""
2414 timestr = ""
2414 timestr = ""
2415 showdate = not nodates
2415 showdate = not nodates
2416 if datesort:
2416 if datesort:
2417 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2417 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2418 else:
2418 else:
2419 keyfunc = None # sort by filename
2419 keyfunc = None # sort by filename
2420 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2420 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2421 if showdate:
2421 if showdate:
2422 if ent[3] == -1:
2422 if ent[3] == -1:
2423 # Pad or slice to locale representation
2423 # Pad or slice to locale representation
2424 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2424 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
2425 time.localtime(0)))
2425 time.localtime(0)))
2426 timestr = 'unset'
2426 timestr = 'unset'
2427 timestr = (timestr[:locale_len] +
2427 timestr = (timestr[:locale_len] +
2428 ' ' * (locale_len - len(timestr)))
2428 ' ' * (locale_len - len(timestr)))
2429 else:
2429 else:
2430 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2430 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2431 time.localtime(ent[3]))
2431 time.localtime(ent[3]))
2432 if ent[1] & 020000:
2432 if ent[1] & 020000:
2433 mode = 'lnk'
2433 mode = 'lnk'
2434 else:
2434 else:
2435 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2435 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2436 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2436 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2437 for f in repo.dirstate.copies():
2437 for f in repo.dirstate.copies():
2438 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2438 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2439
2439
2440 @command('debugsub',
2440 @command('debugsub',
2441 [('r', 'rev', '',
2441 [('r', 'rev', '',
2442 _('revision to check'), _('REV'))],
2442 _('revision to check'), _('REV'))],
2443 _('[-r REV] [REV]'))
2443 _('[-r REV] [REV]'))
2444 def debugsub(ui, repo, rev=None):
2444 def debugsub(ui, repo, rev=None):
2445 ctx = scmutil.revsingle(repo, rev, None)
2445 ctx = scmutil.revsingle(repo, rev, None)
2446 for k, v in sorted(ctx.substate.items()):
2446 for k, v in sorted(ctx.substate.items()):
2447 ui.write('path %s\n' % k)
2447 ui.write('path %s\n' % k)
2448 ui.write(' source %s\n' % v[0])
2448 ui.write(' source %s\n' % v[0])
2449 ui.write(' revision %s\n' % v[1])
2449 ui.write(' revision %s\n' % v[1])
2450
2450
2451 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2451 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'))
2452 def debugwalk(ui, repo, *pats, **opts):
2452 def debugwalk(ui, repo, *pats, **opts):
2453 """show how files match on given patterns"""
2453 """show how files match on given patterns"""
2454 m = scmutil.match(repo[None], pats, opts)
2454 m = scmutil.match(repo[None], pats, opts)
2455 items = list(repo.walk(m))
2455 items = list(repo.walk(m))
2456 if not items:
2456 if not items:
2457 return
2457 return
2458 f = lambda fn: fn
2458 f = lambda fn: fn
2459 if ui.configbool('ui', 'slash') and os.sep != '/':
2459 if ui.configbool('ui', 'slash') and os.sep != '/':
2460 f = lambda fn: util.normpath(fn)
2460 f = lambda fn: util.normpath(fn)
2461 fmt = 'f %%-%ds %%-%ds %%s' % (
2461 fmt = 'f %%-%ds %%-%ds %%s' % (
2462 max([len(abs) for abs in items]),
2462 max([len(abs) for abs in items]),
2463 max([len(m.rel(abs)) for abs in items]))
2463 max([len(m.rel(abs)) for abs in items]))
2464 for abs in items:
2464 for abs in items:
2465 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2465 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
2466 ui.write("%s\n" % line.rstrip())
2466 ui.write("%s\n" % line.rstrip())
2467
2467
2468 @command('debugwireargs',
2468 @command('debugwireargs',
2469 [('', 'three', '', 'three'),
2469 [('', 'three', '', 'three'),
2470 ('', 'four', '', 'four'),
2470 ('', 'four', '', 'four'),
2471 ('', 'five', '', 'five'),
2471 ('', 'five', '', 'five'),
2472 ] + remoteopts,
2472 ] + remoteopts,
2473 _('REPO [OPTIONS]... [ONE [TWO]]'))
2473 _('REPO [OPTIONS]... [ONE [TWO]]'))
2474 def debugwireargs(ui, repopath, *vals, **opts):
2474 def debugwireargs(ui, repopath, *vals, **opts):
2475 repo = hg.peer(ui, opts, repopath)
2475 repo = hg.peer(ui, opts, repopath)
2476 for opt in remoteopts:
2476 for opt in remoteopts:
2477 del opts[opt[1]]
2477 del opts[opt[1]]
2478 args = {}
2478 args = {}
2479 for k, v in opts.iteritems():
2479 for k, v in opts.iteritems():
2480 if v:
2480 if v:
2481 args[k] = v
2481 args[k] = v
2482 # run twice to check that we don't mess up the stream for the next command
2482 # run twice to check that we don't mess up the stream for the next command
2483 res1 = repo.debugwireargs(*vals, **args)
2483 res1 = repo.debugwireargs(*vals, **args)
2484 res2 = repo.debugwireargs(*vals, **args)
2484 res2 = repo.debugwireargs(*vals, **args)
2485 ui.write("%s\n" % res1)
2485 ui.write("%s\n" % res1)
2486 if res1 != res2:
2486 if res1 != res2:
2487 ui.warn("%s\n" % res2)
2487 ui.warn("%s\n" % res2)
2488
2488
2489 @command('^diff',
2489 @command('^diff',
2490 [('r', 'rev', [], _('revision'), _('REV')),
2490 [('r', 'rev', [], _('revision'), _('REV')),
2491 ('c', 'change', '', _('change made by revision'), _('REV'))
2491 ('c', 'change', '', _('change made by revision'), _('REV'))
2492 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2492 ] + diffopts + diffopts2 + walkopts + subrepoopts,
2493 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2493 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'))
2494 def diff(ui, repo, *pats, **opts):
2494 def diff(ui, repo, *pats, **opts):
2495 """diff repository (or selected files)
2495 """diff repository (or selected files)
2496
2496
2497 Show differences between revisions for the specified files.
2497 Show differences between revisions for the specified files.
2498
2498
2499 Differences between files are shown using the unified diff format.
2499 Differences between files are shown using the unified diff format.
2500
2500
2501 .. note::
2501 .. note::
2502 diff may generate unexpected results for merges, as it will
2502 diff may generate unexpected results for merges, as it will
2503 default to comparing against the working directory's first
2503 default to comparing against the working directory's first
2504 parent changeset if no revisions are specified.
2504 parent changeset if no revisions are specified.
2505
2505
2506 When two revision arguments are given, then changes are shown
2506 When two revision arguments are given, then changes are shown
2507 between those revisions. If only one revision is specified then
2507 between those revisions. If only one revision is specified then
2508 that revision is compared to the working directory, and, when no
2508 that revision is compared to the working directory, and, when no
2509 revisions are specified, the working directory files are compared
2509 revisions are specified, the working directory files are compared
2510 to its parent.
2510 to its parent.
2511
2511
2512 Alternatively you can specify -c/--change with a revision to see
2512 Alternatively you can specify -c/--change with a revision to see
2513 the changes in that changeset relative to its first parent.
2513 the changes in that changeset relative to its first parent.
2514
2514
2515 Without the -a/--text option, diff will avoid generating diffs of
2515 Without the -a/--text option, diff will avoid generating diffs of
2516 files it detects as binary. With -a, diff will generate a diff
2516 files it detects as binary. With -a, diff will generate a diff
2517 anyway, probably with undesirable results.
2517 anyway, probably with undesirable results.
2518
2518
2519 Use the -g/--git option to generate diffs in the git extended diff
2519 Use the -g/--git option to generate diffs in the git extended diff
2520 format. For more information, read :hg:`help diffs`.
2520 format. For more information, read :hg:`help diffs`.
2521
2521
2522 .. container:: verbose
2522 .. container:: verbose
2523
2523
2524 Examples:
2524 Examples:
2525
2525
2526 - compare a file in the current working directory to its parent::
2526 - compare a file in the current working directory to its parent::
2527
2527
2528 hg diff foo.c
2528 hg diff foo.c
2529
2529
2530 - compare two historical versions of a directory, with rename info::
2530 - compare two historical versions of a directory, with rename info::
2531
2531
2532 hg diff --git -r 1.0:1.2 lib/
2532 hg diff --git -r 1.0:1.2 lib/
2533
2533
2534 - get change stats relative to the last change on some date::
2534 - get change stats relative to the last change on some date::
2535
2535
2536 hg diff --stat -r "date('may 2')"
2536 hg diff --stat -r "date('may 2')"
2537
2537
2538 - diff all newly-added files that contain a keyword::
2538 - diff all newly-added files that contain a keyword::
2539
2539
2540 hg diff "set:added() and grep(GNU)"
2540 hg diff "set:added() and grep(GNU)"
2541
2541
2542 - compare a revision and its parents::
2542 - compare a revision and its parents::
2543
2543
2544 hg diff -c 9353 # compare against first parent
2544 hg diff -c 9353 # compare against first parent
2545 hg diff -r 9353^:9353 # same using revset syntax
2545 hg diff -r 9353^:9353 # same using revset syntax
2546 hg diff -r 9353^2:9353 # compare against the second parent
2546 hg diff -r 9353^2:9353 # compare against the second parent
2547
2547
2548 Returns 0 on success.
2548 Returns 0 on success.
2549 """
2549 """
2550
2550
2551 revs = opts.get('rev')
2551 revs = opts.get('rev')
2552 change = opts.get('change')
2552 change = opts.get('change')
2553 stat = opts.get('stat')
2553 stat = opts.get('stat')
2554 reverse = opts.get('reverse')
2554 reverse = opts.get('reverse')
2555
2555
2556 if revs and change:
2556 if revs and change:
2557 msg = _('cannot specify --rev and --change at the same time')
2557 msg = _('cannot specify --rev and --change at the same time')
2558 raise util.Abort(msg)
2558 raise util.Abort(msg)
2559 elif change:
2559 elif change:
2560 node2 = scmutil.revsingle(repo, change, None).node()
2560 node2 = scmutil.revsingle(repo, change, None).node()
2561 node1 = repo[node2].p1().node()
2561 node1 = repo[node2].p1().node()
2562 else:
2562 else:
2563 node1, node2 = scmutil.revpair(repo, revs)
2563 node1, node2 = scmutil.revpair(repo, revs)
2564
2564
2565 if reverse:
2565 if reverse:
2566 node1, node2 = node2, node1
2566 node1, node2 = node2, node1
2567
2567
2568 diffopts = patch.diffopts(ui, opts)
2568 diffopts = patch.diffopts(ui, opts)
2569 m = scmutil.match(repo[node2], pats, opts)
2569 m = scmutil.match(repo[node2], pats, opts)
2570 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2570 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
2571 listsubrepos=opts.get('subrepos'))
2571 listsubrepos=opts.get('subrepos'))
2572
2572
2573 @command('^export',
2573 @command('^export',
2574 [('o', 'output', '',
2574 [('o', 'output', '',
2575 _('print output to file with formatted name'), _('FORMAT')),
2575 _('print output to file with formatted name'), _('FORMAT')),
2576 ('', 'switch-parent', None, _('diff against the second parent')),
2576 ('', 'switch-parent', None, _('diff against the second parent')),
2577 ('r', 'rev', [], _('revisions to export'), _('REV')),
2577 ('r', 'rev', [], _('revisions to export'), _('REV')),
2578 ] + diffopts,
2578 ] + diffopts,
2579 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2579 _('[OPTION]... [-o OUTFILESPEC] [-r] REV...'))
2580 def export(ui, repo, *changesets, **opts):
2580 def export(ui, repo, *changesets, **opts):
2581 """dump the header and diffs for one or more changesets
2581 """dump the header and diffs for one or more changesets
2582
2582
2583 Print the changeset header and diffs for one or more revisions.
2583 Print the changeset header and diffs for one or more revisions.
2584
2584
2585 The information shown in the changeset header is: author, date,
2585 The information shown in the changeset header is: author, date,
2586 branch name (if non-default), changeset hash, parent(s) and commit
2586 branch name (if non-default), changeset hash, parent(s) and commit
2587 comment.
2587 comment.
2588
2588
2589 .. note::
2589 .. note::
2590 export may generate unexpected diff output for merge
2590 export may generate unexpected diff output for merge
2591 changesets, as it will compare the merge changeset against its
2591 changesets, as it will compare the merge changeset against its
2592 first parent only.
2592 first parent only.
2593
2593
2594 Output may be to a file, in which case the name of the file is
2594 Output may be to a file, in which case the name of the file is
2595 given using a format string. The formatting rules are as follows:
2595 given using a format string. The formatting rules are as follows:
2596
2596
2597 :``%%``: literal "%" character
2597 :``%%``: literal "%" character
2598 :``%H``: changeset hash (40 hexadecimal digits)
2598 :``%H``: changeset hash (40 hexadecimal digits)
2599 :``%N``: number of patches being generated
2599 :``%N``: number of patches being generated
2600 :``%R``: changeset revision number
2600 :``%R``: changeset revision number
2601 :``%b``: basename of the exporting repository
2601 :``%b``: basename of the exporting repository
2602 :``%h``: short-form changeset hash (12 hexadecimal digits)
2602 :``%h``: short-form changeset hash (12 hexadecimal digits)
2603 :``%m``: first line of the commit message (only alphanumeric characters)
2603 :``%m``: first line of the commit message (only alphanumeric characters)
2604 :``%n``: zero-padded sequence number, starting at 1
2604 :``%n``: zero-padded sequence number, starting at 1
2605 :``%r``: zero-padded changeset revision number
2605 :``%r``: zero-padded changeset revision number
2606
2606
2607 Without the -a/--text option, export will avoid generating diffs
2607 Without the -a/--text option, export will avoid generating diffs
2608 of files it detects as binary. With -a, export will generate a
2608 of files it detects as binary. With -a, export will generate a
2609 diff anyway, probably with undesirable results.
2609 diff anyway, probably with undesirable results.
2610
2610
2611 Use the -g/--git option to generate diffs in the git extended diff
2611 Use the -g/--git option to generate diffs in the git extended diff
2612 format. See :hg:`help diffs` for more information.
2612 format. See :hg:`help diffs` for more information.
2613
2613
2614 With the --switch-parent option, the diff will be against the
2614 With the --switch-parent option, the diff will be against the
2615 second parent. It can be useful to review a merge.
2615 second parent. It can be useful to review a merge.
2616
2616
2617 .. container:: verbose
2617 .. container:: verbose
2618
2618
2619 Examples:
2619 Examples:
2620
2620
2621 - use export and import to transplant a bugfix to the current
2621 - use export and import to transplant a bugfix to the current
2622 branch::
2622 branch::
2623
2623
2624 hg export -r 9353 | hg import -
2624 hg export -r 9353 | hg import -
2625
2625
2626 - export all the changesets between two revisions to a file with
2626 - export all the changesets between two revisions to a file with
2627 rename information::
2627 rename information::
2628
2628
2629 hg export --git -r 123:150 > changes.txt
2629 hg export --git -r 123:150 > changes.txt
2630
2630
2631 - split outgoing changes into a series of patches with
2631 - split outgoing changes into a series of patches with
2632 descriptive names::
2632 descriptive names::
2633
2633
2634 hg export -r "outgoing()" -o "%n-%m.patch"
2634 hg export -r "outgoing()" -o "%n-%m.patch"
2635
2635
2636 Returns 0 on success.
2636 Returns 0 on success.
2637 """
2637 """
2638 changesets += tuple(opts.get('rev', []))
2638 changesets += tuple(opts.get('rev', []))
2639 revs = scmutil.revrange(repo, changesets)
2639 revs = scmutil.revrange(repo, changesets)
2640 if not revs:
2640 if not revs:
2641 raise util.Abort(_("export requires at least one changeset"))
2641 raise util.Abort(_("export requires at least one changeset"))
2642 if len(revs) > 1:
2642 if len(revs) > 1:
2643 ui.note(_('exporting patches:\n'))
2643 ui.note(_('exporting patches:\n'))
2644 else:
2644 else:
2645 ui.note(_('exporting patch:\n'))
2645 ui.note(_('exporting patch:\n'))
2646 cmdutil.export(repo, revs, template=opts.get('output'),
2646 cmdutil.export(repo, revs, template=opts.get('output'),
2647 switch_parent=opts.get('switch_parent'),
2647 switch_parent=opts.get('switch_parent'),
2648 opts=patch.diffopts(ui, opts))
2648 opts=patch.diffopts(ui, opts))
2649
2649
2650 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2650 @command('^forget', walkopts, _('[OPTION]... FILE...'))
2651 def forget(ui, repo, *pats, **opts):
2651 def forget(ui, repo, *pats, **opts):
2652 """forget the specified files on the next commit
2652 """forget the specified files on the next commit
2653
2653
2654 Mark the specified files so they will no longer be tracked
2654 Mark the specified files so they will no longer be tracked
2655 after the next commit.
2655 after the next commit.
2656
2656
2657 This only removes files from the current branch, not from the
2657 This only removes files from the current branch, not from the
2658 entire project history, and it does not delete them from the
2658 entire project history, and it does not delete them from the
2659 working directory.
2659 working directory.
2660
2660
2661 To undo a forget before the next commit, see :hg:`add`.
2661 To undo a forget before the next commit, see :hg:`add`.
2662
2662
2663 .. container:: verbose
2663 .. container:: verbose
2664
2664
2665 Examples:
2665 Examples:
2666
2666
2667 - forget newly-added binary files::
2667 - forget newly-added binary files::
2668
2668
2669 hg forget "set:added() and binary()"
2669 hg forget "set:added() and binary()"
2670
2670
2671 - forget files that would be excluded by .hgignore::
2671 - forget files that would be excluded by .hgignore::
2672
2672
2673 hg forget "set:hgignore()"
2673 hg forget "set:hgignore()"
2674
2674
2675 Returns 0 on success.
2675 Returns 0 on success.
2676 """
2676 """
2677
2677
2678 if not pats:
2678 if not pats:
2679 raise util.Abort(_('no files specified'))
2679 raise util.Abort(_('no files specified'))
2680
2680
2681 m = scmutil.match(repo[None], pats, opts)
2681 m = scmutil.match(repo[None], pats, opts)
2682 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2682 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
2683 return rejected and 1 or 0
2683 return rejected and 1 or 0
2684
2684
2685 @command(
2685 @command(
2686 'graft',
2686 'graft',
2687 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2687 [('r', 'rev', [], _('revisions to graft'), _('REV')),
2688 ('c', 'continue', False, _('resume interrupted graft')),
2688 ('c', 'continue', False, _('resume interrupted graft')),
2689 ('e', 'edit', False, _('invoke editor on commit messages')),
2689 ('e', 'edit', False, _('invoke editor on commit messages')),
2690 ('', 'log', None, _('append graft info to log message')),
2690 ('', 'log', None, _('append graft info to log message')),
2691 ('D', 'currentdate', False,
2691 ('D', 'currentdate', False,
2692 _('record the current date as commit date')),
2692 _('record the current date as commit date')),
2693 ('U', 'currentuser', False,
2693 ('U', 'currentuser', False,
2694 _('record the current user as committer'), _('DATE'))]
2694 _('record the current user as committer'), _('DATE'))]
2695 + commitopts2 + mergetoolopts + dryrunopts,
2695 + commitopts2 + mergetoolopts + dryrunopts,
2696 _('[OPTION]... [-r] REV...'))
2696 _('[OPTION]... [-r] REV...'))
2697 def graft(ui, repo, *revs, **opts):
2697 def graft(ui, repo, *revs, **opts):
2698 '''copy changes from other branches onto the current branch
2698 '''copy changes from other branches onto the current branch
2699
2699
2700 This command uses Mercurial's merge logic to copy individual
2700 This command uses Mercurial's merge logic to copy individual
2701 changes from other branches without merging branches in the
2701 changes from other branches without merging branches in the
2702 history graph. This is sometimes known as 'backporting' or
2702 history graph. This is sometimes known as 'backporting' or
2703 'cherry-picking'. By default, graft will copy user, date, and
2703 'cherry-picking'. By default, graft will copy user, date, and
2704 description from the source changesets.
2704 description from the source changesets.
2705
2705
2706 Changesets that are ancestors of the current revision, that have
2706 Changesets that are ancestors of the current revision, that have
2707 already been grafted, or that are merges will be skipped.
2707 already been grafted, or that are merges will be skipped.
2708
2708
2709 If --log is specified, log messages will have a comment appended
2709 If --log is specified, log messages will have a comment appended
2710 of the form::
2710 of the form::
2711
2711
2712 (grafted from CHANGESETHASH)
2712 (grafted from CHANGESETHASH)
2713
2713
2714 If a graft merge results in conflicts, the graft process is
2714 If a graft merge results in conflicts, the graft process is
2715 interrupted so that the current merge can be manually resolved.
2715 interrupted so that the current merge can be manually resolved.
2716 Once all conflicts are addressed, the graft process can be
2716 Once all conflicts are addressed, the graft process can be
2717 continued with the -c/--continue option.
2717 continued with the -c/--continue option.
2718
2718
2719 .. note::
2719 .. note::
2720 The -c/--continue option does not reapply earlier options.
2720 The -c/--continue option does not reapply earlier options.
2721
2721
2722 .. container:: verbose
2722 .. container:: verbose
2723
2723
2724 Examples:
2724 Examples:
2725
2725
2726 - copy a single change to the stable branch and edit its description::
2726 - copy a single change to the stable branch and edit its description::
2727
2727
2728 hg update stable
2728 hg update stable
2729 hg graft --edit 9393
2729 hg graft --edit 9393
2730
2730
2731 - graft a range of changesets with one exception, updating dates::
2731 - graft a range of changesets with one exception, updating dates::
2732
2732
2733 hg graft -D "2085::2093 and not 2091"
2733 hg graft -D "2085::2093 and not 2091"
2734
2734
2735 - continue a graft after resolving conflicts::
2735 - continue a graft after resolving conflicts::
2736
2736
2737 hg graft -c
2737 hg graft -c
2738
2738
2739 - show the source of a grafted changeset::
2739 - show the source of a grafted changeset::
2740
2740
2741 hg log --debug -r tip
2741 hg log --debug -r tip
2742
2742
2743 Returns 0 on successful completion.
2743 Returns 0 on successful completion.
2744 '''
2744 '''
2745
2745
2746 revs = list(revs)
2746 revs = list(revs)
2747 revs.extend(opts['rev'])
2747 revs.extend(opts['rev'])
2748
2748
2749 if not opts.get('user') and opts.get('currentuser'):
2749 if not opts.get('user') and opts.get('currentuser'):
2750 opts['user'] = ui.username()
2750 opts['user'] = ui.username()
2751 if not opts.get('date') and opts.get('currentdate'):
2751 if not opts.get('date') and opts.get('currentdate'):
2752 opts['date'] = "%d %d" % util.makedate()
2752 opts['date'] = "%d %d" % util.makedate()
2753
2753
2754 editor = None
2754 editor = None
2755 if opts.get('edit'):
2755 if opts.get('edit'):
2756 editor = cmdutil.commitforceeditor
2756 editor = cmdutil.commitforceeditor
2757
2757
2758 cont = False
2758 cont = False
2759 if opts['continue']:
2759 if opts['continue']:
2760 cont = True
2760 cont = True
2761 if revs:
2761 if revs:
2762 raise util.Abort(_("can't specify --continue and revisions"))
2762 raise util.Abort(_("can't specify --continue and revisions"))
2763 # read in unfinished revisions
2763 # read in unfinished revisions
2764 try:
2764 try:
2765 nodes = repo.opener.read('graftstate').splitlines()
2765 nodes = repo.opener.read('graftstate').splitlines()
2766 revs = [repo[node].rev() for node in nodes]
2766 revs = [repo[node].rev() for node in nodes]
2767 except IOError, inst:
2767 except IOError, inst:
2768 if inst.errno != errno.ENOENT:
2768 if inst.errno != errno.ENOENT:
2769 raise
2769 raise
2770 raise util.Abort(_("no graft state found, can't continue"))
2770 raise util.Abort(_("no graft state found, can't continue"))
2771 else:
2771 else:
2772 cmdutil.bailifchanged(repo)
2772 cmdutil.bailifchanged(repo)
2773 if not revs:
2773 if not revs:
2774 raise util.Abort(_('no revisions specified'))
2774 raise util.Abort(_('no revisions specified'))
2775 revs = scmutil.revrange(repo, revs)
2775 revs = scmutil.revrange(repo, revs)
2776
2776
2777 # check for merges
2777 # check for merges
2778 for rev in repo.revs('%ld and merge()', revs):
2778 for rev in repo.revs('%ld and merge()', revs):
2779 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2779 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
2780 revs.remove(rev)
2780 revs.remove(rev)
2781 if not revs:
2781 if not revs:
2782 return -1
2782 return -1
2783
2783
2784 # check for ancestors of dest branch
2784 # check for ancestors of dest branch
2785 for rev in repo.revs('::. and %ld', revs):
2785 for rev in repo.revs('::. and %ld', revs):
2786 ui.warn(_('skipping ancestor revision %s\n') % rev)
2786 ui.warn(_('skipping ancestor revision %s\n') % rev)
2787 revs.remove(rev)
2787 revs.remove(rev)
2788 if not revs:
2788 if not revs:
2789 return -1
2789 return -1
2790
2790
2791 # analyze revs for earlier grafts
2791 # analyze revs for earlier grafts
2792 ids = {}
2792 ids = {}
2793 for ctx in repo.set("%ld", revs):
2793 for ctx in repo.set("%ld", revs):
2794 ids[ctx.hex()] = ctx.rev()
2794 ids[ctx.hex()] = ctx.rev()
2795 n = ctx.extra().get('source')
2795 n = ctx.extra().get('source')
2796 if n:
2796 if n:
2797 ids[n] = ctx.rev()
2797 ids[n] = ctx.rev()
2798
2798
2799 # check ancestors for earlier grafts
2799 # check ancestors for earlier grafts
2800 ui.debug('scanning for duplicate grafts\n')
2800 ui.debug('scanning for duplicate grafts\n')
2801 for ctx in repo.set("::. - ::%ld", revs):
2801 for ctx in repo.set("::. - ::%ld", revs):
2802 n = ctx.extra().get('source')
2802 n = ctx.extra().get('source')
2803 if n in ids:
2803 if n in ids:
2804 r = repo[n].rev()
2804 r = repo[n].rev()
2805 if r in revs:
2805 if r in revs:
2806 ui.warn(_('skipping already grafted revision %s\n') % r)
2806 ui.warn(_('skipping already grafted revision %s\n') % r)
2807 revs.remove(r)
2807 revs.remove(r)
2808 elif ids[n] in revs:
2808 elif ids[n] in revs:
2809 ui.warn(_('skipping already grafted revision %s '
2809 ui.warn(_('skipping already grafted revision %s '
2810 '(same origin %d)\n') % (ids[n], r))
2810 '(same origin %d)\n') % (ids[n], r))
2811 revs.remove(ids[n])
2811 revs.remove(ids[n])
2812 elif ctx.hex() in ids:
2812 elif ctx.hex() in ids:
2813 r = ids[ctx.hex()]
2813 r = ids[ctx.hex()]
2814 ui.warn(_('skipping already grafted revision %s '
2814 ui.warn(_('skipping already grafted revision %s '
2815 '(was grafted from %d)\n') % (r, ctx.rev()))
2815 '(was grafted from %d)\n') % (r, ctx.rev()))
2816 revs.remove(r)
2816 revs.remove(r)
2817 if not revs:
2817 if not revs:
2818 return -1
2818 return -1
2819
2819
2820 wlock = repo.wlock()
2820 wlock = repo.wlock()
2821 try:
2821 try:
2822 for pos, ctx in enumerate(repo.set("%ld", revs)):
2822 for pos, ctx in enumerate(repo.set("%ld", revs)):
2823 current = repo['.']
2823 current = repo['.']
2824
2824
2825 ui.status(_('grafting revision %s\n') % ctx.rev())
2825 ui.status(_('grafting revision %s\n') % ctx.rev())
2826 if opts.get('dry_run'):
2826 if opts.get('dry_run'):
2827 continue
2827 continue
2828
2828
2829 # we don't merge the first commit when continuing
2829 # we don't merge the first commit when continuing
2830 if not cont:
2830 if not cont:
2831 # perform the graft merge with p1(rev) as 'ancestor'
2831 # perform the graft merge with p1(rev) as 'ancestor'
2832 try:
2832 try:
2833 # ui.forcemerge is an internal variable, do not document
2833 # ui.forcemerge is an internal variable, do not document
2834 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2834 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2835 stats = mergemod.update(repo, ctx.node(), True, True, False,
2835 stats = mergemod.update(repo, ctx.node(), True, True, False,
2836 ctx.p1().node())
2836 ctx.p1().node())
2837 finally:
2837 finally:
2838 repo.ui.setconfig('ui', 'forcemerge', '')
2838 repo.ui.setconfig('ui', 'forcemerge', '')
2839 # report any conflicts
2839 # report any conflicts
2840 if stats and stats[3] > 0:
2840 if stats and stats[3] > 0:
2841 # write out state for --continue
2841 # write out state for --continue
2842 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2842 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
2843 repo.opener.write('graftstate', ''.join(nodelines))
2843 repo.opener.write('graftstate', ''.join(nodelines))
2844 raise util.Abort(
2844 raise util.Abort(
2845 _("unresolved conflicts, can't continue"),
2845 _("unresolved conflicts, can't continue"),
2846 hint=_('use hg resolve and hg graft --continue'))
2846 hint=_('use hg resolve and hg graft --continue'))
2847 else:
2847 else:
2848 cont = False
2848 cont = False
2849
2849
2850 # drop the second merge parent
2850 # drop the second merge parent
2851 repo.setparents(current.node(), nullid)
2851 repo.setparents(current.node(), nullid)
2852 repo.dirstate.write()
2852 repo.dirstate.write()
2853 # fix up dirstate for copies and renames
2853 # fix up dirstate for copies and renames
2854 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2854 cmdutil.duplicatecopies(repo, ctx.rev(), ctx.p1().rev())
2855
2855
2856 # commit
2856 # commit
2857 source = ctx.extra().get('source')
2857 source = ctx.extra().get('source')
2858 if not source:
2858 if not source:
2859 source = ctx.hex()
2859 source = ctx.hex()
2860 extra = {'source': source}
2860 extra = {'source': source}
2861 user = ctx.user()
2861 user = ctx.user()
2862 if opts.get('user'):
2862 if opts.get('user'):
2863 user = opts['user']
2863 user = opts['user']
2864 date = ctx.date()
2864 date = ctx.date()
2865 if opts.get('date'):
2865 if opts.get('date'):
2866 date = opts['date']
2866 date = opts['date']
2867 message = ctx.description()
2867 message = ctx.description()
2868 if opts.get('log'):
2868 if opts.get('log'):
2869 message += '\n(grafted from %s)' % ctx.hex()
2869 message += '\n(grafted from %s)' % ctx.hex()
2870 node = repo.commit(text=message, user=user,
2870 node = repo.commit(text=message, user=user,
2871 date=date, extra=extra, editor=editor)
2871 date=date, extra=extra, editor=editor)
2872 if node is None:
2872 if node is None:
2873 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2873 ui.status(_('graft for revision %s is empty\n') % ctx.rev())
2874 finally:
2874 finally:
2875 wlock.release()
2875 wlock.release()
2876
2876
2877 # remove state when we complete successfully
2877 # remove state when we complete successfully
2878 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2878 if not opts.get('dry_run') and os.path.exists(repo.join('graftstate')):
2879 util.unlinkpath(repo.join('graftstate'))
2879 util.unlinkpath(repo.join('graftstate'))
2880
2880
2881 return 0
2881 return 0
2882
2882
2883 @command('grep',
2883 @command('grep',
2884 [('0', 'print0', None, _('end fields with NUL')),
2884 [('0', 'print0', None, _('end fields with NUL')),
2885 ('', 'all', None, _('print all revisions that match')),
2885 ('', 'all', None, _('print all revisions that match')),
2886 ('a', 'text', None, _('treat all files as text')),
2886 ('a', 'text', None, _('treat all files as text')),
2887 ('f', 'follow', None,
2887 ('f', 'follow', None,
2888 _('follow changeset history,'
2888 _('follow changeset history,'
2889 ' or file history across copies and renames')),
2889 ' or file history across copies and renames')),
2890 ('i', 'ignore-case', None, _('ignore case when matching')),
2890 ('i', 'ignore-case', None, _('ignore case when matching')),
2891 ('l', 'files-with-matches', None,
2891 ('l', 'files-with-matches', None,
2892 _('print only filenames and revisions that match')),
2892 _('print only filenames and revisions that match')),
2893 ('n', 'line-number', None, _('print matching line numbers')),
2893 ('n', 'line-number', None, _('print matching line numbers')),
2894 ('r', 'rev', [],
2894 ('r', 'rev', [],
2895 _('only search files changed within revision range'), _('REV')),
2895 _('only search files changed within revision range'), _('REV')),
2896 ('u', 'user', None, _('list the author (long with -v)')),
2896 ('u', 'user', None, _('list the author (long with -v)')),
2897 ('d', 'date', None, _('list the date (short with -q)')),
2897 ('d', 'date', None, _('list the date (short with -q)')),
2898 ] + walkopts,
2898 ] + walkopts,
2899 _('[OPTION]... PATTERN [FILE]...'))
2899 _('[OPTION]... PATTERN [FILE]...'))
2900 def grep(ui, repo, pattern, *pats, **opts):
2900 def grep(ui, repo, pattern, *pats, **opts):
2901 """search for a pattern in specified files and revisions
2901 """search for a pattern in specified files and revisions
2902
2902
2903 Search revisions of files for a regular expression.
2903 Search revisions of files for a regular expression.
2904
2904
2905 This command behaves differently than Unix grep. It only accepts
2905 This command behaves differently than Unix grep. It only accepts
2906 Python/Perl regexps. It searches repository history, not the
2906 Python/Perl regexps. It searches repository history, not the
2907 working directory. It always prints the revision number in which a
2907 working directory. It always prints the revision number in which a
2908 match appears.
2908 match appears.
2909
2909
2910 By default, grep only prints output for the first revision of a
2910 By default, grep only prints output for the first revision of a
2911 file in which it finds a match. To get it to print every revision
2911 file in which it finds a match. To get it to print every revision
2912 that contains a change in match status ("-" for a match that
2912 that contains a change in match status ("-" for a match that
2913 becomes a non-match, or "+" for a non-match that becomes a match),
2913 becomes a non-match, or "+" for a non-match that becomes a match),
2914 use the --all flag.
2914 use the --all flag.
2915
2915
2916 Returns 0 if a match is found, 1 otherwise.
2916 Returns 0 if a match is found, 1 otherwise.
2917 """
2917 """
2918 reflags = re.M
2918 reflags = re.M
2919 if opts.get('ignore_case'):
2919 if opts.get('ignore_case'):
2920 reflags |= re.I
2920 reflags |= re.I
2921 try:
2921 try:
2922 regexp = re.compile(pattern, reflags)
2922 regexp = re.compile(pattern, reflags)
2923 except re.error, inst:
2923 except re.error, inst:
2924 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2924 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
2925 return 1
2925 return 1
2926 sep, eol = ':', '\n'
2926 sep, eol = ':', '\n'
2927 if opts.get('print0'):
2927 if opts.get('print0'):
2928 sep = eol = '\0'
2928 sep = eol = '\0'
2929
2929
2930 getfile = util.lrucachefunc(repo.file)
2930 getfile = util.lrucachefunc(repo.file)
2931
2931
2932 def matchlines(body):
2932 def matchlines(body):
2933 begin = 0
2933 begin = 0
2934 linenum = 0
2934 linenum = 0
2935 while True:
2935 while True:
2936 match = regexp.search(body, begin)
2936 match = regexp.search(body, begin)
2937 if not match:
2937 if not match:
2938 break
2938 break
2939 mstart, mend = match.span()
2939 mstart, mend = match.span()
2940 linenum += body.count('\n', begin, mstart) + 1
2940 linenum += body.count('\n', begin, mstart) + 1
2941 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2941 lstart = body.rfind('\n', begin, mstart) + 1 or begin
2942 begin = body.find('\n', mend) + 1 or len(body) + 1
2942 begin = body.find('\n', mend) + 1 or len(body) + 1
2943 lend = begin - 1
2943 lend = begin - 1
2944 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2944 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
2945
2945
2946 class linestate(object):
2946 class linestate(object):
2947 def __init__(self, line, linenum, colstart, colend):
2947 def __init__(self, line, linenum, colstart, colend):
2948 self.line = line
2948 self.line = line
2949 self.linenum = linenum
2949 self.linenum = linenum
2950 self.colstart = colstart
2950 self.colstart = colstart
2951 self.colend = colend
2951 self.colend = colend
2952
2952
2953 def __hash__(self):
2953 def __hash__(self):
2954 return hash((self.linenum, self.line))
2954 return hash((self.linenum, self.line))
2955
2955
2956 def __eq__(self, other):
2956 def __eq__(self, other):
2957 return self.line == other.line
2957 return self.line == other.line
2958
2958
2959 matches = {}
2959 matches = {}
2960 copies = {}
2960 copies = {}
2961 def grepbody(fn, rev, body):
2961 def grepbody(fn, rev, body):
2962 matches[rev].setdefault(fn, [])
2962 matches[rev].setdefault(fn, [])
2963 m = matches[rev][fn]
2963 m = matches[rev][fn]
2964 for lnum, cstart, cend, line in matchlines(body):
2964 for lnum, cstart, cend, line in matchlines(body):
2965 s = linestate(line, lnum, cstart, cend)
2965 s = linestate(line, lnum, cstart, cend)
2966 m.append(s)
2966 m.append(s)
2967
2967
2968 def difflinestates(a, b):
2968 def difflinestates(a, b):
2969 sm = difflib.SequenceMatcher(None, a, b)
2969 sm = difflib.SequenceMatcher(None, a, b)
2970 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2970 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
2971 if tag == 'insert':
2971 if tag == 'insert':
2972 for i in xrange(blo, bhi):
2972 for i in xrange(blo, bhi):
2973 yield ('+', b[i])
2973 yield ('+', b[i])
2974 elif tag == 'delete':
2974 elif tag == 'delete':
2975 for i in xrange(alo, ahi):
2975 for i in xrange(alo, ahi):
2976 yield ('-', a[i])
2976 yield ('-', a[i])
2977 elif tag == 'replace':
2977 elif tag == 'replace':
2978 for i in xrange(alo, ahi):
2978 for i in xrange(alo, ahi):
2979 yield ('-', a[i])
2979 yield ('-', a[i])
2980 for i in xrange(blo, bhi):
2980 for i in xrange(blo, bhi):
2981 yield ('+', b[i])
2981 yield ('+', b[i])
2982
2982
2983 def display(fn, ctx, pstates, states):
2983 def display(fn, ctx, pstates, states):
2984 rev = ctx.rev()
2984 rev = ctx.rev()
2985 datefunc = ui.quiet and util.shortdate or util.datestr
2985 datefunc = ui.quiet and util.shortdate or util.datestr
2986 found = False
2986 found = False
2987 filerevmatches = {}
2987 filerevmatches = {}
2988 def binary():
2988 def binary():
2989 flog = getfile(fn)
2989 flog = getfile(fn)
2990 return util.binary(flog.read(ctx.filenode(fn)))
2990 return util.binary(flog.read(ctx.filenode(fn)))
2991
2991
2992 if opts.get('all'):
2992 if opts.get('all'):
2993 iter = difflinestates(pstates, states)
2993 iter = difflinestates(pstates, states)
2994 else:
2994 else:
2995 iter = [('', l) for l in states]
2995 iter = [('', l) for l in states]
2996 for change, l in iter:
2996 for change, l in iter:
2997 cols = [fn, str(rev)]
2997 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
2998 before, match, after = None, None, None
2998 before, match, after = None, None, None
2999
2999 if opts.get('line_number'):
3000 if opts.get('line_number'):
3000 cols.append(str(l.linenum))
3001 cols.append((str(l.linenum), 'grep.linenumber'))
3001 if opts.get('all'):
3002 if opts.get('all'):
3002 cols.append(change)
3003 cols.append((change, 'grep.change'))
3003 if opts.get('user'):
3004 if opts.get('user'):
3004 cols.append(ui.shortuser(ctx.user()))
3005 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3005 if opts.get('date'):
3006 if opts.get('date'):
3006 cols.append(datefunc(ctx.date()))
3007 cols.append((datefunc(ctx.date()), 'grep.date'))
3007 if opts.get('files_with_matches'):
3008 if opts.get('files_with_matches'):
3008 c = (fn, rev)
3009 c = (fn, rev)
3009 if c in filerevmatches:
3010 if c in filerevmatches:
3010 continue
3011 continue
3011 filerevmatches[c] = 1
3012 filerevmatches[c] = 1
3012 else:
3013 else:
3013 before = l.line[:l.colstart]
3014 before = l.line[:l.colstart]
3014 match = l.line[l.colstart:l.colend]
3015 match = l.line[l.colstart:l.colend]
3015 after = l.line[l.colend:]
3016 after = l.line[l.colend:]
3016 ui.write(sep.join(cols))
3017 for col, label in cols[:-1]:
3018 ui.write(col, label=label)
3019 ui.write(sep, label='grep.sep')
3020 ui.write(cols[-1][0], label=cols[-1][1])
3017 if before is not None:
3021 if before is not None:
3022 ui.write(sep, label='grep.sep')
3018 if not opts.get('text') and binary():
3023 if not opts.get('text') and binary():
3019 ui.write(sep + " Binary file matches")
3024 ui.write(" Binary file matches")
3020 else:
3025 else:
3021 ui.write(sep + before)
3026 ui.write(before)
3022 ui.write(match, label='grep.match')
3027 ui.write(match, label='grep.match')
3023 ui.write(after)
3028 ui.write(after)
3024 ui.write(eol)
3029 ui.write(eol)
3025 found = True
3030 found = True
3026 return found
3031 return found
3027
3032
3028 skip = {}
3033 skip = {}
3029 revfiles = {}
3034 revfiles = {}
3030 matchfn = scmutil.match(repo[None], pats, opts)
3035 matchfn = scmutil.match(repo[None], pats, opts)
3031 found = False
3036 found = False
3032 follow = opts.get('follow')
3037 follow = opts.get('follow')
3033
3038
3034 def prep(ctx, fns):
3039 def prep(ctx, fns):
3035 rev = ctx.rev()
3040 rev = ctx.rev()
3036 pctx = ctx.p1()
3041 pctx = ctx.p1()
3037 parent = pctx.rev()
3042 parent = pctx.rev()
3038 matches.setdefault(rev, {})
3043 matches.setdefault(rev, {})
3039 matches.setdefault(parent, {})
3044 matches.setdefault(parent, {})
3040 files = revfiles.setdefault(rev, [])
3045 files = revfiles.setdefault(rev, [])
3041 for fn in fns:
3046 for fn in fns:
3042 flog = getfile(fn)
3047 flog = getfile(fn)
3043 try:
3048 try:
3044 fnode = ctx.filenode(fn)
3049 fnode = ctx.filenode(fn)
3045 except error.LookupError:
3050 except error.LookupError:
3046 continue
3051 continue
3047
3052
3048 copied = flog.renamed(fnode)
3053 copied = flog.renamed(fnode)
3049 copy = follow and copied and copied[0]
3054 copy = follow and copied and copied[0]
3050 if copy:
3055 if copy:
3051 copies.setdefault(rev, {})[fn] = copy
3056 copies.setdefault(rev, {})[fn] = copy
3052 if fn in skip:
3057 if fn in skip:
3053 if copy:
3058 if copy:
3054 skip[copy] = True
3059 skip[copy] = True
3055 continue
3060 continue
3056 files.append(fn)
3061 files.append(fn)
3057
3062
3058 if fn not in matches[rev]:
3063 if fn not in matches[rev]:
3059 grepbody(fn, rev, flog.read(fnode))
3064 grepbody(fn, rev, flog.read(fnode))
3060
3065
3061 pfn = copy or fn
3066 pfn = copy or fn
3062 if pfn not in matches[parent]:
3067 if pfn not in matches[parent]:
3063 try:
3068 try:
3064 fnode = pctx.filenode(pfn)
3069 fnode = pctx.filenode(pfn)
3065 grepbody(pfn, parent, flog.read(fnode))
3070 grepbody(pfn, parent, flog.read(fnode))
3066 except error.LookupError:
3071 except error.LookupError:
3067 pass
3072 pass
3068
3073
3069 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3074 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3070 rev = ctx.rev()
3075 rev = ctx.rev()
3071 parent = ctx.p1().rev()
3076 parent = ctx.p1().rev()
3072 for fn in sorted(revfiles.get(rev, [])):
3077 for fn in sorted(revfiles.get(rev, [])):
3073 states = matches[rev][fn]
3078 states = matches[rev][fn]
3074 copy = copies.get(rev, {}).get(fn)
3079 copy = copies.get(rev, {}).get(fn)
3075 if fn in skip:
3080 if fn in skip:
3076 if copy:
3081 if copy:
3077 skip[copy] = True
3082 skip[copy] = True
3078 continue
3083 continue
3079 pstates = matches.get(parent, {}).get(copy or fn, [])
3084 pstates = matches.get(parent, {}).get(copy or fn, [])
3080 if pstates or states:
3085 if pstates or states:
3081 r = display(fn, ctx, pstates, states)
3086 r = display(fn, ctx, pstates, states)
3082 found = found or r
3087 found = found or r
3083 if r and not opts.get('all'):
3088 if r and not opts.get('all'):
3084 skip[fn] = True
3089 skip[fn] = True
3085 if copy:
3090 if copy:
3086 skip[copy] = True
3091 skip[copy] = True
3087 del matches[rev]
3092 del matches[rev]
3088 del revfiles[rev]
3093 del revfiles[rev]
3089
3094
3090 return not found
3095 return not found
3091
3096
3092 @command('heads',
3097 @command('heads',
3093 [('r', 'rev', '',
3098 [('r', 'rev', '',
3094 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3099 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3095 ('t', 'topo', False, _('show topological heads only')),
3100 ('t', 'topo', False, _('show topological heads only')),
3096 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3101 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3097 ('c', 'closed', False, _('show normal and closed branch heads')),
3102 ('c', 'closed', False, _('show normal and closed branch heads')),
3098 ] + templateopts,
3103 ] + templateopts,
3099 _('[-ct] [-r STARTREV] [REV]...'))
3104 _('[-ct] [-r STARTREV] [REV]...'))
3100 def heads(ui, repo, *branchrevs, **opts):
3105 def heads(ui, repo, *branchrevs, **opts):
3101 """show current repository heads or show branch heads
3106 """show current repository heads or show branch heads
3102
3107
3103 With no arguments, show all repository branch heads.
3108 With no arguments, show all repository branch heads.
3104
3109
3105 Repository "heads" are changesets with no child changesets. They are
3110 Repository "heads" are changesets with no child changesets. They are
3106 where development generally takes place and are the usual targets
3111 where development generally takes place and are the usual targets
3107 for update and merge operations. Branch heads are changesets that have
3112 for update and merge operations. Branch heads are changesets that have
3108 no child changeset on the same branch.
3113 no child changeset on the same branch.
3109
3114
3110 If one or more REVs are given, only branch heads on the branches
3115 If one or more REVs are given, only branch heads on the branches
3111 associated with the specified changesets are shown. This means
3116 associated with the specified changesets are shown. This means
3112 that you can use :hg:`heads foo` to see the heads on a branch
3117 that you can use :hg:`heads foo` to see the heads on a branch
3113 named ``foo``.
3118 named ``foo``.
3114
3119
3115 If -c/--closed is specified, also show branch heads marked closed
3120 If -c/--closed is specified, also show branch heads marked closed
3116 (see :hg:`commit --close-branch`).
3121 (see :hg:`commit --close-branch`).
3117
3122
3118 If STARTREV is specified, only those heads that are descendants of
3123 If STARTREV is specified, only those heads that are descendants of
3119 STARTREV will be displayed.
3124 STARTREV will be displayed.
3120
3125
3121 If -t/--topo is specified, named branch mechanics will be ignored and only
3126 If -t/--topo is specified, named branch mechanics will be ignored and only
3122 changesets without children will be shown.
3127 changesets without children will be shown.
3123
3128
3124 Returns 0 if matching heads are found, 1 if not.
3129 Returns 0 if matching heads are found, 1 if not.
3125 """
3130 """
3126
3131
3127 start = None
3132 start = None
3128 if 'rev' in opts:
3133 if 'rev' in opts:
3129 start = scmutil.revsingle(repo, opts['rev'], None).node()
3134 start = scmutil.revsingle(repo, opts['rev'], None).node()
3130
3135
3131 if opts.get('topo'):
3136 if opts.get('topo'):
3132 heads = [repo[h] for h in repo.heads(start)]
3137 heads = [repo[h] for h in repo.heads(start)]
3133 else:
3138 else:
3134 heads = []
3139 heads = []
3135 for branch in repo.branchmap():
3140 for branch in repo.branchmap():
3136 heads += repo.branchheads(branch, start, opts.get('closed'))
3141 heads += repo.branchheads(branch, start, opts.get('closed'))
3137 heads = [repo[h] for h in heads]
3142 heads = [repo[h] for h in heads]
3138
3143
3139 if branchrevs:
3144 if branchrevs:
3140 branches = set(repo[br].branch() for br in branchrevs)
3145 branches = set(repo[br].branch() for br in branchrevs)
3141 heads = [h for h in heads if h.branch() in branches]
3146 heads = [h for h in heads if h.branch() in branches]
3142
3147
3143 if opts.get('active') and branchrevs:
3148 if opts.get('active') and branchrevs:
3144 dagheads = repo.heads(start)
3149 dagheads = repo.heads(start)
3145 heads = [h for h in heads if h.node() in dagheads]
3150 heads = [h for h in heads if h.node() in dagheads]
3146
3151
3147 if branchrevs:
3152 if branchrevs:
3148 haveheads = set(h.branch() for h in heads)
3153 haveheads = set(h.branch() for h in heads)
3149 if branches - haveheads:
3154 if branches - haveheads:
3150 headless = ', '.join(b for b in branches - haveheads)
3155 headless = ', '.join(b for b in branches - haveheads)
3151 msg = _('no open branch heads found on branches %s')
3156 msg = _('no open branch heads found on branches %s')
3152 if opts.get('rev'):
3157 if opts.get('rev'):
3153 msg += _(' (started at %s)') % opts['rev']
3158 msg += _(' (started at %s)') % opts['rev']
3154 ui.warn((msg + '\n') % headless)
3159 ui.warn((msg + '\n') % headless)
3155
3160
3156 if not heads:
3161 if not heads:
3157 return 1
3162 return 1
3158
3163
3159 heads = sorted(heads, key=lambda x: -x.rev())
3164 heads = sorted(heads, key=lambda x: -x.rev())
3160 displayer = cmdutil.show_changeset(ui, repo, opts)
3165 displayer = cmdutil.show_changeset(ui, repo, opts)
3161 for ctx in heads:
3166 for ctx in heads:
3162 displayer.show(ctx)
3167 displayer.show(ctx)
3163 displayer.close()
3168 displayer.close()
3164
3169
3165 @command('help',
3170 @command('help',
3166 [('e', 'extension', None, _('show only help for extensions')),
3171 [('e', 'extension', None, _('show only help for extensions')),
3167 ('c', 'command', None, _('show only help for commands')),
3172 ('c', 'command', None, _('show only help for commands')),
3168 ('k', 'keyword', '', _('show topics matching keyword')),
3173 ('k', 'keyword', '', _('show topics matching keyword')),
3169 ],
3174 ],
3170 _('[-ec] [TOPIC]'))
3175 _('[-ec] [TOPIC]'))
3171 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3176 def help_(ui, name=None, unknowncmd=False, full=True, **opts):
3172 """show help for a given topic or a help overview
3177 """show help for a given topic or a help overview
3173
3178
3174 With no arguments, print a list of commands with short help messages.
3179 With no arguments, print a list of commands with short help messages.
3175
3180
3176 Given a topic, extension, or command name, print help for that
3181 Given a topic, extension, or command name, print help for that
3177 topic.
3182 topic.
3178
3183
3179 Returns 0 if successful.
3184 Returns 0 if successful.
3180 """
3185 """
3181
3186
3182 textwidth = min(ui.termwidth(), 80) - 2
3187 textwidth = min(ui.termwidth(), 80) - 2
3183
3188
3184 def helpcmd(name):
3189 def helpcmd(name):
3185 try:
3190 try:
3186 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3191 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
3187 except error.AmbiguousCommand, inst:
3192 except error.AmbiguousCommand, inst:
3188 # py3k fix: except vars can't be used outside the scope of the
3193 # py3k fix: except vars can't be used outside the scope of the
3189 # except block, nor can be used inside a lambda. python issue4617
3194 # except block, nor can be used inside a lambda. python issue4617
3190 prefix = inst.args[0]
3195 prefix = inst.args[0]
3191 select = lambda c: c.lstrip('^').startswith(prefix)
3196 select = lambda c: c.lstrip('^').startswith(prefix)
3192 rst = helplist(select)
3197 rst = helplist(select)
3193 return rst
3198 return rst
3194
3199
3195 rst = []
3200 rst = []
3196
3201
3197 # check if it's an invalid alias and display its error if it is
3202 # check if it's an invalid alias and display its error if it is
3198 if getattr(entry[0], 'badalias', False):
3203 if getattr(entry[0], 'badalias', False):
3199 if not unknowncmd:
3204 if not unknowncmd:
3200 ui.pushbuffer()
3205 ui.pushbuffer()
3201 entry[0](ui)
3206 entry[0](ui)
3202 rst.append(ui.popbuffer())
3207 rst.append(ui.popbuffer())
3203 return rst
3208 return rst
3204
3209
3205 # synopsis
3210 # synopsis
3206 if len(entry) > 2:
3211 if len(entry) > 2:
3207 if entry[2].startswith('hg'):
3212 if entry[2].startswith('hg'):
3208 rst.append("%s\n" % entry[2])
3213 rst.append("%s\n" % entry[2])
3209 else:
3214 else:
3210 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3215 rst.append('hg %s %s\n' % (aliases[0], entry[2]))
3211 else:
3216 else:
3212 rst.append('hg %s\n' % aliases[0])
3217 rst.append('hg %s\n' % aliases[0])
3213 # aliases
3218 # aliases
3214 if full and not ui.quiet and len(aliases) > 1:
3219 if full and not ui.quiet and len(aliases) > 1:
3215 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3220 rst.append(_("\naliases: %s\n") % ', '.join(aliases[1:]))
3216 rst.append('\n')
3221 rst.append('\n')
3217
3222
3218 # description
3223 # description
3219 doc = gettext(entry[0].__doc__)
3224 doc = gettext(entry[0].__doc__)
3220 if not doc:
3225 if not doc:
3221 doc = _("(no help text available)")
3226 doc = _("(no help text available)")
3222 if util.safehasattr(entry[0], 'definition'): # aliased command
3227 if util.safehasattr(entry[0], 'definition'): # aliased command
3223 if entry[0].definition.startswith('!'): # shell alias
3228 if entry[0].definition.startswith('!'): # shell alias
3224 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3229 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
3225 else:
3230 else:
3226 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3231 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
3227 doc = doc.splitlines(True)
3232 doc = doc.splitlines(True)
3228 if ui.quiet or not full:
3233 if ui.quiet or not full:
3229 rst.append(doc[0])
3234 rst.append(doc[0])
3230 else:
3235 else:
3231 rst.extend(doc)
3236 rst.extend(doc)
3232 rst.append('\n')
3237 rst.append('\n')
3233
3238
3234 # check if this command shadows a non-trivial (multi-line)
3239 # check if this command shadows a non-trivial (multi-line)
3235 # extension help text
3240 # extension help text
3236 try:
3241 try:
3237 mod = extensions.find(name)
3242 mod = extensions.find(name)
3238 doc = gettext(mod.__doc__) or ''
3243 doc = gettext(mod.__doc__) or ''
3239 if '\n' in doc.strip():
3244 if '\n' in doc.strip():
3240 msg = _('use "hg help -e %s" to show help for '
3245 msg = _('use "hg help -e %s" to show help for '
3241 'the %s extension') % (name, name)
3246 'the %s extension') % (name, name)
3242 rst.append('\n%s\n' % msg)
3247 rst.append('\n%s\n' % msg)
3243 except KeyError:
3248 except KeyError:
3244 pass
3249 pass
3245
3250
3246 # options
3251 # options
3247 if not ui.quiet and entry[1]:
3252 if not ui.quiet and entry[1]:
3248 rst.append('\n%s\n\n' % _("options:"))
3253 rst.append('\n%s\n\n' % _("options:"))
3249 rst.append(help.optrst(entry[1], ui.verbose))
3254 rst.append(help.optrst(entry[1], ui.verbose))
3250
3255
3251 if ui.verbose:
3256 if ui.verbose:
3252 rst.append('\n%s\n\n' % _("global options:"))
3257 rst.append('\n%s\n\n' % _("global options:"))
3253 rst.append(help.optrst(globalopts, ui.verbose))
3258 rst.append(help.optrst(globalopts, ui.verbose))
3254
3259
3255 if not ui.verbose:
3260 if not ui.verbose:
3256 if not full:
3261 if not full:
3257 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3262 rst.append(_('\nuse "hg help %s" to show the full help text\n')
3258 % name)
3263 % name)
3259 elif not ui.quiet:
3264 elif not ui.quiet:
3260 rst.append(_('\nuse "hg -v help %s" to show more info\n')
3265 rst.append(_('\nuse "hg -v help %s" to show more info\n')
3261 % name)
3266 % name)
3262 return rst
3267 return rst
3263
3268
3264
3269
3265 def helplist(select=None):
3270 def helplist(select=None):
3266 # list of commands
3271 # list of commands
3267 if name == "shortlist":
3272 if name == "shortlist":
3268 header = _('basic commands:\n\n')
3273 header = _('basic commands:\n\n')
3269 else:
3274 else:
3270 header = _('list of commands:\n\n')
3275 header = _('list of commands:\n\n')
3271
3276
3272 h = {}
3277 h = {}
3273 cmds = {}
3278 cmds = {}
3274 for c, e in table.iteritems():
3279 for c, e in table.iteritems():
3275 f = c.split("|", 1)[0]
3280 f = c.split("|", 1)[0]
3276 if select and not select(f):
3281 if select and not select(f):
3277 continue
3282 continue
3278 if (not select and name != 'shortlist' and
3283 if (not select and name != 'shortlist' and
3279 e[0].__module__ != __name__):
3284 e[0].__module__ != __name__):
3280 continue
3285 continue
3281 if name == "shortlist" and not f.startswith("^"):
3286 if name == "shortlist" and not f.startswith("^"):
3282 continue
3287 continue
3283 f = f.lstrip("^")
3288 f = f.lstrip("^")
3284 if not ui.debugflag and f.startswith("debug"):
3289 if not ui.debugflag and f.startswith("debug"):
3285 continue
3290 continue
3286 doc = e[0].__doc__
3291 doc = e[0].__doc__
3287 if doc and 'DEPRECATED' in doc and not ui.verbose:
3292 if doc and 'DEPRECATED' in doc and not ui.verbose:
3288 continue
3293 continue
3289 doc = gettext(doc)
3294 doc = gettext(doc)
3290 if not doc:
3295 if not doc:
3291 doc = _("(no help text available)")
3296 doc = _("(no help text available)")
3292 h[f] = doc.splitlines()[0].rstrip()
3297 h[f] = doc.splitlines()[0].rstrip()
3293 cmds[f] = c.lstrip("^")
3298 cmds[f] = c.lstrip("^")
3294
3299
3295 rst = []
3300 rst = []
3296 if not h:
3301 if not h:
3297 if not ui.quiet:
3302 if not ui.quiet:
3298 rst.append(_('no commands defined\n'))
3303 rst.append(_('no commands defined\n'))
3299 return rst
3304 return rst
3300
3305
3301 if not ui.quiet:
3306 if not ui.quiet:
3302 rst.append(header)
3307 rst.append(header)
3303 fns = sorted(h)
3308 fns = sorted(h)
3304 for f in fns:
3309 for f in fns:
3305 if ui.verbose:
3310 if ui.verbose:
3306 commands = cmds[f].replace("|",", ")
3311 commands = cmds[f].replace("|",", ")
3307 rst.append(" :%s: %s\n" % (commands, h[f]))
3312 rst.append(" :%s: %s\n" % (commands, h[f]))
3308 else:
3313 else:
3309 rst.append(' :%s: %s\n' % (f, h[f]))
3314 rst.append(' :%s: %s\n' % (f, h[f]))
3310
3315
3311 if not name:
3316 if not name:
3312 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3317 exts = help.listexts(_('enabled extensions:'), extensions.enabled())
3313 if exts:
3318 if exts:
3314 rst.append('\n')
3319 rst.append('\n')
3315 rst.extend(exts)
3320 rst.extend(exts)
3316
3321
3317 rst.append(_("\nadditional help topics:\n\n"))
3322 rst.append(_("\nadditional help topics:\n\n"))
3318 topics = []
3323 topics = []
3319 for names, header, doc in help.helptable:
3324 for names, header, doc in help.helptable:
3320 topics.append((names[0], header))
3325 topics.append((names[0], header))
3321 for t, desc in topics:
3326 for t, desc in topics:
3322 rst.append(" :%s: %s\n" % (t, desc))
3327 rst.append(" :%s: %s\n" % (t, desc))
3323
3328
3324 optlist = []
3329 optlist = []
3325 if not ui.quiet:
3330 if not ui.quiet:
3326 if ui.verbose:
3331 if ui.verbose:
3327 optlist.append((_("global options:"), globalopts))
3332 optlist.append((_("global options:"), globalopts))
3328 if name == 'shortlist':
3333 if name == 'shortlist':
3329 optlist.append((_('use "hg help" for the full list '
3334 optlist.append((_('use "hg help" for the full list '
3330 'of commands'), ()))
3335 'of commands'), ()))
3331 else:
3336 else:
3332 if name == 'shortlist':
3337 if name == 'shortlist':
3333 msg = _('use "hg help" for the full list of commands '
3338 msg = _('use "hg help" for the full list of commands '
3334 'or "hg -v" for details')
3339 'or "hg -v" for details')
3335 elif name and not full:
3340 elif name and not full:
3336 msg = _('use "hg help %s" to show the full help '
3341 msg = _('use "hg help %s" to show the full help '
3337 'text') % name
3342 'text') % name
3338 else:
3343 else:
3339 msg = _('use "hg -v help%s" to show builtin aliases and '
3344 msg = _('use "hg -v help%s" to show builtin aliases and '
3340 'global options') % (name and " " + name or "")
3345 'global options') % (name and " " + name or "")
3341 optlist.append((msg, ()))
3346 optlist.append((msg, ()))
3342
3347
3343 if optlist:
3348 if optlist:
3344 for title, options in optlist:
3349 for title, options in optlist:
3345 rst.append('\n%s\n' % title)
3350 rst.append('\n%s\n' % title)
3346 if options:
3351 if options:
3347 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3352 rst.append('\n%s\n' % help.optrst(options, ui.verbose))
3348 return rst
3353 return rst
3349
3354
3350 def helptopic(name):
3355 def helptopic(name):
3351 for names, header, doc in help.helptable:
3356 for names, header, doc in help.helptable:
3352 if name in names:
3357 if name in names:
3353 break
3358 break
3354 else:
3359 else:
3355 raise error.UnknownCommand(name)
3360 raise error.UnknownCommand(name)
3356
3361
3357 rst = ["%s\n\n" % header]
3362 rst = ["%s\n\n" % header]
3358 # description
3363 # description
3359 if not doc:
3364 if not doc:
3360 rst.append(" %s\n" % _("(no help text available)"))
3365 rst.append(" %s\n" % _("(no help text available)"))
3361 if util.safehasattr(doc, '__call__'):
3366 if util.safehasattr(doc, '__call__'):
3362 rst += [" %s\n" % l for l in doc().splitlines()]
3367 rst += [" %s\n" % l for l in doc().splitlines()]
3363
3368
3364 try:
3369 try:
3365 cmdutil.findcmd(name, table)
3370 cmdutil.findcmd(name, table)
3366 rst.append(_('\nuse "hg help -c %s" to see help for '
3371 rst.append(_('\nuse "hg help -c %s" to see help for '
3367 'the %s command\n') % (name, name))
3372 'the %s command\n') % (name, name))
3368 except error.UnknownCommand:
3373 except error.UnknownCommand:
3369 pass
3374 pass
3370 return rst
3375 return rst
3371
3376
3372 def helpext(name):
3377 def helpext(name):
3373 try:
3378 try:
3374 mod = extensions.find(name)
3379 mod = extensions.find(name)
3375 doc = gettext(mod.__doc__) or _('no help text available')
3380 doc = gettext(mod.__doc__) or _('no help text available')
3376 except KeyError:
3381 except KeyError:
3377 mod = None
3382 mod = None
3378 doc = extensions.disabledext(name)
3383 doc = extensions.disabledext(name)
3379 if not doc:
3384 if not doc:
3380 raise error.UnknownCommand(name)
3385 raise error.UnknownCommand(name)
3381
3386
3382 if '\n' not in doc:
3387 if '\n' not in doc:
3383 head, tail = doc, ""
3388 head, tail = doc, ""
3384 else:
3389 else:
3385 head, tail = doc.split('\n', 1)
3390 head, tail = doc.split('\n', 1)
3386 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3391 rst = [_('%s extension - %s\n\n') % (name.split('.')[-1], head)]
3387 if tail:
3392 if tail:
3388 rst.extend(tail.splitlines(True))
3393 rst.extend(tail.splitlines(True))
3389 rst.append('\n')
3394 rst.append('\n')
3390
3395
3391 if mod:
3396 if mod:
3392 try:
3397 try:
3393 ct = mod.cmdtable
3398 ct = mod.cmdtable
3394 except AttributeError:
3399 except AttributeError:
3395 ct = {}
3400 ct = {}
3396 modcmds = set([c.split('|', 1)[0] for c in ct])
3401 modcmds = set([c.split('|', 1)[0] for c in ct])
3397 rst.extend(helplist(modcmds.__contains__))
3402 rst.extend(helplist(modcmds.__contains__))
3398 else:
3403 else:
3399 rst.append(_('use "hg help extensions" for information on enabling '
3404 rst.append(_('use "hg help extensions" for information on enabling '
3400 'extensions\n'))
3405 'extensions\n'))
3401 return rst
3406 return rst
3402
3407
3403 def helpextcmd(name):
3408 def helpextcmd(name):
3404 cmd, ext, mod = extensions.disabledcmd(ui, name,
3409 cmd, ext, mod = extensions.disabledcmd(ui, name,
3405 ui.configbool('ui', 'strict'))
3410 ui.configbool('ui', 'strict'))
3406 doc = gettext(mod.__doc__).splitlines()[0]
3411 doc = gettext(mod.__doc__).splitlines()[0]
3407
3412
3408 rst = help.listexts(_("'%s' is provided by the following "
3413 rst = help.listexts(_("'%s' is provided by the following "
3409 "extension:") % cmd, {ext: doc}, indent=4)
3414 "extension:") % cmd, {ext: doc}, indent=4)
3410 rst.append('\n')
3415 rst.append('\n')
3411 rst.append(_('use "hg help extensions" for information on enabling '
3416 rst.append(_('use "hg help extensions" for information on enabling '
3412 'extensions\n'))
3417 'extensions\n'))
3413 return rst
3418 return rst
3414
3419
3415
3420
3416 rst = []
3421 rst = []
3417 kw = opts.get('keyword')
3422 kw = opts.get('keyword')
3418 if kw:
3423 if kw:
3419 matches = help.topicmatch(kw)
3424 matches = help.topicmatch(kw)
3420 for t, title in (('topics', _('Topics')),
3425 for t, title in (('topics', _('Topics')),
3421 ('commands', _('Commands')),
3426 ('commands', _('Commands')),
3422 ('extensions', _('Extensions')),
3427 ('extensions', _('Extensions')),
3423 ('extensioncommands', _('Extension Commands'))):
3428 ('extensioncommands', _('Extension Commands'))):
3424 if matches[t]:
3429 if matches[t]:
3425 rst.append('%s:\n\n' % title)
3430 rst.append('%s:\n\n' % title)
3426 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3431 rst.extend(minirst.maketable(sorted(matches[t]), 1))
3427 rst.append('\n')
3432 rst.append('\n')
3428 elif name and name != 'shortlist':
3433 elif name and name != 'shortlist':
3429 i = None
3434 i = None
3430 if unknowncmd:
3435 if unknowncmd:
3431 queries = (helpextcmd,)
3436 queries = (helpextcmd,)
3432 elif opts.get('extension'):
3437 elif opts.get('extension'):
3433 queries = (helpext,)
3438 queries = (helpext,)
3434 elif opts.get('command'):
3439 elif opts.get('command'):
3435 queries = (helpcmd,)
3440 queries = (helpcmd,)
3436 else:
3441 else:
3437 queries = (helptopic, helpcmd, helpext, helpextcmd)
3442 queries = (helptopic, helpcmd, helpext, helpextcmd)
3438 for f in queries:
3443 for f in queries:
3439 try:
3444 try:
3440 rst = f(name)
3445 rst = f(name)
3441 i = None
3446 i = None
3442 break
3447 break
3443 except error.UnknownCommand, inst:
3448 except error.UnknownCommand, inst:
3444 i = inst
3449 i = inst
3445 if i:
3450 if i:
3446 raise i
3451 raise i
3447 else:
3452 else:
3448 # program name
3453 # program name
3449 if not ui.quiet:
3454 if not ui.quiet:
3450 rst = [_("Mercurial Distributed SCM\n"), '\n']
3455 rst = [_("Mercurial Distributed SCM\n"), '\n']
3451 rst.extend(helplist())
3456 rst.extend(helplist())
3452
3457
3453 keep = ui.verbose and ['verbose'] or []
3458 keep = ui.verbose and ['verbose'] or []
3454 formatted, pruned = minirst.format(''.join(rst), textwidth, keep=keep)
3459 formatted, pruned = minirst.format(''.join(rst), textwidth, keep=keep)
3455 ui.write(formatted)
3460 ui.write(formatted)
3456
3461
3457
3462
3458 @command('identify|id',
3463 @command('identify|id',
3459 [('r', 'rev', '',
3464 [('r', 'rev', '',
3460 _('identify the specified revision'), _('REV')),
3465 _('identify the specified revision'), _('REV')),
3461 ('n', 'num', None, _('show local revision number')),
3466 ('n', 'num', None, _('show local revision number')),
3462 ('i', 'id', None, _('show global revision id')),
3467 ('i', 'id', None, _('show global revision id')),
3463 ('b', 'branch', None, _('show branch')),
3468 ('b', 'branch', None, _('show branch')),
3464 ('t', 'tags', None, _('show tags')),
3469 ('t', 'tags', None, _('show tags')),
3465 ('B', 'bookmarks', None, _('show bookmarks')),
3470 ('B', 'bookmarks', None, _('show bookmarks')),
3466 ] + remoteopts,
3471 ] + remoteopts,
3467 _('[-nibtB] [-r REV] [SOURCE]'))
3472 _('[-nibtB] [-r REV] [SOURCE]'))
3468 def identify(ui, repo, source=None, rev=None,
3473 def identify(ui, repo, source=None, rev=None,
3469 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3474 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3470 """identify the working copy or specified revision
3475 """identify the working copy or specified revision
3471
3476
3472 Print a summary identifying the repository state at REV using one or
3477 Print a summary identifying the repository state at REV using one or
3473 two parent hash identifiers, followed by a "+" if the working
3478 two parent hash identifiers, followed by a "+" if the working
3474 directory has uncommitted changes, the branch name (if not default),
3479 directory has uncommitted changes, the branch name (if not default),
3475 a list of tags, and a list of bookmarks.
3480 a list of tags, and a list of bookmarks.
3476
3481
3477 When REV is not given, print a summary of the current state of the
3482 When REV is not given, print a summary of the current state of the
3478 repository.
3483 repository.
3479
3484
3480 Specifying a path to a repository root or Mercurial bundle will
3485 Specifying a path to a repository root or Mercurial bundle will
3481 cause lookup to operate on that repository/bundle.
3486 cause lookup to operate on that repository/bundle.
3482
3487
3483 .. container:: verbose
3488 .. container:: verbose
3484
3489
3485 Examples:
3490 Examples:
3486
3491
3487 - generate a build identifier for the working directory::
3492 - generate a build identifier for the working directory::
3488
3493
3489 hg id --id > build-id.dat
3494 hg id --id > build-id.dat
3490
3495
3491 - find the revision corresponding to a tag::
3496 - find the revision corresponding to a tag::
3492
3497
3493 hg id -n -r 1.3
3498 hg id -n -r 1.3
3494
3499
3495 - check the most recent revision of a remote repository::
3500 - check the most recent revision of a remote repository::
3496
3501
3497 hg id -r tip http://selenic.com/hg/
3502 hg id -r tip http://selenic.com/hg/
3498
3503
3499 Returns 0 if successful.
3504 Returns 0 if successful.
3500 """
3505 """
3501
3506
3502 if not repo and not source:
3507 if not repo and not source:
3503 raise util.Abort(_("there is no Mercurial repository here "
3508 raise util.Abort(_("there is no Mercurial repository here "
3504 "(.hg not found)"))
3509 "(.hg not found)"))
3505
3510
3506 hexfunc = ui.debugflag and hex or short
3511 hexfunc = ui.debugflag and hex or short
3507 default = not (num or id or branch or tags or bookmarks)
3512 default = not (num or id or branch or tags or bookmarks)
3508 output = []
3513 output = []
3509 revs = []
3514 revs = []
3510
3515
3511 if source:
3516 if source:
3512 source, branches = hg.parseurl(ui.expandpath(source))
3517 source, branches = hg.parseurl(ui.expandpath(source))
3513 peer = hg.peer(ui, opts, source)
3518 peer = hg.peer(ui, opts, source)
3514 repo = peer.local()
3519 repo = peer.local()
3515 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3520 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3516
3521
3517 if not repo:
3522 if not repo:
3518 if num or branch or tags:
3523 if num or branch or tags:
3519 raise util.Abort(
3524 raise util.Abort(
3520 _("can't query remote revision number, branch, or tags"))
3525 _("can't query remote revision number, branch, or tags"))
3521 if not rev and revs:
3526 if not rev and revs:
3522 rev = revs[0]
3527 rev = revs[0]
3523 if not rev:
3528 if not rev:
3524 rev = "tip"
3529 rev = "tip"
3525
3530
3526 remoterev = peer.lookup(rev)
3531 remoterev = peer.lookup(rev)
3527 if default or id:
3532 if default or id:
3528 output = [hexfunc(remoterev)]
3533 output = [hexfunc(remoterev)]
3529
3534
3530 def getbms():
3535 def getbms():
3531 bms = []
3536 bms = []
3532
3537
3533 if 'bookmarks' in peer.listkeys('namespaces'):
3538 if 'bookmarks' in peer.listkeys('namespaces'):
3534 hexremoterev = hex(remoterev)
3539 hexremoterev = hex(remoterev)
3535 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3540 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3536 if bmr == hexremoterev]
3541 if bmr == hexremoterev]
3537
3542
3538 return bms
3543 return bms
3539
3544
3540 if bookmarks:
3545 if bookmarks:
3541 output.extend(getbms())
3546 output.extend(getbms())
3542 elif default and not ui.quiet:
3547 elif default and not ui.quiet:
3543 # multiple bookmarks for a single parent separated by '/'
3548 # multiple bookmarks for a single parent separated by '/'
3544 bm = '/'.join(getbms())
3549 bm = '/'.join(getbms())
3545 if bm:
3550 if bm:
3546 output.append(bm)
3551 output.append(bm)
3547 else:
3552 else:
3548 if not rev:
3553 if not rev:
3549 ctx = repo[None]
3554 ctx = repo[None]
3550 parents = ctx.parents()
3555 parents = ctx.parents()
3551 changed = ""
3556 changed = ""
3552 if default or id or num:
3557 if default or id or num:
3553 if (util.any(repo.status())
3558 if (util.any(repo.status())
3554 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3559 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3555 changed = '+'
3560 changed = '+'
3556 if default or id:
3561 if default or id:
3557 output = ["%s%s" %
3562 output = ["%s%s" %
3558 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3563 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
3559 if num:
3564 if num:
3560 output.append("%s%s" %
3565 output.append("%s%s" %
3561 ('+'.join([str(p.rev()) for p in parents]), changed))
3566 ('+'.join([str(p.rev()) for p in parents]), changed))
3562 else:
3567 else:
3563 ctx = scmutil.revsingle(repo, rev)
3568 ctx = scmutil.revsingle(repo, rev)
3564 if default or id:
3569 if default or id:
3565 output = [hexfunc(ctx.node())]
3570 output = [hexfunc(ctx.node())]
3566 if num:
3571 if num:
3567 output.append(str(ctx.rev()))
3572 output.append(str(ctx.rev()))
3568
3573
3569 if default and not ui.quiet:
3574 if default and not ui.quiet:
3570 b = ctx.branch()
3575 b = ctx.branch()
3571 if b != 'default':
3576 if b != 'default':
3572 output.append("(%s)" % b)
3577 output.append("(%s)" % b)
3573
3578
3574 # multiple tags for a single parent separated by '/'
3579 # multiple tags for a single parent separated by '/'
3575 t = '/'.join(ctx.tags())
3580 t = '/'.join(ctx.tags())
3576 if t:
3581 if t:
3577 output.append(t)
3582 output.append(t)
3578
3583
3579 # multiple bookmarks for a single parent separated by '/'
3584 # multiple bookmarks for a single parent separated by '/'
3580 bm = '/'.join(ctx.bookmarks())
3585 bm = '/'.join(ctx.bookmarks())
3581 if bm:
3586 if bm:
3582 output.append(bm)
3587 output.append(bm)
3583 else:
3588 else:
3584 if branch:
3589 if branch:
3585 output.append(ctx.branch())
3590 output.append(ctx.branch())
3586
3591
3587 if tags:
3592 if tags:
3588 output.extend(ctx.tags())
3593 output.extend(ctx.tags())
3589
3594
3590 if bookmarks:
3595 if bookmarks:
3591 output.extend(ctx.bookmarks())
3596 output.extend(ctx.bookmarks())
3592
3597
3593 ui.write("%s\n" % ' '.join(output))
3598 ui.write("%s\n" % ' '.join(output))
3594
3599
3595 @command('import|patch',
3600 @command('import|patch',
3596 [('p', 'strip', 1,
3601 [('p', 'strip', 1,
3597 _('directory strip option for patch. This has the same '
3602 _('directory strip option for patch. This has the same '
3598 'meaning as the corresponding patch option'), _('NUM')),
3603 'meaning as the corresponding patch option'), _('NUM')),
3599 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3604 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
3600 ('e', 'edit', False, _('invoke editor on commit messages')),
3605 ('e', 'edit', False, _('invoke editor on commit messages')),
3601 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3606 ('f', 'force', None, _('skip check for outstanding uncommitted changes')),
3602 ('', 'no-commit', None,
3607 ('', 'no-commit', None,
3603 _("don't commit, just update the working directory")),
3608 _("don't commit, just update the working directory")),
3604 ('', 'bypass', None,
3609 ('', 'bypass', None,
3605 _("apply patch without touching the working directory")),
3610 _("apply patch without touching the working directory")),
3606 ('', 'exact', None,
3611 ('', 'exact', None,
3607 _('apply patch to the nodes from which it was generated')),
3612 _('apply patch to the nodes from which it was generated')),
3608 ('', 'import-branch', None,
3613 ('', 'import-branch', None,
3609 _('use any branch information in patch (implied by --exact)'))] +
3614 _('use any branch information in patch (implied by --exact)'))] +
3610 commitopts + commitopts2 + similarityopts,
3615 commitopts + commitopts2 + similarityopts,
3611 _('[OPTION]... PATCH...'))
3616 _('[OPTION]... PATCH...'))
3612 def import_(ui, repo, patch1=None, *patches, **opts):
3617 def import_(ui, repo, patch1=None, *patches, **opts):
3613 """import an ordered set of patches
3618 """import an ordered set of patches
3614
3619
3615 Import a list of patches and commit them individually (unless
3620 Import a list of patches and commit them individually (unless
3616 --no-commit is specified).
3621 --no-commit is specified).
3617
3622
3618 If there are outstanding changes in the working directory, import
3623 If there are outstanding changes in the working directory, import
3619 will abort unless given the -f/--force flag.
3624 will abort unless given the -f/--force flag.
3620
3625
3621 You can import a patch straight from a mail message. Even patches
3626 You can import a patch straight from a mail message. Even patches
3622 as attachments work (to use the body part, it must have type
3627 as attachments work (to use the body part, it must have type
3623 text/plain or text/x-patch). From and Subject headers of email
3628 text/plain or text/x-patch). From and Subject headers of email
3624 message are used as default committer and commit message. All
3629 message are used as default committer and commit message. All
3625 text/plain body parts before first diff are added to commit
3630 text/plain body parts before first diff are added to commit
3626 message.
3631 message.
3627
3632
3628 If the imported patch was generated by :hg:`export`, user and
3633 If the imported patch was generated by :hg:`export`, user and
3629 description from patch override values from message headers and
3634 description from patch override values from message headers and
3630 body. Values given on command line with -m/--message and -u/--user
3635 body. Values given on command line with -m/--message and -u/--user
3631 override these.
3636 override these.
3632
3637
3633 If --exact is specified, import will set the working directory to
3638 If --exact is specified, import will set the working directory to
3634 the parent of each patch before applying it, and will abort if the
3639 the parent of each patch before applying it, and will abort if the
3635 resulting changeset has a different ID than the one recorded in
3640 resulting changeset has a different ID than the one recorded in
3636 the patch. This may happen due to character set problems or other
3641 the patch. This may happen due to character set problems or other
3637 deficiencies in the text patch format.
3642 deficiencies in the text patch format.
3638
3643
3639 Use --bypass to apply and commit patches directly to the
3644 Use --bypass to apply and commit patches directly to the
3640 repository, not touching the working directory. Without --exact,
3645 repository, not touching the working directory. Without --exact,
3641 patches will be applied on top of the working directory parent
3646 patches will be applied on top of the working directory parent
3642 revision.
3647 revision.
3643
3648
3644 With -s/--similarity, hg will attempt to discover renames and
3649 With -s/--similarity, hg will attempt to discover renames and
3645 copies in the patch in the same way as :hg:`addremove`.
3650 copies in the patch in the same way as :hg:`addremove`.
3646
3651
3647 To read a patch from standard input, use "-" as the patch name. If
3652 To read a patch from standard input, use "-" as the patch name. If
3648 a URL is specified, the patch will be downloaded from it.
3653 a URL is specified, the patch will be downloaded from it.
3649 See :hg:`help dates` for a list of formats valid for -d/--date.
3654 See :hg:`help dates` for a list of formats valid for -d/--date.
3650
3655
3651 .. container:: verbose
3656 .. container:: verbose
3652
3657
3653 Examples:
3658 Examples:
3654
3659
3655 - import a traditional patch from a website and detect renames::
3660 - import a traditional patch from a website and detect renames::
3656
3661
3657 hg import -s 80 http://example.com/bugfix.patch
3662 hg import -s 80 http://example.com/bugfix.patch
3658
3663
3659 - import a changeset from an hgweb server::
3664 - import a changeset from an hgweb server::
3660
3665
3661 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3666 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
3662
3667
3663 - import all the patches in an Unix-style mbox::
3668 - import all the patches in an Unix-style mbox::
3664
3669
3665 hg import incoming-patches.mbox
3670 hg import incoming-patches.mbox
3666
3671
3667 - attempt to exactly restore an exported changeset (not always
3672 - attempt to exactly restore an exported changeset (not always
3668 possible)::
3673 possible)::
3669
3674
3670 hg import --exact proposed-fix.patch
3675 hg import --exact proposed-fix.patch
3671
3676
3672 Returns 0 on success.
3677 Returns 0 on success.
3673 """
3678 """
3674
3679
3675 if not patch1:
3680 if not patch1:
3676 raise util.Abort(_('need at least one patch to import'))
3681 raise util.Abort(_('need at least one patch to import'))
3677
3682
3678 patches = (patch1,) + patches
3683 patches = (patch1,) + patches
3679
3684
3680 date = opts.get('date')
3685 date = opts.get('date')
3681 if date:
3686 if date:
3682 opts['date'] = util.parsedate(date)
3687 opts['date'] = util.parsedate(date)
3683
3688
3684 editor = cmdutil.commiteditor
3689 editor = cmdutil.commiteditor
3685 if opts.get('edit'):
3690 if opts.get('edit'):
3686 editor = cmdutil.commitforceeditor
3691 editor = cmdutil.commitforceeditor
3687
3692
3688 update = not opts.get('bypass')
3693 update = not opts.get('bypass')
3689 if not update and opts.get('no_commit'):
3694 if not update and opts.get('no_commit'):
3690 raise util.Abort(_('cannot use --no-commit with --bypass'))
3695 raise util.Abort(_('cannot use --no-commit with --bypass'))
3691 try:
3696 try:
3692 sim = float(opts.get('similarity') or 0)
3697 sim = float(opts.get('similarity') or 0)
3693 except ValueError:
3698 except ValueError:
3694 raise util.Abort(_('similarity must be a number'))
3699 raise util.Abort(_('similarity must be a number'))
3695 if sim < 0 or sim > 100:
3700 if sim < 0 or sim > 100:
3696 raise util.Abort(_('similarity must be between 0 and 100'))
3701 raise util.Abort(_('similarity must be between 0 and 100'))
3697 if sim and not update:
3702 if sim and not update:
3698 raise util.Abort(_('cannot use --similarity with --bypass'))
3703 raise util.Abort(_('cannot use --similarity with --bypass'))
3699
3704
3700 if (opts.get('exact') or not opts.get('force')) and update:
3705 if (opts.get('exact') or not opts.get('force')) and update:
3701 cmdutil.bailifchanged(repo)
3706 cmdutil.bailifchanged(repo)
3702
3707
3703 base = opts["base"]
3708 base = opts["base"]
3704 strip = opts["strip"]
3709 strip = opts["strip"]
3705 wlock = lock = tr = None
3710 wlock = lock = tr = None
3706 msgs = []
3711 msgs = []
3707
3712
3708 def checkexact(repo, n, nodeid):
3713 def checkexact(repo, n, nodeid):
3709 if opts.get('exact') and hex(n) != nodeid:
3714 if opts.get('exact') and hex(n) != nodeid:
3710 repo.rollback()
3715 repo.rollback()
3711 raise util.Abort(_('patch is damaged or loses information'))
3716 raise util.Abort(_('patch is damaged or loses information'))
3712
3717
3713 def tryone(ui, hunk, parents):
3718 def tryone(ui, hunk, parents):
3714 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3719 tmpname, message, user, date, branch, nodeid, p1, p2 = \
3715 patch.extract(ui, hunk)
3720 patch.extract(ui, hunk)
3716
3721
3717 if not tmpname:
3722 if not tmpname:
3718 return (None, None)
3723 return (None, None)
3719 msg = _('applied to working directory')
3724 msg = _('applied to working directory')
3720
3725
3721 try:
3726 try:
3722 cmdline_message = cmdutil.logmessage(ui, opts)
3727 cmdline_message = cmdutil.logmessage(ui, opts)
3723 if cmdline_message:
3728 if cmdline_message:
3724 # pickup the cmdline msg
3729 # pickup the cmdline msg
3725 message = cmdline_message
3730 message = cmdline_message
3726 elif message:
3731 elif message:
3727 # pickup the patch msg
3732 # pickup the patch msg
3728 message = message.strip()
3733 message = message.strip()
3729 else:
3734 else:
3730 # launch the editor
3735 # launch the editor
3731 message = None
3736 message = None
3732 ui.debug('message:\n%s\n' % message)
3737 ui.debug('message:\n%s\n' % message)
3733
3738
3734 if len(parents) == 1:
3739 if len(parents) == 1:
3735 parents.append(repo[nullid])
3740 parents.append(repo[nullid])
3736 if opts.get('exact'):
3741 if opts.get('exact'):
3737 if not nodeid or not p1:
3742 if not nodeid or not p1:
3738 raise util.Abort(_('not a Mercurial patch'))
3743 raise util.Abort(_('not a Mercurial patch'))
3739 p1 = repo[p1]
3744 p1 = repo[p1]
3740 p2 = repo[p2 or nullid]
3745 p2 = repo[p2 or nullid]
3741 elif p2:
3746 elif p2:
3742 try:
3747 try:
3743 p1 = repo[p1]
3748 p1 = repo[p1]
3744 p2 = repo[p2]
3749 p2 = repo[p2]
3745 # Without any options, consider p2 only if the
3750 # Without any options, consider p2 only if the
3746 # patch is being applied on top of the recorded
3751 # patch is being applied on top of the recorded
3747 # first parent.
3752 # first parent.
3748 if p1 != parents[0]:
3753 if p1 != parents[0]:
3749 p1 = parents[0]
3754 p1 = parents[0]
3750 p2 = repo[nullid]
3755 p2 = repo[nullid]
3751 except error.RepoError:
3756 except error.RepoError:
3752 p1, p2 = parents
3757 p1, p2 = parents
3753 else:
3758 else:
3754 p1, p2 = parents
3759 p1, p2 = parents
3755
3760
3756 n = None
3761 n = None
3757 if update:
3762 if update:
3758 if p1 != parents[0]:
3763 if p1 != parents[0]:
3759 hg.clean(repo, p1.node())
3764 hg.clean(repo, p1.node())
3760 if p2 != parents[1]:
3765 if p2 != parents[1]:
3761 repo.setparents(p1.node(), p2.node())
3766 repo.setparents(p1.node(), p2.node())
3762
3767
3763 if opts.get('exact') or opts.get('import_branch'):
3768 if opts.get('exact') or opts.get('import_branch'):
3764 repo.dirstate.setbranch(branch or 'default')
3769 repo.dirstate.setbranch(branch or 'default')
3765
3770
3766 files = set()
3771 files = set()
3767 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3772 patch.patch(ui, repo, tmpname, strip=strip, files=files,
3768 eolmode=None, similarity=sim / 100.0)
3773 eolmode=None, similarity=sim / 100.0)
3769 files = list(files)
3774 files = list(files)
3770 if opts.get('no_commit'):
3775 if opts.get('no_commit'):
3771 if message:
3776 if message:
3772 msgs.append(message)
3777 msgs.append(message)
3773 else:
3778 else:
3774 if opts.get('exact') or p2:
3779 if opts.get('exact') or p2:
3775 # If you got here, you either use --force and know what
3780 # If you got here, you either use --force and know what
3776 # you are doing or used --exact or a merge patch while
3781 # you are doing or used --exact or a merge patch while
3777 # being updated to its first parent.
3782 # being updated to its first parent.
3778 m = None
3783 m = None
3779 else:
3784 else:
3780 m = scmutil.matchfiles(repo, files or [])
3785 m = scmutil.matchfiles(repo, files or [])
3781 n = repo.commit(message, opts.get('user') or user,
3786 n = repo.commit(message, opts.get('user') or user,
3782 opts.get('date') or date, match=m,
3787 opts.get('date') or date, match=m,
3783 editor=editor)
3788 editor=editor)
3784 checkexact(repo, n, nodeid)
3789 checkexact(repo, n, nodeid)
3785 else:
3790 else:
3786 if opts.get('exact') or opts.get('import_branch'):
3791 if opts.get('exact') or opts.get('import_branch'):
3787 branch = branch or 'default'
3792 branch = branch or 'default'
3788 else:
3793 else:
3789 branch = p1.branch()
3794 branch = p1.branch()
3790 store = patch.filestore()
3795 store = patch.filestore()
3791 try:
3796 try:
3792 files = set()
3797 files = set()
3793 try:
3798 try:
3794 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3799 patch.patchrepo(ui, repo, p1, store, tmpname, strip,
3795 files, eolmode=None)
3800 files, eolmode=None)
3796 except patch.PatchError, e:
3801 except patch.PatchError, e:
3797 raise util.Abort(str(e))
3802 raise util.Abort(str(e))
3798 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3803 memctx = patch.makememctx(repo, (p1.node(), p2.node()),
3799 message,
3804 message,
3800 opts.get('user') or user,
3805 opts.get('user') or user,
3801 opts.get('date') or date,
3806 opts.get('date') or date,
3802 branch, files, store,
3807 branch, files, store,
3803 editor=cmdutil.commiteditor)
3808 editor=cmdutil.commiteditor)
3804 repo.savecommitmessage(memctx.description())
3809 repo.savecommitmessage(memctx.description())
3805 n = memctx.commit()
3810 n = memctx.commit()
3806 checkexact(repo, n, nodeid)
3811 checkexact(repo, n, nodeid)
3807 finally:
3812 finally:
3808 store.close()
3813 store.close()
3809 if n:
3814 if n:
3810 # i18n: refers to a short changeset id
3815 # i18n: refers to a short changeset id
3811 msg = _('created %s') % short(n)
3816 msg = _('created %s') % short(n)
3812 return (msg, n)
3817 return (msg, n)
3813 finally:
3818 finally:
3814 os.unlink(tmpname)
3819 os.unlink(tmpname)
3815
3820
3816 try:
3821 try:
3817 try:
3822 try:
3818 wlock = repo.wlock()
3823 wlock = repo.wlock()
3819 if not opts.get('no_commit'):
3824 if not opts.get('no_commit'):
3820 lock = repo.lock()
3825 lock = repo.lock()
3821 tr = repo.transaction('import')
3826 tr = repo.transaction('import')
3822 parents = repo.parents()
3827 parents = repo.parents()
3823 for patchurl in patches:
3828 for patchurl in patches:
3824 if patchurl == '-':
3829 if patchurl == '-':
3825 ui.status(_('applying patch from stdin\n'))
3830 ui.status(_('applying patch from stdin\n'))
3826 patchfile = ui.fin
3831 patchfile = ui.fin
3827 patchurl = 'stdin' # for error message
3832 patchurl = 'stdin' # for error message
3828 else:
3833 else:
3829 patchurl = os.path.join(base, patchurl)
3834 patchurl = os.path.join(base, patchurl)
3830 ui.status(_('applying %s\n') % patchurl)
3835 ui.status(_('applying %s\n') % patchurl)
3831 patchfile = url.open(ui, patchurl)
3836 patchfile = url.open(ui, patchurl)
3832
3837
3833 haspatch = False
3838 haspatch = False
3834 for hunk in patch.split(patchfile):
3839 for hunk in patch.split(patchfile):
3835 (msg, node) = tryone(ui, hunk, parents)
3840 (msg, node) = tryone(ui, hunk, parents)
3836 if msg:
3841 if msg:
3837 haspatch = True
3842 haspatch = True
3838 ui.note(msg + '\n')
3843 ui.note(msg + '\n')
3839 if update or opts.get('exact'):
3844 if update or opts.get('exact'):
3840 parents = repo.parents()
3845 parents = repo.parents()
3841 else:
3846 else:
3842 parents = [repo[node]]
3847 parents = [repo[node]]
3843
3848
3844 if not haspatch:
3849 if not haspatch:
3845 raise util.Abort(_('%s: no diffs found') % patchurl)
3850 raise util.Abort(_('%s: no diffs found') % patchurl)
3846
3851
3847 if tr:
3852 if tr:
3848 tr.close()
3853 tr.close()
3849 if msgs:
3854 if msgs:
3850 repo.savecommitmessage('\n* * *\n'.join(msgs))
3855 repo.savecommitmessage('\n* * *\n'.join(msgs))
3851 except: # re-raises
3856 except: # re-raises
3852 # wlock.release() indirectly calls dirstate.write(): since
3857 # wlock.release() indirectly calls dirstate.write(): since
3853 # we're crashing, we do not want to change the working dir
3858 # we're crashing, we do not want to change the working dir
3854 # parent after all, so make sure it writes nothing
3859 # parent after all, so make sure it writes nothing
3855 repo.dirstate.invalidate()
3860 repo.dirstate.invalidate()
3856 raise
3861 raise
3857 finally:
3862 finally:
3858 if tr:
3863 if tr:
3859 tr.release()
3864 tr.release()
3860 release(lock, wlock)
3865 release(lock, wlock)
3861
3866
3862 @command('incoming|in',
3867 @command('incoming|in',
3863 [('f', 'force', None,
3868 [('f', 'force', None,
3864 _('run even if remote repository is unrelated')),
3869 _('run even if remote repository is unrelated')),
3865 ('n', 'newest-first', None, _('show newest record first')),
3870 ('n', 'newest-first', None, _('show newest record first')),
3866 ('', 'bundle', '',
3871 ('', 'bundle', '',
3867 _('file to store the bundles into'), _('FILE')),
3872 _('file to store the bundles into'), _('FILE')),
3868 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3873 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
3869 ('B', 'bookmarks', False, _("compare bookmarks")),
3874 ('B', 'bookmarks', False, _("compare bookmarks")),
3870 ('b', 'branch', [],
3875 ('b', 'branch', [],
3871 _('a specific branch you would like to pull'), _('BRANCH')),
3876 _('a specific branch you would like to pull'), _('BRANCH')),
3872 ] + logopts + remoteopts + subrepoopts,
3877 ] + logopts + remoteopts + subrepoopts,
3873 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3878 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
3874 def incoming(ui, repo, source="default", **opts):
3879 def incoming(ui, repo, source="default", **opts):
3875 """show new changesets found in source
3880 """show new changesets found in source
3876
3881
3877 Show new changesets found in the specified path/URL or the default
3882 Show new changesets found in the specified path/URL or the default
3878 pull location. These are the changesets that would have been pulled
3883 pull location. These are the changesets that would have been pulled
3879 if a pull at the time you issued this command.
3884 if a pull at the time you issued this command.
3880
3885
3881 For remote repository, using --bundle avoids downloading the
3886 For remote repository, using --bundle avoids downloading the
3882 changesets twice if the incoming is followed by a pull.
3887 changesets twice if the incoming is followed by a pull.
3883
3888
3884 See pull for valid source format details.
3889 See pull for valid source format details.
3885
3890
3886 Returns 0 if there are incoming changes, 1 otherwise.
3891 Returns 0 if there are incoming changes, 1 otherwise.
3887 """
3892 """
3888 if opts.get('graph'):
3893 if opts.get('graph'):
3889 cmdutil.checkunsupportedgraphflags([], opts)
3894 cmdutil.checkunsupportedgraphflags([], opts)
3890 def display(other, chlist, displayer):
3895 def display(other, chlist, displayer):
3891 revdag = cmdutil.graphrevs(other, chlist, opts)
3896 revdag = cmdutil.graphrevs(other, chlist, opts)
3892 showparents = [ctx.node() for ctx in repo[None].parents()]
3897 showparents = [ctx.node() for ctx in repo[None].parents()]
3893 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3898 cmdutil.displaygraph(ui, revdag, displayer, showparents,
3894 graphmod.asciiedges)
3899 graphmod.asciiedges)
3895
3900
3896 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3901 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
3897 return 0
3902 return 0
3898
3903
3899 if opts.get('bundle') and opts.get('subrepos'):
3904 if opts.get('bundle') and opts.get('subrepos'):
3900 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3905 raise util.Abort(_('cannot combine --bundle and --subrepos'))
3901
3906
3902 if opts.get('bookmarks'):
3907 if opts.get('bookmarks'):
3903 source, branches = hg.parseurl(ui.expandpath(source),
3908 source, branches = hg.parseurl(ui.expandpath(source),
3904 opts.get('branch'))
3909 opts.get('branch'))
3905 other = hg.peer(repo, opts, source)
3910 other = hg.peer(repo, opts, source)
3906 if 'bookmarks' not in other.listkeys('namespaces'):
3911 if 'bookmarks' not in other.listkeys('namespaces'):
3907 ui.warn(_("remote doesn't support bookmarks\n"))
3912 ui.warn(_("remote doesn't support bookmarks\n"))
3908 return 0
3913 return 0
3909 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3914 ui.status(_('comparing with %s\n') % util.hidepassword(source))
3910 return bookmarks.diff(ui, repo, other)
3915 return bookmarks.diff(ui, repo, other)
3911
3916
3912 repo._subtoppath = ui.expandpath(source)
3917 repo._subtoppath = ui.expandpath(source)
3913 try:
3918 try:
3914 return hg.incoming(ui, repo, source, opts)
3919 return hg.incoming(ui, repo, source, opts)
3915 finally:
3920 finally:
3916 del repo._subtoppath
3921 del repo._subtoppath
3917
3922
3918
3923
3919 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3924 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'))
3920 def init(ui, dest=".", **opts):
3925 def init(ui, dest=".", **opts):
3921 """create a new repository in the given directory
3926 """create a new repository in the given directory
3922
3927
3923 Initialize a new repository in the given directory. If the given
3928 Initialize a new repository in the given directory. If the given
3924 directory does not exist, it will be created.
3929 directory does not exist, it will be created.
3925
3930
3926 If no directory is given, the current directory is used.
3931 If no directory is given, the current directory is used.
3927
3932
3928 It is possible to specify an ``ssh://`` URL as the destination.
3933 It is possible to specify an ``ssh://`` URL as the destination.
3929 See :hg:`help urls` for more information.
3934 See :hg:`help urls` for more information.
3930
3935
3931 Returns 0 on success.
3936 Returns 0 on success.
3932 """
3937 """
3933 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3938 hg.peer(ui, opts, ui.expandpath(dest), create=True)
3934
3939
3935 @command('locate',
3940 @command('locate',
3936 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3941 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3937 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3942 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3938 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3943 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
3939 ] + walkopts,
3944 ] + walkopts,
3940 _('[OPTION]... [PATTERN]...'))
3945 _('[OPTION]... [PATTERN]...'))
3941 def locate(ui, repo, *pats, **opts):
3946 def locate(ui, repo, *pats, **opts):
3942 """locate files matching specific patterns
3947 """locate files matching specific patterns
3943
3948
3944 Print files under Mercurial control in the working directory whose
3949 Print files under Mercurial control in the working directory whose
3945 names match the given patterns.
3950 names match the given patterns.
3946
3951
3947 By default, this command searches all directories in the working
3952 By default, this command searches all directories in the working
3948 directory. To search just the current directory and its
3953 directory. To search just the current directory and its
3949 subdirectories, use "--include .".
3954 subdirectories, use "--include .".
3950
3955
3951 If no patterns are given to match, this command prints the names
3956 If no patterns are given to match, this command prints the names
3952 of all files under Mercurial control in the working directory.
3957 of all files under Mercurial control in the working directory.
3953
3958
3954 If you want to feed the output of this command into the "xargs"
3959 If you want to feed the output of this command into the "xargs"
3955 command, use the -0 option to both this command and "xargs". This
3960 command, use the -0 option to both this command and "xargs". This
3956 will avoid the problem of "xargs" treating single filenames that
3961 will avoid the problem of "xargs" treating single filenames that
3957 contain whitespace as multiple filenames.
3962 contain whitespace as multiple filenames.
3958
3963
3959 Returns 0 if a match is found, 1 otherwise.
3964 Returns 0 if a match is found, 1 otherwise.
3960 """
3965 """
3961 end = opts.get('print0') and '\0' or '\n'
3966 end = opts.get('print0') and '\0' or '\n'
3962 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3967 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
3963
3968
3964 ret = 1
3969 ret = 1
3965 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3970 m = scmutil.match(repo[rev], pats, opts, default='relglob')
3966 m.bad = lambda x, y: False
3971 m.bad = lambda x, y: False
3967 for abs in repo[rev].walk(m):
3972 for abs in repo[rev].walk(m):
3968 if not rev and abs not in repo.dirstate:
3973 if not rev and abs not in repo.dirstate:
3969 continue
3974 continue
3970 if opts.get('fullpath'):
3975 if opts.get('fullpath'):
3971 ui.write(repo.wjoin(abs), end)
3976 ui.write(repo.wjoin(abs), end)
3972 else:
3977 else:
3973 ui.write(((pats and m.rel(abs)) or abs), end)
3978 ui.write(((pats and m.rel(abs)) or abs), end)
3974 ret = 0
3979 ret = 0
3975
3980
3976 return ret
3981 return ret
3977
3982
3978 @command('^log|history',
3983 @command('^log|history',
3979 [('f', 'follow', None,
3984 [('f', 'follow', None,
3980 _('follow changeset history, or file history across copies and renames')),
3985 _('follow changeset history, or file history across copies and renames')),
3981 ('', 'follow-first', None,
3986 ('', 'follow-first', None,
3982 _('only follow the first parent of merge changesets (DEPRECATED)')),
3987 _('only follow the first parent of merge changesets (DEPRECATED)')),
3983 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3988 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
3984 ('C', 'copies', None, _('show copied files')),
3989 ('C', 'copies', None, _('show copied files')),
3985 ('k', 'keyword', [],
3990 ('k', 'keyword', [],
3986 _('do case-insensitive search for a given text'), _('TEXT')),
3991 _('do case-insensitive search for a given text'), _('TEXT')),
3987 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3992 ('r', 'rev', [], _('show the specified revision or range'), _('REV')),
3988 ('', 'removed', None, _('include revisions where files were removed')),
3993 ('', 'removed', None, _('include revisions where files were removed')),
3989 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3994 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
3990 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3995 ('u', 'user', [], _('revisions committed by user'), _('USER')),
3991 ('', 'only-branch', [],
3996 ('', 'only-branch', [],
3992 _('show only changesets within the given named branch (DEPRECATED)'),
3997 _('show only changesets within the given named branch (DEPRECATED)'),
3993 _('BRANCH')),
3998 _('BRANCH')),
3994 ('b', 'branch', [],
3999 ('b', 'branch', [],
3995 _('show changesets within the given named branch'), _('BRANCH')),
4000 _('show changesets within the given named branch'), _('BRANCH')),
3996 ('P', 'prune', [],
4001 ('P', 'prune', [],
3997 _('do not display revision or any of its ancestors'), _('REV')),
4002 _('do not display revision or any of its ancestors'), _('REV')),
3998 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
4003 ('', 'hidden', False, _('show hidden changesets (DEPRECATED)')),
3999 ] + logopts + walkopts,
4004 ] + logopts + walkopts,
4000 _('[OPTION]... [FILE]'))
4005 _('[OPTION]... [FILE]'))
4001 def log(ui, repo, *pats, **opts):
4006 def log(ui, repo, *pats, **opts):
4002 """show revision history of entire repository or files
4007 """show revision history of entire repository or files
4003
4008
4004 Print the revision history of the specified files or the entire
4009 Print the revision history of the specified files or the entire
4005 project.
4010 project.
4006
4011
4007 If no revision range is specified, the default is ``tip:0`` unless
4012 If no revision range is specified, the default is ``tip:0`` unless
4008 --follow is set, in which case the working directory parent is
4013 --follow is set, in which case the working directory parent is
4009 used as the starting revision.
4014 used as the starting revision.
4010
4015
4011 File history is shown without following rename or copy history of
4016 File history is shown without following rename or copy history of
4012 files. Use -f/--follow with a filename to follow history across
4017 files. Use -f/--follow with a filename to follow history across
4013 renames and copies. --follow without a filename will only show
4018 renames and copies. --follow without a filename will only show
4014 ancestors or descendants of the starting revision.
4019 ancestors or descendants of the starting revision.
4015
4020
4016 By default this command prints revision number and changeset id,
4021 By default this command prints revision number and changeset id,
4017 tags, non-trivial parents, user, date and time, and a summary for
4022 tags, non-trivial parents, user, date and time, and a summary for
4018 each commit. When the -v/--verbose switch is used, the list of
4023 each commit. When the -v/--verbose switch is used, the list of
4019 changed files and full commit message are shown.
4024 changed files and full commit message are shown.
4020
4025
4021 .. note::
4026 .. note::
4022 log -p/--patch may generate unexpected diff output for merge
4027 log -p/--patch may generate unexpected diff output for merge
4023 changesets, as it will only compare the merge changeset against
4028 changesets, as it will only compare the merge changeset against
4024 its first parent. Also, only files different from BOTH parents
4029 its first parent. Also, only files different from BOTH parents
4025 will appear in files:.
4030 will appear in files:.
4026
4031
4027 .. note::
4032 .. note::
4028 for performance reasons, log FILE may omit duplicate changes
4033 for performance reasons, log FILE may omit duplicate changes
4029 made on branches and will not show deletions. To see all
4034 made on branches and will not show deletions. To see all
4030 changes including duplicates and deletions, use the --removed
4035 changes including duplicates and deletions, use the --removed
4031 switch.
4036 switch.
4032
4037
4033 .. container:: verbose
4038 .. container:: verbose
4034
4039
4035 Some examples:
4040 Some examples:
4036
4041
4037 - changesets with full descriptions and file lists::
4042 - changesets with full descriptions and file lists::
4038
4043
4039 hg log -v
4044 hg log -v
4040
4045
4041 - changesets ancestral to the working directory::
4046 - changesets ancestral to the working directory::
4042
4047
4043 hg log -f
4048 hg log -f
4044
4049
4045 - last 10 commits on the current branch::
4050 - last 10 commits on the current branch::
4046
4051
4047 hg log -l 10 -b .
4052 hg log -l 10 -b .
4048
4053
4049 - changesets showing all modifications of a file, including removals::
4054 - changesets showing all modifications of a file, including removals::
4050
4055
4051 hg log --removed file.c
4056 hg log --removed file.c
4052
4057
4053 - all changesets that touch a directory, with diffs, excluding merges::
4058 - all changesets that touch a directory, with diffs, excluding merges::
4054
4059
4055 hg log -Mp lib/
4060 hg log -Mp lib/
4056
4061
4057 - all revision numbers that match a keyword::
4062 - all revision numbers that match a keyword::
4058
4063
4059 hg log -k bug --template "{rev}\\n"
4064 hg log -k bug --template "{rev}\\n"
4060
4065
4061 - check if a given changeset is included is a tagged release::
4066 - check if a given changeset is included is a tagged release::
4062
4067
4063 hg log -r "a21ccf and ancestor(1.9)"
4068 hg log -r "a21ccf and ancestor(1.9)"
4064
4069
4065 - find all changesets by some user in a date range::
4070 - find all changesets by some user in a date range::
4066
4071
4067 hg log -k alice -d "may 2008 to jul 2008"
4072 hg log -k alice -d "may 2008 to jul 2008"
4068
4073
4069 - summary of all changesets after the last tag::
4074 - summary of all changesets after the last tag::
4070
4075
4071 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4076 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4072
4077
4073 See :hg:`help dates` for a list of formats valid for -d/--date.
4078 See :hg:`help dates` for a list of formats valid for -d/--date.
4074
4079
4075 See :hg:`help revisions` and :hg:`help revsets` for more about
4080 See :hg:`help revisions` and :hg:`help revsets` for more about
4076 specifying revisions.
4081 specifying revisions.
4077
4082
4078 See :hg:`help templates` for more about pre-packaged styles and
4083 See :hg:`help templates` for more about pre-packaged styles and
4079 specifying custom templates.
4084 specifying custom templates.
4080
4085
4081 Returns 0 on success.
4086 Returns 0 on success.
4082 """
4087 """
4083 if opts.get('graph'):
4088 if opts.get('graph'):
4084 return cmdutil.graphlog(ui, repo, *pats, **opts)
4089 return cmdutil.graphlog(ui, repo, *pats, **opts)
4085
4090
4086 matchfn = scmutil.match(repo[None], pats, opts)
4091 matchfn = scmutil.match(repo[None], pats, opts)
4087 limit = cmdutil.loglimit(opts)
4092 limit = cmdutil.loglimit(opts)
4088 count = 0
4093 count = 0
4089
4094
4090 getrenamed, endrev = None, None
4095 getrenamed, endrev = None, None
4091 if opts.get('copies'):
4096 if opts.get('copies'):
4092 if opts.get('rev'):
4097 if opts.get('rev'):
4093 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4098 endrev = max(scmutil.revrange(repo, opts.get('rev'))) + 1
4094 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4099 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4095
4100
4096 df = False
4101 df = False
4097 if opts.get("date"):
4102 if opts.get("date"):
4098 df = util.matchdate(opts["date"])
4103 df = util.matchdate(opts["date"])
4099
4104
4100 branches = opts.get('branch', []) + opts.get('only_branch', [])
4105 branches = opts.get('branch', []) + opts.get('only_branch', [])
4101 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4106 opts['branch'] = [repo.lookupbranch(b) for b in branches]
4102
4107
4103 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4108 displayer = cmdutil.show_changeset(ui, repo, opts, True)
4104 def prep(ctx, fns):
4109 def prep(ctx, fns):
4105 rev = ctx.rev()
4110 rev = ctx.rev()
4106 parents = [p for p in repo.changelog.parentrevs(rev)
4111 parents = [p for p in repo.changelog.parentrevs(rev)
4107 if p != nullrev]
4112 if p != nullrev]
4108 if opts.get('no_merges') and len(parents) == 2:
4113 if opts.get('no_merges') and len(parents) == 2:
4109 return
4114 return
4110 if opts.get('only_merges') and len(parents) != 2:
4115 if opts.get('only_merges') and len(parents) != 2:
4111 return
4116 return
4112 if opts.get('branch') and ctx.branch() not in opts['branch']:
4117 if opts.get('branch') and ctx.branch() not in opts['branch']:
4113 return
4118 return
4114 if not opts.get('hidden') and ctx.hidden():
4119 if not opts.get('hidden') and ctx.hidden():
4115 return
4120 return
4116 if df and not df(ctx.date()[0]):
4121 if df and not df(ctx.date()[0]):
4117 return
4122 return
4118
4123
4119 lower = encoding.lower
4124 lower = encoding.lower
4120 if opts.get('user'):
4125 if opts.get('user'):
4121 luser = lower(ctx.user())
4126 luser = lower(ctx.user())
4122 for k in [lower(x) for x in opts['user']]:
4127 for k in [lower(x) for x in opts['user']]:
4123 if (k in luser):
4128 if (k in luser):
4124 break
4129 break
4125 else:
4130 else:
4126 return
4131 return
4127 if opts.get('keyword'):
4132 if opts.get('keyword'):
4128 luser = lower(ctx.user())
4133 luser = lower(ctx.user())
4129 ldesc = lower(ctx.description())
4134 ldesc = lower(ctx.description())
4130 lfiles = lower(" ".join(ctx.files()))
4135 lfiles = lower(" ".join(ctx.files()))
4131 for k in [lower(x) for x in opts['keyword']]:
4136 for k in [lower(x) for x in opts['keyword']]:
4132 if (k in luser or k in ldesc or k in lfiles):
4137 if (k in luser or k in ldesc or k in lfiles):
4133 break
4138 break
4134 else:
4139 else:
4135 return
4140 return
4136
4141
4137 copies = None
4142 copies = None
4138 if getrenamed is not None and rev:
4143 if getrenamed is not None and rev:
4139 copies = []
4144 copies = []
4140 for fn in ctx.files():
4145 for fn in ctx.files():
4141 rename = getrenamed(fn, rev)
4146 rename = getrenamed(fn, rev)
4142 if rename:
4147 if rename:
4143 copies.append((fn, rename[0]))
4148 copies.append((fn, rename[0]))
4144
4149
4145 revmatchfn = None
4150 revmatchfn = None
4146 if opts.get('patch') or opts.get('stat'):
4151 if opts.get('patch') or opts.get('stat'):
4147 if opts.get('follow') or opts.get('follow_first'):
4152 if opts.get('follow') or opts.get('follow_first'):
4148 # note: this might be wrong when following through merges
4153 # note: this might be wrong when following through merges
4149 revmatchfn = scmutil.match(repo[None], fns, default='path')
4154 revmatchfn = scmutil.match(repo[None], fns, default='path')
4150 else:
4155 else:
4151 revmatchfn = matchfn
4156 revmatchfn = matchfn
4152
4157
4153 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4158 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4154
4159
4155 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4160 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
4156 if count == limit:
4161 if count == limit:
4157 break
4162 break
4158 if displayer.flush(ctx.rev()):
4163 if displayer.flush(ctx.rev()):
4159 count += 1
4164 count += 1
4160 displayer.close()
4165 displayer.close()
4161
4166
4162 @command('manifest',
4167 @command('manifest',
4163 [('r', 'rev', '', _('revision to display'), _('REV')),
4168 [('r', 'rev', '', _('revision to display'), _('REV')),
4164 ('', 'all', False, _("list files from all revisions"))],
4169 ('', 'all', False, _("list files from all revisions"))],
4165 _('[-r REV]'))
4170 _('[-r REV]'))
4166 def manifest(ui, repo, node=None, rev=None, **opts):
4171 def manifest(ui, repo, node=None, rev=None, **opts):
4167 """output the current or given revision of the project manifest
4172 """output the current or given revision of the project manifest
4168
4173
4169 Print a list of version controlled files for the given revision.
4174 Print a list of version controlled files for the given revision.
4170 If no revision is given, the first parent of the working directory
4175 If no revision is given, the first parent of the working directory
4171 is used, or the null revision if no revision is checked out.
4176 is used, or the null revision if no revision is checked out.
4172
4177
4173 With -v, print file permissions, symlink and executable bits.
4178 With -v, print file permissions, symlink and executable bits.
4174 With --debug, print file revision hashes.
4179 With --debug, print file revision hashes.
4175
4180
4176 If option --all is specified, the list of all files from all revisions
4181 If option --all is specified, the list of all files from all revisions
4177 is printed. This includes deleted and renamed files.
4182 is printed. This includes deleted and renamed files.
4178
4183
4179 Returns 0 on success.
4184 Returns 0 on success.
4180 """
4185 """
4181 if opts.get('all'):
4186 if opts.get('all'):
4182 if rev or node:
4187 if rev or node:
4183 raise util.Abort(_("can't specify a revision with --all"))
4188 raise util.Abort(_("can't specify a revision with --all"))
4184
4189
4185 res = []
4190 res = []
4186 prefix = "data/"
4191 prefix = "data/"
4187 suffix = ".i"
4192 suffix = ".i"
4188 plen = len(prefix)
4193 plen = len(prefix)
4189 slen = len(suffix)
4194 slen = len(suffix)
4190 lock = repo.lock()
4195 lock = repo.lock()
4191 try:
4196 try:
4192 for fn, b, size in repo.store.datafiles():
4197 for fn, b, size in repo.store.datafiles():
4193 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4198 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4194 res.append(fn[plen:-slen])
4199 res.append(fn[plen:-slen])
4195 finally:
4200 finally:
4196 lock.release()
4201 lock.release()
4197 for f in res:
4202 for f in res:
4198 ui.write("%s\n" % f)
4203 ui.write("%s\n" % f)
4199 return
4204 return
4200
4205
4201 if rev and node:
4206 if rev and node:
4202 raise util.Abort(_("please specify just one revision"))
4207 raise util.Abort(_("please specify just one revision"))
4203
4208
4204 if not node:
4209 if not node:
4205 node = rev
4210 node = rev
4206
4211
4207 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
4212 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
4208 ctx = scmutil.revsingle(repo, node)
4213 ctx = scmutil.revsingle(repo, node)
4209 for f in ctx:
4214 for f in ctx:
4210 if ui.debugflag:
4215 if ui.debugflag:
4211 ui.write("%40s " % hex(ctx.manifest()[f]))
4216 ui.write("%40s " % hex(ctx.manifest()[f]))
4212 if ui.verbose:
4217 if ui.verbose:
4213 ui.write(decor[ctx.flags(f)])
4218 ui.write(decor[ctx.flags(f)])
4214 ui.write("%s\n" % f)
4219 ui.write("%s\n" % f)
4215
4220
4216 @command('^merge',
4221 @command('^merge',
4217 [('f', 'force', None, _('force a merge with outstanding changes')),
4222 [('f', 'force', None, _('force a merge with outstanding changes')),
4218 ('r', 'rev', '', _('revision to merge'), _('REV')),
4223 ('r', 'rev', '', _('revision to merge'), _('REV')),
4219 ('P', 'preview', None,
4224 ('P', 'preview', None,
4220 _('review revisions to merge (no merge is performed)'))
4225 _('review revisions to merge (no merge is performed)'))
4221 ] + mergetoolopts,
4226 ] + mergetoolopts,
4222 _('[-P] [-f] [[-r] REV]'))
4227 _('[-P] [-f] [[-r] REV]'))
4223 def merge(ui, repo, node=None, **opts):
4228 def merge(ui, repo, node=None, **opts):
4224 """merge working directory with another revision
4229 """merge working directory with another revision
4225
4230
4226 The current working directory is updated with all changes made in
4231 The current working directory is updated with all changes made in
4227 the requested revision since the last common predecessor revision.
4232 the requested revision since the last common predecessor revision.
4228
4233
4229 Files that changed between either parent are marked as changed for
4234 Files that changed between either parent are marked as changed for
4230 the next commit and a commit must be performed before any further
4235 the next commit and a commit must be performed before any further
4231 updates to the repository are allowed. The next commit will have
4236 updates to the repository are allowed. The next commit will have
4232 two parents.
4237 two parents.
4233
4238
4234 ``--tool`` can be used to specify the merge tool used for file
4239 ``--tool`` can be used to specify the merge tool used for file
4235 merges. It overrides the HGMERGE environment variable and your
4240 merges. It overrides the HGMERGE environment variable and your
4236 configuration files. See :hg:`help merge-tools` for options.
4241 configuration files. See :hg:`help merge-tools` for options.
4237
4242
4238 If no revision is specified, the working directory's parent is a
4243 If no revision is specified, the working directory's parent is a
4239 head revision, and the current branch contains exactly one other
4244 head revision, and the current branch contains exactly one other
4240 head, the other head is merged with by default. Otherwise, an
4245 head, the other head is merged with by default. Otherwise, an
4241 explicit revision with which to merge with must be provided.
4246 explicit revision with which to merge with must be provided.
4242
4247
4243 :hg:`resolve` must be used to resolve unresolved files.
4248 :hg:`resolve` must be used to resolve unresolved files.
4244
4249
4245 To undo an uncommitted merge, use :hg:`update --clean .` which
4250 To undo an uncommitted merge, use :hg:`update --clean .` which
4246 will check out a clean copy of the original merge parent, losing
4251 will check out a clean copy of the original merge parent, losing
4247 all changes.
4252 all changes.
4248
4253
4249 Returns 0 on success, 1 if there are unresolved files.
4254 Returns 0 on success, 1 if there are unresolved files.
4250 """
4255 """
4251
4256
4252 if opts.get('rev') and node:
4257 if opts.get('rev') and node:
4253 raise util.Abort(_("please specify just one revision"))
4258 raise util.Abort(_("please specify just one revision"))
4254 if not node:
4259 if not node:
4255 node = opts.get('rev')
4260 node = opts.get('rev')
4256
4261
4257 if node:
4262 if node:
4258 node = scmutil.revsingle(repo, node).node()
4263 node = scmutil.revsingle(repo, node).node()
4259
4264
4260 if not node and repo._bookmarkcurrent:
4265 if not node and repo._bookmarkcurrent:
4261 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4266 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4262 curhead = repo[repo._bookmarkcurrent]
4267 curhead = repo[repo._bookmarkcurrent]
4263 if len(bmheads) == 2:
4268 if len(bmheads) == 2:
4264 if curhead == bmheads[0]:
4269 if curhead == bmheads[0]:
4265 node = bmheads[1]
4270 node = bmheads[1]
4266 else:
4271 else:
4267 node = bmheads[0]
4272 node = bmheads[0]
4268 elif len(bmheads) > 2:
4273 elif len(bmheads) > 2:
4269 raise util.Abort(_("multiple matching bookmarks to merge - "
4274 raise util.Abort(_("multiple matching bookmarks to merge - "
4270 "please merge with an explicit rev or bookmark"),
4275 "please merge with an explicit rev or bookmark"),
4271 hint=_("run 'hg heads' to see all heads"))
4276 hint=_("run 'hg heads' to see all heads"))
4272 elif len(bmheads) <= 1:
4277 elif len(bmheads) <= 1:
4273 raise util.Abort(_("no matching bookmark to merge - "
4278 raise util.Abort(_("no matching bookmark to merge - "
4274 "please merge with an explicit rev or bookmark"),
4279 "please merge with an explicit rev or bookmark"),
4275 hint=_("run 'hg heads' to see all heads"))
4280 hint=_("run 'hg heads' to see all heads"))
4276
4281
4277 if not node and not repo._bookmarkcurrent:
4282 if not node and not repo._bookmarkcurrent:
4278 branch = repo[None].branch()
4283 branch = repo[None].branch()
4279 bheads = repo.branchheads(branch)
4284 bheads = repo.branchheads(branch)
4280 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4285 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4281
4286
4282 if len(nbhs) > 2:
4287 if len(nbhs) > 2:
4283 raise util.Abort(_("branch '%s' has %d heads - "
4288 raise util.Abort(_("branch '%s' has %d heads - "
4284 "please merge with an explicit rev")
4289 "please merge with an explicit rev")
4285 % (branch, len(bheads)),
4290 % (branch, len(bheads)),
4286 hint=_("run 'hg heads .' to see heads"))
4291 hint=_("run 'hg heads .' to see heads"))
4287
4292
4288 parent = repo.dirstate.p1()
4293 parent = repo.dirstate.p1()
4289 if len(nbhs) <= 1:
4294 if len(nbhs) <= 1:
4290 if len(bheads) > 1:
4295 if len(bheads) > 1:
4291 raise util.Abort(_("heads are bookmarked - "
4296 raise util.Abort(_("heads are bookmarked - "
4292 "please merge with an explicit rev"),
4297 "please merge with an explicit rev"),
4293 hint=_("run 'hg heads' to see all heads"))
4298 hint=_("run 'hg heads' to see all heads"))
4294 if len(repo.heads()) > 1:
4299 if len(repo.heads()) > 1:
4295 raise util.Abort(_("branch '%s' has one head - "
4300 raise util.Abort(_("branch '%s' has one head - "
4296 "please merge with an explicit rev")
4301 "please merge with an explicit rev")
4297 % branch,
4302 % branch,
4298 hint=_("run 'hg heads' to see all heads"))
4303 hint=_("run 'hg heads' to see all heads"))
4299 msg, hint = _('nothing to merge'), None
4304 msg, hint = _('nothing to merge'), None
4300 if parent != repo.lookup(branch):
4305 if parent != repo.lookup(branch):
4301 hint = _("use 'hg update' instead")
4306 hint = _("use 'hg update' instead")
4302 raise util.Abort(msg, hint=hint)
4307 raise util.Abort(msg, hint=hint)
4303
4308
4304 if parent not in bheads:
4309 if parent not in bheads:
4305 raise util.Abort(_('working directory not at a head revision'),
4310 raise util.Abort(_('working directory not at a head revision'),
4306 hint=_("use 'hg update' or merge with an "
4311 hint=_("use 'hg update' or merge with an "
4307 "explicit revision"))
4312 "explicit revision"))
4308 if parent == nbhs[0]:
4313 if parent == nbhs[0]:
4309 node = nbhs[-1]
4314 node = nbhs[-1]
4310 else:
4315 else:
4311 node = nbhs[0]
4316 node = nbhs[0]
4312
4317
4313 if opts.get('preview'):
4318 if opts.get('preview'):
4314 # find nodes that are ancestors of p2 but not of p1
4319 # find nodes that are ancestors of p2 but not of p1
4315 p1 = repo.lookup('.')
4320 p1 = repo.lookup('.')
4316 p2 = repo.lookup(node)
4321 p2 = repo.lookup(node)
4317 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4322 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4318
4323
4319 displayer = cmdutil.show_changeset(ui, repo, opts)
4324 displayer = cmdutil.show_changeset(ui, repo, opts)
4320 for node in nodes:
4325 for node in nodes:
4321 displayer.show(repo[node])
4326 displayer.show(repo[node])
4322 displayer.close()
4327 displayer.close()
4323 return 0
4328 return 0
4324
4329
4325 try:
4330 try:
4326 # ui.forcemerge is an internal variable, do not document
4331 # ui.forcemerge is an internal variable, do not document
4327 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4332 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4328 return hg.merge(repo, node, force=opts.get('force'))
4333 return hg.merge(repo, node, force=opts.get('force'))
4329 finally:
4334 finally:
4330 ui.setconfig('ui', 'forcemerge', '')
4335 ui.setconfig('ui', 'forcemerge', '')
4331
4336
4332 @command('outgoing|out',
4337 @command('outgoing|out',
4333 [('f', 'force', None, _('run even when the destination is unrelated')),
4338 [('f', 'force', None, _('run even when the destination is unrelated')),
4334 ('r', 'rev', [],
4339 ('r', 'rev', [],
4335 _('a changeset intended to be included in the destination'), _('REV')),
4340 _('a changeset intended to be included in the destination'), _('REV')),
4336 ('n', 'newest-first', None, _('show newest record first')),
4341 ('n', 'newest-first', None, _('show newest record first')),
4337 ('B', 'bookmarks', False, _('compare bookmarks')),
4342 ('B', 'bookmarks', False, _('compare bookmarks')),
4338 ('b', 'branch', [], _('a specific branch you would like to push'),
4343 ('b', 'branch', [], _('a specific branch you would like to push'),
4339 _('BRANCH')),
4344 _('BRANCH')),
4340 ] + logopts + remoteopts + subrepoopts,
4345 ] + logopts + remoteopts + subrepoopts,
4341 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4346 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4342 def outgoing(ui, repo, dest=None, **opts):
4347 def outgoing(ui, repo, dest=None, **opts):
4343 """show changesets not found in the destination
4348 """show changesets not found in the destination
4344
4349
4345 Show changesets not found in the specified destination repository
4350 Show changesets not found in the specified destination repository
4346 or the default push location. These are the changesets that would
4351 or the default push location. These are the changesets that would
4347 be pushed if a push was requested.
4352 be pushed if a push was requested.
4348
4353
4349 See pull for details of valid destination formats.
4354 See pull for details of valid destination formats.
4350
4355
4351 Returns 0 if there are outgoing changes, 1 otherwise.
4356 Returns 0 if there are outgoing changes, 1 otherwise.
4352 """
4357 """
4353 if opts.get('graph'):
4358 if opts.get('graph'):
4354 cmdutil.checkunsupportedgraphflags([], opts)
4359 cmdutil.checkunsupportedgraphflags([], opts)
4355 o = hg._outgoing(ui, repo, dest, opts)
4360 o = hg._outgoing(ui, repo, dest, opts)
4356 if o is None:
4361 if o is None:
4357 return
4362 return
4358
4363
4359 revdag = cmdutil.graphrevs(repo, o, opts)
4364 revdag = cmdutil.graphrevs(repo, o, opts)
4360 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4365 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4361 showparents = [ctx.node() for ctx in repo[None].parents()]
4366 showparents = [ctx.node() for ctx in repo[None].parents()]
4362 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4367 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4363 graphmod.asciiedges)
4368 graphmod.asciiedges)
4364 return 0
4369 return 0
4365
4370
4366 if opts.get('bookmarks'):
4371 if opts.get('bookmarks'):
4367 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4372 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4368 dest, branches = hg.parseurl(dest, opts.get('branch'))
4373 dest, branches = hg.parseurl(dest, opts.get('branch'))
4369 other = hg.peer(repo, opts, dest)
4374 other = hg.peer(repo, opts, dest)
4370 if 'bookmarks' not in other.listkeys('namespaces'):
4375 if 'bookmarks' not in other.listkeys('namespaces'):
4371 ui.warn(_("remote doesn't support bookmarks\n"))
4376 ui.warn(_("remote doesn't support bookmarks\n"))
4372 return 0
4377 return 0
4373 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4378 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4374 return bookmarks.diff(ui, other, repo)
4379 return bookmarks.diff(ui, other, repo)
4375
4380
4376 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4381 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4377 try:
4382 try:
4378 return hg.outgoing(ui, repo, dest, opts)
4383 return hg.outgoing(ui, repo, dest, opts)
4379 finally:
4384 finally:
4380 del repo._subtoppath
4385 del repo._subtoppath
4381
4386
4382 @command('parents',
4387 @command('parents',
4383 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4388 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4384 ] + templateopts,
4389 ] + templateopts,
4385 _('[-r REV] [FILE]'))
4390 _('[-r REV] [FILE]'))
4386 def parents(ui, repo, file_=None, **opts):
4391 def parents(ui, repo, file_=None, **opts):
4387 """show the parents of the working directory or revision
4392 """show the parents of the working directory or revision
4388
4393
4389 Print the working directory's parent revisions. If a revision is
4394 Print the working directory's parent revisions. If a revision is
4390 given via -r/--rev, the parent of that revision will be printed.
4395 given via -r/--rev, the parent of that revision will be printed.
4391 If a file argument is given, the revision in which the file was
4396 If a file argument is given, the revision in which the file was
4392 last changed (before the working directory revision or the
4397 last changed (before the working directory revision or the
4393 argument to --rev if given) is printed.
4398 argument to --rev if given) is printed.
4394
4399
4395 Returns 0 on success.
4400 Returns 0 on success.
4396 """
4401 """
4397
4402
4398 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4403 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4399
4404
4400 if file_:
4405 if file_:
4401 m = scmutil.match(ctx, (file_,), opts)
4406 m = scmutil.match(ctx, (file_,), opts)
4402 if m.anypats() or len(m.files()) != 1:
4407 if m.anypats() or len(m.files()) != 1:
4403 raise util.Abort(_('can only specify an explicit filename'))
4408 raise util.Abort(_('can only specify an explicit filename'))
4404 file_ = m.files()[0]
4409 file_ = m.files()[0]
4405 filenodes = []
4410 filenodes = []
4406 for cp in ctx.parents():
4411 for cp in ctx.parents():
4407 if not cp:
4412 if not cp:
4408 continue
4413 continue
4409 try:
4414 try:
4410 filenodes.append(cp.filenode(file_))
4415 filenodes.append(cp.filenode(file_))
4411 except error.LookupError:
4416 except error.LookupError:
4412 pass
4417 pass
4413 if not filenodes:
4418 if not filenodes:
4414 raise util.Abort(_("'%s' not found in manifest!") % file_)
4419 raise util.Abort(_("'%s' not found in manifest!") % file_)
4415 fl = repo.file(file_)
4420 fl = repo.file(file_)
4416 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4421 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
4417 else:
4422 else:
4418 p = [cp.node() for cp in ctx.parents()]
4423 p = [cp.node() for cp in ctx.parents()]
4419
4424
4420 displayer = cmdutil.show_changeset(ui, repo, opts)
4425 displayer = cmdutil.show_changeset(ui, repo, opts)
4421 for n in p:
4426 for n in p:
4422 if n != nullid:
4427 if n != nullid:
4423 displayer.show(repo[n])
4428 displayer.show(repo[n])
4424 displayer.close()
4429 displayer.close()
4425
4430
4426 @command('paths', [], _('[NAME]'))
4431 @command('paths', [], _('[NAME]'))
4427 def paths(ui, repo, search=None):
4432 def paths(ui, repo, search=None):
4428 """show aliases for remote repositories
4433 """show aliases for remote repositories
4429
4434
4430 Show definition of symbolic path name NAME. If no name is given,
4435 Show definition of symbolic path name NAME. If no name is given,
4431 show definition of all available names.
4436 show definition of all available names.
4432
4437
4433 Option -q/--quiet suppresses all output when searching for NAME
4438 Option -q/--quiet suppresses all output when searching for NAME
4434 and shows only the path names when listing all definitions.
4439 and shows only the path names when listing all definitions.
4435
4440
4436 Path names are defined in the [paths] section of your
4441 Path names are defined in the [paths] section of your
4437 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4442 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4438 repository, ``.hg/hgrc`` is used, too.
4443 repository, ``.hg/hgrc`` is used, too.
4439
4444
4440 The path names ``default`` and ``default-push`` have a special
4445 The path names ``default`` and ``default-push`` have a special
4441 meaning. When performing a push or pull operation, they are used
4446 meaning. When performing a push or pull operation, they are used
4442 as fallbacks if no location is specified on the command-line.
4447 as fallbacks if no location is specified on the command-line.
4443 When ``default-push`` is set, it will be used for push and
4448 When ``default-push`` is set, it will be used for push and
4444 ``default`` will be used for pull; otherwise ``default`` is used
4449 ``default`` will be used for pull; otherwise ``default`` is used
4445 as the fallback for both. When cloning a repository, the clone
4450 as the fallback for both. When cloning a repository, the clone
4446 source is written as ``default`` in ``.hg/hgrc``. Note that
4451 source is written as ``default`` in ``.hg/hgrc``. Note that
4447 ``default`` and ``default-push`` apply to all inbound (e.g.
4452 ``default`` and ``default-push`` apply to all inbound (e.g.
4448 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4453 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4449 :hg:`bundle`) operations.
4454 :hg:`bundle`) operations.
4450
4455
4451 See :hg:`help urls` for more information.
4456 See :hg:`help urls` for more information.
4452
4457
4453 Returns 0 on success.
4458 Returns 0 on success.
4454 """
4459 """
4455 if search:
4460 if search:
4456 for name, path in ui.configitems("paths"):
4461 for name, path in ui.configitems("paths"):
4457 if name == search:
4462 if name == search:
4458 ui.status("%s\n" % util.hidepassword(path))
4463 ui.status("%s\n" % util.hidepassword(path))
4459 return
4464 return
4460 if not ui.quiet:
4465 if not ui.quiet:
4461 ui.warn(_("not found!\n"))
4466 ui.warn(_("not found!\n"))
4462 return 1
4467 return 1
4463 else:
4468 else:
4464 for name, path in ui.configitems("paths"):
4469 for name, path in ui.configitems("paths"):
4465 if ui.quiet:
4470 if ui.quiet:
4466 ui.write("%s\n" % name)
4471 ui.write("%s\n" % name)
4467 else:
4472 else:
4468 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4473 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4469
4474
4470 @command('^phase',
4475 @command('^phase',
4471 [('p', 'public', False, _('set changeset phase to public')),
4476 [('p', 'public', False, _('set changeset phase to public')),
4472 ('d', 'draft', False, _('set changeset phase to draft')),
4477 ('d', 'draft', False, _('set changeset phase to draft')),
4473 ('s', 'secret', False, _('set changeset phase to secret')),
4478 ('s', 'secret', False, _('set changeset phase to secret')),
4474 ('f', 'force', False, _('allow to move boundary backward')),
4479 ('f', 'force', False, _('allow to move boundary backward')),
4475 ('r', 'rev', [], _('target revision'), _('REV')),
4480 ('r', 'rev', [], _('target revision'), _('REV')),
4476 ],
4481 ],
4477 _('[-p|-d|-s] [-f] [-r] REV...'))
4482 _('[-p|-d|-s] [-f] [-r] REV...'))
4478 def phase(ui, repo, *revs, **opts):
4483 def phase(ui, repo, *revs, **opts):
4479 """set or show the current phase name
4484 """set or show the current phase name
4480
4485
4481 With no argument, show the phase name of specified revisions.
4486 With no argument, show the phase name of specified revisions.
4482
4487
4483 With one of -p/--public, -d/--draft or -s/--secret, change the
4488 With one of -p/--public, -d/--draft or -s/--secret, change the
4484 phase value of the specified revisions.
4489 phase value of the specified revisions.
4485
4490
4486 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4491 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4487 lower phase to an higher phase. Phases are ordered as follows::
4492 lower phase to an higher phase. Phases are ordered as follows::
4488
4493
4489 public < draft < secret
4494 public < draft < secret
4490
4495
4491 Return 0 on success, 1 if no phases were changed or some could not
4496 Return 0 on success, 1 if no phases were changed or some could not
4492 be changed.
4497 be changed.
4493 """
4498 """
4494 # search for a unique phase argument
4499 # search for a unique phase argument
4495 targetphase = None
4500 targetphase = None
4496 for idx, name in enumerate(phases.phasenames):
4501 for idx, name in enumerate(phases.phasenames):
4497 if opts[name]:
4502 if opts[name]:
4498 if targetphase is not None:
4503 if targetphase is not None:
4499 raise util.Abort(_('only one phase can be specified'))
4504 raise util.Abort(_('only one phase can be specified'))
4500 targetphase = idx
4505 targetphase = idx
4501
4506
4502 # look for specified revision
4507 # look for specified revision
4503 revs = list(revs)
4508 revs = list(revs)
4504 revs.extend(opts['rev'])
4509 revs.extend(opts['rev'])
4505 if not revs:
4510 if not revs:
4506 raise util.Abort(_('no revisions specified'))
4511 raise util.Abort(_('no revisions specified'))
4507
4512
4508 revs = scmutil.revrange(repo, revs)
4513 revs = scmutil.revrange(repo, revs)
4509
4514
4510 lock = None
4515 lock = None
4511 ret = 0
4516 ret = 0
4512 if targetphase is None:
4517 if targetphase is None:
4513 # display
4518 # display
4514 for r in revs:
4519 for r in revs:
4515 ctx = repo[r]
4520 ctx = repo[r]
4516 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4521 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4517 else:
4522 else:
4518 lock = repo.lock()
4523 lock = repo.lock()
4519 try:
4524 try:
4520 # set phase
4525 # set phase
4521 if not revs:
4526 if not revs:
4522 raise util.Abort(_('empty revision set'))
4527 raise util.Abort(_('empty revision set'))
4523 nodes = [repo[r].node() for r in revs]
4528 nodes = [repo[r].node() for r in revs]
4524 olddata = repo._phasecache.getphaserevs(repo)[:]
4529 olddata = repo._phasecache.getphaserevs(repo)[:]
4525 phases.advanceboundary(repo, targetphase, nodes)
4530 phases.advanceboundary(repo, targetphase, nodes)
4526 if opts['force']:
4531 if opts['force']:
4527 phases.retractboundary(repo, targetphase, nodes)
4532 phases.retractboundary(repo, targetphase, nodes)
4528 finally:
4533 finally:
4529 lock.release()
4534 lock.release()
4530 newdata = repo._phasecache.getphaserevs(repo)
4535 newdata = repo._phasecache.getphaserevs(repo)
4531 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4536 changes = sum(o != newdata[i] for i, o in enumerate(olddata))
4532 rejected = [n for n in nodes
4537 rejected = [n for n in nodes
4533 if newdata[repo[n].rev()] < targetphase]
4538 if newdata[repo[n].rev()] < targetphase]
4534 if rejected:
4539 if rejected:
4535 ui.warn(_('cannot move %i changesets to a more permissive '
4540 ui.warn(_('cannot move %i changesets to a more permissive '
4536 'phase, use --force\n') % len(rejected))
4541 'phase, use --force\n') % len(rejected))
4537 ret = 1
4542 ret = 1
4538 if changes:
4543 if changes:
4539 msg = _('phase changed for %i changesets\n') % changes
4544 msg = _('phase changed for %i changesets\n') % changes
4540 if ret:
4545 if ret:
4541 ui.status(msg)
4546 ui.status(msg)
4542 else:
4547 else:
4543 ui.note(msg)
4548 ui.note(msg)
4544 else:
4549 else:
4545 ui.warn(_('no phases changed\n'))
4550 ui.warn(_('no phases changed\n'))
4546 ret = 1
4551 ret = 1
4547 return ret
4552 return ret
4548
4553
4549 def postincoming(ui, repo, modheads, optupdate, checkout):
4554 def postincoming(ui, repo, modheads, optupdate, checkout):
4550 if modheads == 0:
4555 if modheads == 0:
4551 return
4556 return
4552 if optupdate:
4557 if optupdate:
4553 movemarkfrom = repo['.'].node()
4558 movemarkfrom = repo['.'].node()
4554 try:
4559 try:
4555 ret = hg.update(repo, checkout)
4560 ret = hg.update(repo, checkout)
4556 except util.Abort, inst:
4561 except util.Abort, inst:
4557 ui.warn(_("not updating: %s\n") % str(inst))
4562 ui.warn(_("not updating: %s\n") % str(inst))
4558 return 0
4563 return 0
4559 if not ret and not checkout:
4564 if not ret and not checkout:
4560 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4565 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4561 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4566 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4562 return ret
4567 return ret
4563 if modheads > 1:
4568 if modheads > 1:
4564 currentbranchheads = len(repo.branchheads())
4569 currentbranchheads = len(repo.branchheads())
4565 if currentbranchheads == modheads:
4570 if currentbranchheads == modheads:
4566 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4571 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4567 elif currentbranchheads > 1:
4572 elif currentbranchheads > 1:
4568 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4573 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4569 "merge)\n"))
4574 "merge)\n"))
4570 else:
4575 else:
4571 ui.status(_("(run 'hg heads' to see heads)\n"))
4576 ui.status(_("(run 'hg heads' to see heads)\n"))
4572 else:
4577 else:
4573 ui.status(_("(run 'hg update' to get a working copy)\n"))
4578 ui.status(_("(run 'hg update' to get a working copy)\n"))
4574
4579
4575 @command('^pull',
4580 @command('^pull',
4576 [('u', 'update', None,
4581 [('u', 'update', None,
4577 _('update to new branch head if changesets were pulled')),
4582 _('update to new branch head if changesets were pulled')),
4578 ('f', 'force', None, _('run even when remote repository is unrelated')),
4583 ('f', 'force', None, _('run even when remote repository is unrelated')),
4579 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4584 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4580 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4585 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4581 ('b', 'branch', [], _('a specific branch you would like to pull'),
4586 ('b', 'branch', [], _('a specific branch you would like to pull'),
4582 _('BRANCH')),
4587 _('BRANCH')),
4583 ] + remoteopts,
4588 ] + remoteopts,
4584 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4589 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4585 def pull(ui, repo, source="default", **opts):
4590 def pull(ui, repo, source="default", **opts):
4586 """pull changes from the specified source
4591 """pull changes from the specified source
4587
4592
4588 Pull changes from a remote repository to a local one.
4593 Pull changes from a remote repository to a local one.
4589
4594
4590 This finds all changes from the repository at the specified path
4595 This finds all changes from the repository at the specified path
4591 or URL and adds them to a local repository (the current one unless
4596 or URL and adds them to a local repository (the current one unless
4592 -R is specified). By default, this does not update the copy of the
4597 -R is specified). By default, this does not update the copy of the
4593 project in the working directory.
4598 project in the working directory.
4594
4599
4595 Use :hg:`incoming` if you want to see what would have been added
4600 Use :hg:`incoming` if you want to see what would have been added
4596 by a pull at the time you issued this command. If you then decide
4601 by a pull at the time you issued this command. If you then decide
4597 to add those changes to the repository, you should use :hg:`pull
4602 to add those changes to the repository, you should use :hg:`pull
4598 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4603 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4599
4604
4600 If SOURCE is omitted, the 'default' path will be used.
4605 If SOURCE is omitted, the 'default' path will be used.
4601 See :hg:`help urls` for more information.
4606 See :hg:`help urls` for more information.
4602
4607
4603 Returns 0 on success, 1 if an update had unresolved files.
4608 Returns 0 on success, 1 if an update had unresolved files.
4604 """
4609 """
4605 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4610 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4606 other = hg.peer(repo, opts, source)
4611 other = hg.peer(repo, opts, source)
4607 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4612 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4608 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4613 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
4609
4614
4610 if opts.get('bookmark'):
4615 if opts.get('bookmark'):
4611 if not revs:
4616 if not revs:
4612 revs = []
4617 revs = []
4613 rb = other.listkeys('bookmarks')
4618 rb = other.listkeys('bookmarks')
4614 for b in opts['bookmark']:
4619 for b in opts['bookmark']:
4615 if b not in rb:
4620 if b not in rb:
4616 raise util.Abort(_('remote bookmark %s not found!') % b)
4621 raise util.Abort(_('remote bookmark %s not found!') % b)
4617 revs.append(rb[b])
4622 revs.append(rb[b])
4618
4623
4619 if revs:
4624 if revs:
4620 try:
4625 try:
4621 revs = [other.lookup(rev) for rev in revs]
4626 revs = [other.lookup(rev) for rev in revs]
4622 except error.CapabilityError:
4627 except error.CapabilityError:
4623 err = _("other repository doesn't support revision lookup, "
4628 err = _("other repository doesn't support revision lookup, "
4624 "so a rev cannot be specified.")
4629 "so a rev cannot be specified.")
4625 raise util.Abort(err)
4630 raise util.Abort(err)
4626
4631
4627 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4632 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
4628 bookmarks.updatefromremote(ui, repo, other, source)
4633 bookmarks.updatefromremote(ui, repo, other, source)
4629 if checkout:
4634 if checkout:
4630 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4635 checkout = str(repo.changelog.rev(other.lookup(checkout)))
4631 repo._subtoppath = source
4636 repo._subtoppath = source
4632 try:
4637 try:
4633 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4638 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
4634
4639
4635 finally:
4640 finally:
4636 del repo._subtoppath
4641 del repo._subtoppath
4637
4642
4638 # update specified bookmarks
4643 # update specified bookmarks
4639 if opts.get('bookmark'):
4644 if opts.get('bookmark'):
4640 for b in opts['bookmark']:
4645 for b in opts['bookmark']:
4641 # explicit pull overrides local bookmark if any
4646 # explicit pull overrides local bookmark if any
4642 ui.status(_("importing bookmark %s\n") % b)
4647 ui.status(_("importing bookmark %s\n") % b)
4643 repo._bookmarks[b] = repo[rb[b]].node()
4648 repo._bookmarks[b] = repo[rb[b]].node()
4644 bookmarks.write(repo)
4649 bookmarks.write(repo)
4645
4650
4646 return ret
4651 return ret
4647
4652
4648 @command('^push',
4653 @command('^push',
4649 [('f', 'force', None, _('force push')),
4654 [('f', 'force', None, _('force push')),
4650 ('r', 'rev', [],
4655 ('r', 'rev', [],
4651 _('a changeset intended to be included in the destination'),
4656 _('a changeset intended to be included in the destination'),
4652 _('REV')),
4657 _('REV')),
4653 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4658 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4654 ('b', 'branch', [],
4659 ('b', 'branch', [],
4655 _('a specific branch you would like to push'), _('BRANCH')),
4660 _('a specific branch you would like to push'), _('BRANCH')),
4656 ('', 'new-branch', False, _('allow pushing a new branch')),
4661 ('', 'new-branch', False, _('allow pushing a new branch')),
4657 ] + remoteopts,
4662 ] + remoteopts,
4658 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4663 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
4659 def push(ui, repo, dest=None, **opts):
4664 def push(ui, repo, dest=None, **opts):
4660 """push changes to the specified destination
4665 """push changes to the specified destination
4661
4666
4662 Push changesets from the local repository to the specified
4667 Push changesets from the local repository to the specified
4663 destination.
4668 destination.
4664
4669
4665 This operation is symmetrical to pull: it is identical to a pull
4670 This operation is symmetrical to pull: it is identical to a pull
4666 in the destination repository from the current one.
4671 in the destination repository from the current one.
4667
4672
4668 By default, push will not allow creation of new heads at the
4673 By default, push will not allow creation of new heads at the
4669 destination, since multiple heads would make it unclear which head
4674 destination, since multiple heads would make it unclear which head
4670 to use. In this situation, it is recommended to pull and merge
4675 to use. In this situation, it is recommended to pull and merge
4671 before pushing.
4676 before pushing.
4672
4677
4673 Use --new-branch if you want to allow push to create a new named
4678 Use --new-branch if you want to allow push to create a new named
4674 branch that is not present at the destination. This allows you to
4679 branch that is not present at the destination. This allows you to
4675 only create a new branch without forcing other changes.
4680 only create a new branch without forcing other changes.
4676
4681
4677 Use -f/--force to override the default behavior and push all
4682 Use -f/--force to override the default behavior and push all
4678 changesets on all branches.
4683 changesets on all branches.
4679
4684
4680 If -r/--rev is used, the specified revision and all its ancestors
4685 If -r/--rev is used, the specified revision and all its ancestors
4681 will be pushed to the remote repository.
4686 will be pushed to the remote repository.
4682
4687
4683 If -B/--bookmark is used, the specified bookmarked revision, its
4688 If -B/--bookmark is used, the specified bookmarked revision, its
4684 ancestors, and the bookmark will be pushed to the remote
4689 ancestors, and the bookmark will be pushed to the remote
4685 repository.
4690 repository.
4686
4691
4687 Please see :hg:`help urls` for important details about ``ssh://``
4692 Please see :hg:`help urls` for important details about ``ssh://``
4688 URLs. If DESTINATION is omitted, a default path will be used.
4693 URLs. If DESTINATION is omitted, a default path will be used.
4689
4694
4690 Returns 0 if push was successful, 1 if nothing to push.
4695 Returns 0 if push was successful, 1 if nothing to push.
4691 """
4696 """
4692
4697
4693 if opts.get('bookmark'):
4698 if opts.get('bookmark'):
4694 for b in opts['bookmark']:
4699 for b in opts['bookmark']:
4695 # translate -B options to -r so changesets get pushed
4700 # translate -B options to -r so changesets get pushed
4696 if b in repo._bookmarks:
4701 if b in repo._bookmarks:
4697 opts.setdefault('rev', []).append(b)
4702 opts.setdefault('rev', []).append(b)
4698 else:
4703 else:
4699 # if we try to push a deleted bookmark, translate it to null
4704 # if we try to push a deleted bookmark, translate it to null
4700 # this lets simultaneous -r, -b options continue working
4705 # this lets simultaneous -r, -b options continue working
4701 opts.setdefault('rev', []).append("null")
4706 opts.setdefault('rev', []).append("null")
4702
4707
4703 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4708 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4704 dest, branches = hg.parseurl(dest, opts.get('branch'))
4709 dest, branches = hg.parseurl(dest, opts.get('branch'))
4705 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4710 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
4706 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4711 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
4707 other = hg.peer(repo, opts, dest)
4712 other = hg.peer(repo, opts, dest)
4708 if revs:
4713 if revs:
4709 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4714 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
4710
4715
4711 repo._subtoppath = dest
4716 repo._subtoppath = dest
4712 try:
4717 try:
4713 # push subrepos depth-first for coherent ordering
4718 # push subrepos depth-first for coherent ordering
4714 c = repo['']
4719 c = repo['']
4715 subs = c.substate # only repos that are committed
4720 subs = c.substate # only repos that are committed
4716 for s in sorted(subs):
4721 for s in sorted(subs):
4717 if c.sub(s).push(opts) == 0:
4722 if c.sub(s).push(opts) == 0:
4718 return False
4723 return False
4719 finally:
4724 finally:
4720 del repo._subtoppath
4725 del repo._subtoppath
4721 result = repo.push(other, opts.get('force'), revs=revs,
4726 result = repo.push(other, opts.get('force'), revs=revs,
4722 newbranch=opts.get('new_branch'))
4727 newbranch=opts.get('new_branch'))
4723
4728
4724 result = not result
4729 result = not result
4725
4730
4726 if opts.get('bookmark'):
4731 if opts.get('bookmark'):
4727 rb = other.listkeys('bookmarks')
4732 rb = other.listkeys('bookmarks')
4728 for b in opts['bookmark']:
4733 for b in opts['bookmark']:
4729 # explicit push overrides remote bookmark if any
4734 # explicit push overrides remote bookmark if any
4730 if b in repo._bookmarks:
4735 if b in repo._bookmarks:
4731 ui.status(_("exporting bookmark %s\n") % b)
4736 ui.status(_("exporting bookmark %s\n") % b)
4732 new = repo[b].hex()
4737 new = repo[b].hex()
4733 elif b in rb:
4738 elif b in rb:
4734 ui.status(_("deleting remote bookmark %s\n") % b)
4739 ui.status(_("deleting remote bookmark %s\n") % b)
4735 new = '' # delete
4740 new = '' # delete
4736 else:
4741 else:
4737 ui.warn(_('bookmark %s does not exist on the local '
4742 ui.warn(_('bookmark %s does not exist on the local '
4738 'or remote repository!\n') % b)
4743 'or remote repository!\n') % b)
4739 return 2
4744 return 2
4740 old = rb.get(b, '')
4745 old = rb.get(b, '')
4741 r = other.pushkey('bookmarks', b, old, new)
4746 r = other.pushkey('bookmarks', b, old, new)
4742 if not r:
4747 if not r:
4743 ui.warn(_('updating bookmark %s failed!\n') % b)
4748 ui.warn(_('updating bookmark %s failed!\n') % b)
4744 if not result:
4749 if not result:
4745 result = 2
4750 result = 2
4746
4751
4747 return result
4752 return result
4748
4753
4749 @command('recover', [])
4754 @command('recover', [])
4750 def recover(ui, repo):
4755 def recover(ui, repo):
4751 """roll back an interrupted transaction
4756 """roll back an interrupted transaction
4752
4757
4753 Recover from an interrupted commit or pull.
4758 Recover from an interrupted commit or pull.
4754
4759
4755 This command tries to fix the repository status after an
4760 This command tries to fix the repository status after an
4756 interrupted operation. It should only be necessary when Mercurial
4761 interrupted operation. It should only be necessary when Mercurial
4757 suggests it.
4762 suggests it.
4758
4763
4759 Returns 0 if successful, 1 if nothing to recover or verify fails.
4764 Returns 0 if successful, 1 if nothing to recover or verify fails.
4760 """
4765 """
4761 if repo.recover():
4766 if repo.recover():
4762 return hg.verify(repo)
4767 return hg.verify(repo)
4763 return 1
4768 return 1
4764
4769
4765 @command('^remove|rm',
4770 @command('^remove|rm',
4766 [('A', 'after', None, _('record delete for missing files')),
4771 [('A', 'after', None, _('record delete for missing files')),
4767 ('f', 'force', None,
4772 ('f', 'force', None,
4768 _('remove (and delete) file even if added or modified')),
4773 _('remove (and delete) file even if added or modified')),
4769 ] + walkopts,
4774 ] + walkopts,
4770 _('[OPTION]... FILE...'))
4775 _('[OPTION]... FILE...'))
4771 def remove(ui, repo, *pats, **opts):
4776 def remove(ui, repo, *pats, **opts):
4772 """remove the specified files on the next commit
4777 """remove the specified files on the next commit
4773
4778
4774 Schedule the indicated files for removal from the current branch.
4779 Schedule the indicated files for removal from the current branch.
4775
4780
4776 This command schedules the files to be removed at the next commit.
4781 This command schedules the files to be removed at the next commit.
4777 To undo a remove before that, see :hg:`revert`. To undo added
4782 To undo a remove before that, see :hg:`revert`. To undo added
4778 files, see :hg:`forget`.
4783 files, see :hg:`forget`.
4779
4784
4780 .. container:: verbose
4785 .. container:: verbose
4781
4786
4782 -A/--after can be used to remove only files that have already
4787 -A/--after can be used to remove only files that have already
4783 been deleted, -f/--force can be used to force deletion, and -Af
4788 been deleted, -f/--force can be used to force deletion, and -Af
4784 can be used to remove files from the next revision without
4789 can be used to remove files from the next revision without
4785 deleting them from the working directory.
4790 deleting them from the working directory.
4786
4791
4787 The following table details the behavior of remove for different
4792 The following table details the behavior of remove for different
4788 file states (columns) and option combinations (rows). The file
4793 file states (columns) and option combinations (rows). The file
4789 states are Added [A], Clean [C], Modified [M] and Missing [!]
4794 states are Added [A], Clean [C], Modified [M] and Missing [!]
4790 (as reported by :hg:`status`). The actions are Warn, Remove
4795 (as reported by :hg:`status`). The actions are Warn, Remove
4791 (from branch) and Delete (from disk):
4796 (from branch) and Delete (from disk):
4792
4797
4793 ======= == == == ==
4798 ======= == == == ==
4794 A C M !
4799 A C M !
4795 ======= == == == ==
4800 ======= == == == ==
4796 none W RD W R
4801 none W RD W R
4797 -f R RD RD R
4802 -f R RD RD R
4798 -A W W W R
4803 -A W W W R
4799 -Af R R R R
4804 -Af R R R R
4800 ======= == == == ==
4805 ======= == == == ==
4801
4806
4802 Note that remove never deletes files in Added [A] state from the
4807 Note that remove never deletes files in Added [A] state from the
4803 working directory, not even if option --force is specified.
4808 working directory, not even if option --force is specified.
4804
4809
4805 Returns 0 on success, 1 if any warnings encountered.
4810 Returns 0 on success, 1 if any warnings encountered.
4806 """
4811 """
4807
4812
4808 ret = 0
4813 ret = 0
4809 after, force = opts.get('after'), opts.get('force')
4814 after, force = opts.get('after'), opts.get('force')
4810 if not pats and not after:
4815 if not pats and not after:
4811 raise util.Abort(_('no files specified'))
4816 raise util.Abort(_('no files specified'))
4812
4817
4813 m = scmutil.match(repo[None], pats, opts)
4818 m = scmutil.match(repo[None], pats, opts)
4814 s = repo.status(match=m, clean=True)
4819 s = repo.status(match=m, clean=True)
4815 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4820 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
4816
4821
4817 for f in m.files():
4822 for f in m.files():
4818 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4823 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
4819 if os.path.exists(m.rel(f)):
4824 if os.path.exists(m.rel(f)):
4820 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4825 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
4821 ret = 1
4826 ret = 1
4822
4827
4823 if force:
4828 if force:
4824 list = modified + deleted + clean + added
4829 list = modified + deleted + clean + added
4825 elif after:
4830 elif after:
4826 list = deleted
4831 list = deleted
4827 for f in modified + added + clean:
4832 for f in modified + added + clean:
4828 ui.warn(_('not removing %s: file still exists (use -f'
4833 ui.warn(_('not removing %s: file still exists (use -f'
4829 ' to force removal)\n') % m.rel(f))
4834 ' to force removal)\n') % m.rel(f))
4830 ret = 1
4835 ret = 1
4831 else:
4836 else:
4832 list = deleted + clean
4837 list = deleted + clean
4833 for f in modified:
4838 for f in modified:
4834 ui.warn(_('not removing %s: file is modified (use -f'
4839 ui.warn(_('not removing %s: file is modified (use -f'
4835 ' to force removal)\n') % m.rel(f))
4840 ' to force removal)\n') % m.rel(f))
4836 ret = 1
4841 ret = 1
4837 for f in added:
4842 for f in added:
4838 ui.warn(_('not removing %s: file has been marked for add'
4843 ui.warn(_('not removing %s: file has been marked for add'
4839 ' (use forget to undo)\n') % m.rel(f))
4844 ' (use forget to undo)\n') % m.rel(f))
4840 ret = 1
4845 ret = 1
4841
4846
4842 for f in sorted(list):
4847 for f in sorted(list):
4843 if ui.verbose or not m.exact(f):
4848 if ui.verbose or not m.exact(f):
4844 ui.status(_('removing %s\n') % m.rel(f))
4849 ui.status(_('removing %s\n') % m.rel(f))
4845
4850
4846 wlock = repo.wlock()
4851 wlock = repo.wlock()
4847 try:
4852 try:
4848 if not after:
4853 if not after:
4849 for f in list:
4854 for f in list:
4850 if f in added:
4855 if f in added:
4851 continue # we never unlink added files on remove
4856 continue # we never unlink added files on remove
4852 try:
4857 try:
4853 util.unlinkpath(repo.wjoin(f))
4858 util.unlinkpath(repo.wjoin(f))
4854 except OSError, inst:
4859 except OSError, inst:
4855 if inst.errno != errno.ENOENT:
4860 if inst.errno != errno.ENOENT:
4856 raise
4861 raise
4857 repo[None].forget(list)
4862 repo[None].forget(list)
4858 finally:
4863 finally:
4859 wlock.release()
4864 wlock.release()
4860
4865
4861 return ret
4866 return ret
4862
4867
4863 @command('rename|move|mv',
4868 @command('rename|move|mv',
4864 [('A', 'after', None, _('record a rename that has already occurred')),
4869 [('A', 'after', None, _('record a rename that has already occurred')),
4865 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4870 ('f', 'force', None, _('forcibly copy over an existing managed file')),
4866 ] + walkopts + dryrunopts,
4871 ] + walkopts + dryrunopts,
4867 _('[OPTION]... SOURCE... DEST'))
4872 _('[OPTION]... SOURCE... DEST'))
4868 def rename(ui, repo, *pats, **opts):
4873 def rename(ui, repo, *pats, **opts):
4869 """rename files; equivalent of copy + remove
4874 """rename files; equivalent of copy + remove
4870
4875
4871 Mark dest as copies of sources; mark sources for deletion. If dest
4876 Mark dest as copies of sources; mark sources for deletion. If dest
4872 is a directory, copies are put in that directory. If dest is a
4877 is a directory, copies are put in that directory. If dest is a
4873 file, there can only be one source.
4878 file, there can only be one source.
4874
4879
4875 By default, this command copies the contents of files as they
4880 By default, this command copies the contents of files as they
4876 exist in the working directory. If invoked with -A/--after, the
4881 exist in the working directory. If invoked with -A/--after, the
4877 operation is recorded, but no copying is performed.
4882 operation is recorded, but no copying is performed.
4878
4883
4879 This command takes effect at the next commit. To undo a rename
4884 This command takes effect at the next commit. To undo a rename
4880 before that, see :hg:`revert`.
4885 before that, see :hg:`revert`.
4881
4886
4882 Returns 0 on success, 1 if errors are encountered.
4887 Returns 0 on success, 1 if errors are encountered.
4883 """
4888 """
4884 wlock = repo.wlock(False)
4889 wlock = repo.wlock(False)
4885 try:
4890 try:
4886 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4891 return cmdutil.copy(ui, repo, pats, opts, rename=True)
4887 finally:
4892 finally:
4888 wlock.release()
4893 wlock.release()
4889
4894
4890 @command('resolve',
4895 @command('resolve',
4891 [('a', 'all', None, _('select all unresolved files')),
4896 [('a', 'all', None, _('select all unresolved files')),
4892 ('l', 'list', None, _('list state of files needing merge')),
4897 ('l', 'list', None, _('list state of files needing merge')),
4893 ('m', 'mark', None, _('mark files as resolved')),
4898 ('m', 'mark', None, _('mark files as resolved')),
4894 ('u', 'unmark', None, _('mark files as unresolved')),
4899 ('u', 'unmark', None, _('mark files as unresolved')),
4895 ('n', 'no-status', None, _('hide status prefix'))]
4900 ('n', 'no-status', None, _('hide status prefix'))]
4896 + mergetoolopts + walkopts,
4901 + mergetoolopts + walkopts,
4897 _('[OPTION]... [FILE]...'))
4902 _('[OPTION]... [FILE]...'))
4898 def resolve(ui, repo, *pats, **opts):
4903 def resolve(ui, repo, *pats, **opts):
4899 """redo merges or set/view the merge status of files
4904 """redo merges or set/view the merge status of files
4900
4905
4901 Merges with unresolved conflicts are often the result of
4906 Merges with unresolved conflicts are often the result of
4902 non-interactive merging using the ``internal:merge`` configuration
4907 non-interactive merging using the ``internal:merge`` configuration
4903 setting, or a command-line merge tool like ``diff3``. The resolve
4908 setting, or a command-line merge tool like ``diff3``. The resolve
4904 command is used to manage the files involved in a merge, after
4909 command is used to manage the files involved in a merge, after
4905 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4910 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
4906 working directory must have two parents). See :hg:`help
4911 working directory must have two parents). See :hg:`help
4907 merge-tools` for information on configuring merge tools.
4912 merge-tools` for information on configuring merge tools.
4908
4913
4909 The resolve command can be used in the following ways:
4914 The resolve command can be used in the following ways:
4910
4915
4911 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4916 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
4912 files, discarding any previous merge attempts. Re-merging is not
4917 files, discarding any previous merge attempts. Re-merging is not
4913 performed for files already marked as resolved. Use ``--all/-a``
4918 performed for files already marked as resolved. Use ``--all/-a``
4914 to select all unresolved files. ``--tool`` can be used to specify
4919 to select all unresolved files. ``--tool`` can be used to specify
4915 the merge tool used for the given files. It overrides the HGMERGE
4920 the merge tool used for the given files. It overrides the HGMERGE
4916 environment variable and your configuration files. Previous file
4921 environment variable and your configuration files. Previous file
4917 contents are saved with a ``.orig`` suffix.
4922 contents are saved with a ``.orig`` suffix.
4918
4923
4919 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4924 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
4920 (e.g. after having manually fixed-up the files). The default is
4925 (e.g. after having manually fixed-up the files). The default is
4921 to mark all unresolved files.
4926 to mark all unresolved files.
4922
4927
4923 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4928 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
4924 default is to mark all resolved files.
4929 default is to mark all resolved files.
4925
4930
4926 - :hg:`resolve -l`: list files which had or still have conflicts.
4931 - :hg:`resolve -l`: list files which had or still have conflicts.
4927 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4932 In the printed list, ``U`` = unresolved and ``R`` = resolved.
4928
4933
4929 Note that Mercurial will not let you commit files with unresolved
4934 Note that Mercurial will not let you commit files with unresolved
4930 merge conflicts. You must use :hg:`resolve -m ...` before you can
4935 merge conflicts. You must use :hg:`resolve -m ...` before you can
4931 commit after a conflicting merge.
4936 commit after a conflicting merge.
4932
4937
4933 Returns 0 on success, 1 if any files fail a resolve attempt.
4938 Returns 0 on success, 1 if any files fail a resolve attempt.
4934 """
4939 """
4935
4940
4936 all, mark, unmark, show, nostatus = \
4941 all, mark, unmark, show, nostatus = \
4937 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4942 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
4938
4943
4939 if (show and (mark or unmark)) or (mark and unmark):
4944 if (show and (mark or unmark)) or (mark and unmark):
4940 raise util.Abort(_("too many options specified"))
4945 raise util.Abort(_("too many options specified"))
4941 if pats and all:
4946 if pats and all:
4942 raise util.Abort(_("can't specify --all and patterns"))
4947 raise util.Abort(_("can't specify --all and patterns"))
4943 if not (all or pats or show or mark or unmark):
4948 if not (all or pats or show or mark or unmark):
4944 raise util.Abort(_('no files or directories specified; '
4949 raise util.Abort(_('no files or directories specified; '
4945 'use --all to remerge all files'))
4950 'use --all to remerge all files'))
4946
4951
4947 ms = mergemod.mergestate(repo)
4952 ms = mergemod.mergestate(repo)
4948 m = scmutil.match(repo[None], pats, opts)
4953 m = scmutil.match(repo[None], pats, opts)
4949 ret = 0
4954 ret = 0
4950
4955
4951 for f in ms:
4956 for f in ms:
4952 if m(f):
4957 if m(f):
4953 if show:
4958 if show:
4954 if nostatus:
4959 if nostatus:
4955 ui.write("%s\n" % f)
4960 ui.write("%s\n" % f)
4956 else:
4961 else:
4957 ui.write("%s %s\n" % (ms[f].upper(), f),
4962 ui.write("%s %s\n" % (ms[f].upper(), f),
4958 label='resolve.' +
4963 label='resolve.' +
4959 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4964 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
4960 elif mark:
4965 elif mark:
4961 ms.mark(f, "r")
4966 ms.mark(f, "r")
4962 elif unmark:
4967 elif unmark:
4963 ms.mark(f, "u")
4968 ms.mark(f, "u")
4964 else:
4969 else:
4965 wctx = repo[None]
4970 wctx = repo[None]
4966 mctx = wctx.parents()[-1]
4971 mctx = wctx.parents()[-1]
4967
4972
4968 # backup pre-resolve (merge uses .orig for its own purposes)
4973 # backup pre-resolve (merge uses .orig for its own purposes)
4969 a = repo.wjoin(f)
4974 a = repo.wjoin(f)
4970 util.copyfile(a, a + ".resolve")
4975 util.copyfile(a, a + ".resolve")
4971
4976
4972 try:
4977 try:
4973 # resolve file
4978 # resolve file
4974 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4979 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
4975 if ms.resolve(f, wctx, mctx):
4980 if ms.resolve(f, wctx, mctx):
4976 ret = 1
4981 ret = 1
4977 finally:
4982 finally:
4978 ui.setconfig('ui', 'forcemerge', '')
4983 ui.setconfig('ui', 'forcemerge', '')
4979 ms.commit()
4984 ms.commit()
4980
4985
4981 # replace filemerge's .orig file with our resolve file
4986 # replace filemerge's .orig file with our resolve file
4982 util.rename(a + ".resolve", a + ".orig")
4987 util.rename(a + ".resolve", a + ".orig")
4983
4988
4984 ms.commit()
4989 ms.commit()
4985 return ret
4990 return ret
4986
4991
4987 @command('revert',
4992 @command('revert',
4988 [('a', 'all', None, _('revert all changes when no arguments given')),
4993 [('a', 'all', None, _('revert all changes when no arguments given')),
4989 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4994 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
4990 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4995 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
4991 ('C', 'no-backup', None, _('do not save backup copies of files')),
4996 ('C', 'no-backup', None, _('do not save backup copies of files')),
4992 ] + walkopts + dryrunopts,
4997 ] + walkopts + dryrunopts,
4993 _('[OPTION]... [-r REV] [NAME]...'))
4998 _('[OPTION]... [-r REV] [NAME]...'))
4994 def revert(ui, repo, *pats, **opts):
4999 def revert(ui, repo, *pats, **opts):
4995 """restore files to their checkout state
5000 """restore files to their checkout state
4996
5001
4997 .. note::
5002 .. note::
4998
5003
4999 To check out earlier revisions, you should use :hg:`update REV`.
5004 To check out earlier revisions, you should use :hg:`update REV`.
5000 To cancel an uncommitted merge (and lose your changes), use
5005 To cancel an uncommitted merge (and lose your changes), use
5001 :hg:`update --clean .`.
5006 :hg:`update --clean .`.
5002
5007
5003 With no revision specified, revert the specified files or directories
5008 With no revision specified, revert the specified files or directories
5004 to the contents they had in the parent of the working directory.
5009 to the contents they had in the parent of the working directory.
5005 This restores the contents of files to an unmodified
5010 This restores the contents of files to an unmodified
5006 state and unschedules adds, removes, copies, and renames. If the
5011 state and unschedules adds, removes, copies, and renames. If the
5007 working directory has two parents, you must explicitly specify a
5012 working directory has two parents, you must explicitly specify a
5008 revision.
5013 revision.
5009
5014
5010 Using the -r/--rev or -d/--date options, revert the given files or
5015 Using the -r/--rev or -d/--date options, revert the given files or
5011 directories to their states as of a specific revision. Because
5016 directories to their states as of a specific revision. Because
5012 revert does not change the working directory parents, this will
5017 revert does not change the working directory parents, this will
5013 cause these files to appear modified. This can be helpful to "back
5018 cause these files to appear modified. This can be helpful to "back
5014 out" some or all of an earlier change. See :hg:`backout` for a
5019 out" some or all of an earlier change. See :hg:`backout` for a
5015 related method.
5020 related method.
5016
5021
5017 Modified files are saved with a .orig suffix before reverting.
5022 Modified files are saved with a .orig suffix before reverting.
5018 To disable these backups, use --no-backup.
5023 To disable these backups, use --no-backup.
5019
5024
5020 See :hg:`help dates` for a list of formats valid for -d/--date.
5025 See :hg:`help dates` for a list of formats valid for -d/--date.
5021
5026
5022 Returns 0 on success.
5027 Returns 0 on success.
5023 """
5028 """
5024
5029
5025 if opts.get("date"):
5030 if opts.get("date"):
5026 if opts.get("rev"):
5031 if opts.get("rev"):
5027 raise util.Abort(_("you can't specify a revision and a date"))
5032 raise util.Abort(_("you can't specify a revision and a date"))
5028 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5033 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5029
5034
5030 parent, p2 = repo.dirstate.parents()
5035 parent, p2 = repo.dirstate.parents()
5031 if not opts.get('rev') and p2 != nullid:
5036 if not opts.get('rev') and p2 != nullid:
5032 # revert after merge is a trap for new users (issue2915)
5037 # revert after merge is a trap for new users (issue2915)
5033 raise util.Abort(_('uncommitted merge with no revision specified'),
5038 raise util.Abort(_('uncommitted merge with no revision specified'),
5034 hint=_('use "hg update" or see "hg help revert"'))
5039 hint=_('use "hg update" or see "hg help revert"'))
5035
5040
5036 ctx = scmutil.revsingle(repo, opts.get('rev'))
5041 ctx = scmutil.revsingle(repo, opts.get('rev'))
5037
5042
5038 if not pats and not opts.get('all'):
5043 if not pats and not opts.get('all'):
5039 msg = _("no files or directories specified")
5044 msg = _("no files or directories specified")
5040 if p2 != nullid:
5045 if p2 != nullid:
5041 hint = _("uncommitted merge, use --all to discard all changes,"
5046 hint = _("uncommitted merge, use --all to discard all changes,"
5042 " or 'hg update -C .' to abort the merge")
5047 " or 'hg update -C .' to abort the merge")
5043 raise util.Abort(msg, hint=hint)
5048 raise util.Abort(msg, hint=hint)
5044 dirty = util.any(repo.status())
5049 dirty = util.any(repo.status())
5045 node = ctx.node()
5050 node = ctx.node()
5046 if node != parent:
5051 if node != parent:
5047 if dirty:
5052 if dirty:
5048 hint = _("uncommitted changes, use --all to discard all"
5053 hint = _("uncommitted changes, use --all to discard all"
5049 " changes, or 'hg update %s' to update") % ctx.rev()
5054 " changes, or 'hg update %s' to update") % ctx.rev()
5050 else:
5055 else:
5051 hint = _("use --all to revert all files,"
5056 hint = _("use --all to revert all files,"
5052 " or 'hg update %s' to update") % ctx.rev()
5057 " or 'hg update %s' to update") % ctx.rev()
5053 elif dirty:
5058 elif dirty:
5054 hint = _("uncommitted changes, use --all to discard all changes")
5059 hint = _("uncommitted changes, use --all to discard all changes")
5055 else:
5060 else:
5056 hint = _("use --all to revert all files")
5061 hint = _("use --all to revert all files")
5057 raise util.Abort(msg, hint=hint)
5062 raise util.Abort(msg, hint=hint)
5058
5063
5059 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5064 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5060
5065
5061 @command('rollback', dryrunopts +
5066 @command('rollback', dryrunopts +
5062 [('f', 'force', False, _('ignore safety measures'))])
5067 [('f', 'force', False, _('ignore safety measures'))])
5063 def rollback(ui, repo, **opts):
5068 def rollback(ui, repo, **opts):
5064 """roll back the last transaction (dangerous)
5069 """roll back the last transaction (dangerous)
5065
5070
5066 This command should be used with care. There is only one level of
5071 This command should be used with care. There is only one level of
5067 rollback, and there is no way to undo a rollback. It will also
5072 rollback, and there is no way to undo a rollback. It will also
5068 restore the dirstate at the time of the last transaction, losing
5073 restore the dirstate at the time of the last transaction, losing
5069 any dirstate changes since that time. This command does not alter
5074 any dirstate changes since that time. This command does not alter
5070 the working directory.
5075 the working directory.
5071
5076
5072 Transactions are used to encapsulate the effects of all commands
5077 Transactions are used to encapsulate the effects of all commands
5073 that create new changesets or propagate existing changesets into a
5078 that create new changesets or propagate existing changesets into a
5074 repository.
5079 repository.
5075
5080
5076 .. container:: verbose
5081 .. container:: verbose
5077
5082
5078 For example, the following commands are transactional, and their
5083 For example, the following commands are transactional, and their
5079 effects can be rolled back:
5084 effects can be rolled back:
5080
5085
5081 - commit
5086 - commit
5082 - import
5087 - import
5083 - pull
5088 - pull
5084 - push (with this repository as the destination)
5089 - push (with this repository as the destination)
5085 - unbundle
5090 - unbundle
5086
5091
5087 To avoid permanent data loss, rollback will refuse to rollback a
5092 To avoid permanent data loss, rollback will refuse to rollback a
5088 commit transaction if it isn't checked out. Use --force to
5093 commit transaction if it isn't checked out. Use --force to
5089 override this protection.
5094 override this protection.
5090
5095
5091 This command is not intended for use on public repositories. Once
5096 This command is not intended for use on public repositories. Once
5092 changes are visible for pull by other users, rolling a transaction
5097 changes are visible for pull by other users, rolling a transaction
5093 back locally is ineffective (someone else may already have pulled
5098 back locally is ineffective (someone else may already have pulled
5094 the changes). Furthermore, a race is possible with readers of the
5099 the changes). Furthermore, a race is possible with readers of the
5095 repository; for example an in-progress pull from the repository
5100 repository; for example an in-progress pull from the repository
5096 may fail if a rollback is performed.
5101 may fail if a rollback is performed.
5097
5102
5098 Returns 0 on success, 1 if no rollback data is available.
5103 Returns 0 on success, 1 if no rollback data is available.
5099 """
5104 """
5100 return repo.rollback(dryrun=opts.get('dry_run'),
5105 return repo.rollback(dryrun=opts.get('dry_run'),
5101 force=opts.get('force'))
5106 force=opts.get('force'))
5102
5107
5103 @command('root', [])
5108 @command('root', [])
5104 def root(ui, repo):
5109 def root(ui, repo):
5105 """print the root (top) of the current working directory
5110 """print the root (top) of the current working directory
5106
5111
5107 Print the root directory of the current repository.
5112 Print the root directory of the current repository.
5108
5113
5109 Returns 0 on success.
5114 Returns 0 on success.
5110 """
5115 """
5111 ui.write(repo.root + "\n")
5116 ui.write(repo.root + "\n")
5112
5117
5113 @command('^serve',
5118 @command('^serve',
5114 [('A', 'accesslog', '', _('name of access log file to write to'),
5119 [('A', 'accesslog', '', _('name of access log file to write to'),
5115 _('FILE')),
5120 _('FILE')),
5116 ('d', 'daemon', None, _('run server in background')),
5121 ('d', 'daemon', None, _('run server in background')),
5117 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5122 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('NUM')),
5118 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5123 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5119 # use string type, then we can check if something was passed
5124 # use string type, then we can check if something was passed
5120 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5125 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5121 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5126 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5122 _('ADDR')),
5127 _('ADDR')),
5123 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5128 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5124 _('PREFIX')),
5129 _('PREFIX')),
5125 ('n', 'name', '',
5130 ('n', 'name', '',
5126 _('name to show in web pages (default: working directory)'), _('NAME')),
5131 _('name to show in web pages (default: working directory)'), _('NAME')),
5127 ('', 'web-conf', '',
5132 ('', 'web-conf', '',
5128 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5133 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5129 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5134 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5130 _('FILE')),
5135 _('FILE')),
5131 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5136 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5132 ('', 'stdio', None, _('for remote clients')),
5137 ('', 'stdio', None, _('for remote clients')),
5133 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5138 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5134 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5139 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5135 ('', 'style', '', _('template style to use'), _('STYLE')),
5140 ('', 'style', '', _('template style to use'), _('STYLE')),
5136 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5141 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5137 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5142 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5138 _('[OPTION]...'))
5143 _('[OPTION]...'))
5139 def serve(ui, repo, **opts):
5144 def serve(ui, repo, **opts):
5140 """start stand-alone webserver
5145 """start stand-alone webserver
5141
5146
5142 Start a local HTTP repository browser and pull server. You can use
5147 Start a local HTTP repository browser and pull server. You can use
5143 this for ad-hoc sharing and browsing of repositories. It is
5148 this for ad-hoc sharing and browsing of repositories. It is
5144 recommended to use a real web server to serve a repository for
5149 recommended to use a real web server to serve a repository for
5145 longer periods of time.
5150 longer periods of time.
5146
5151
5147 Please note that the server does not implement access control.
5152 Please note that the server does not implement access control.
5148 This means that, by default, anybody can read from the server and
5153 This means that, by default, anybody can read from the server and
5149 nobody can write to it by default. Set the ``web.allow_push``
5154 nobody can write to it by default. Set the ``web.allow_push``
5150 option to ``*`` to allow everybody to push to the server. You
5155 option to ``*`` to allow everybody to push to the server. You
5151 should use a real web server if you need to authenticate users.
5156 should use a real web server if you need to authenticate users.
5152
5157
5153 By default, the server logs accesses to stdout and errors to
5158 By default, the server logs accesses to stdout and errors to
5154 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5159 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5155 files.
5160 files.
5156
5161
5157 To have the server choose a free port number to listen on, specify
5162 To have the server choose a free port number to listen on, specify
5158 a port number of 0; in this case, the server will print the port
5163 a port number of 0; in this case, the server will print the port
5159 number it uses.
5164 number it uses.
5160
5165
5161 Returns 0 on success.
5166 Returns 0 on success.
5162 """
5167 """
5163
5168
5164 if opts["stdio"] and opts["cmdserver"]:
5169 if opts["stdio"] and opts["cmdserver"]:
5165 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5170 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5166
5171
5167 def checkrepo():
5172 def checkrepo():
5168 if repo is None:
5173 if repo is None:
5169 raise error.RepoError(_("there is no Mercurial repository here"
5174 raise error.RepoError(_("there is no Mercurial repository here"
5170 " (.hg not found)"))
5175 " (.hg not found)"))
5171
5176
5172 if opts["stdio"]:
5177 if opts["stdio"]:
5173 checkrepo()
5178 checkrepo()
5174 s = sshserver.sshserver(ui, repo)
5179 s = sshserver.sshserver(ui, repo)
5175 s.serve_forever()
5180 s.serve_forever()
5176
5181
5177 if opts["cmdserver"]:
5182 if opts["cmdserver"]:
5178 checkrepo()
5183 checkrepo()
5179 s = commandserver.server(ui, repo, opts["cmdserver"])
5184 s = commandserver.server(ui, repo, opts["cmdserver"])
5180 return s.serve()
5185 return s.serve()
5181
5186
5182 # this way we can check if something was given in the command-line
5187 # this way we can check if something was given in the command-line
5183 if opts.get('port'):
5188 if opts.get('port'):
5184 opts['port'] = util.getport(opts.get('port'))
5189 opts['port'] = util.getport(opts.get('port'))
5185
5190
5186 baseui = repo and repo.baseui or ui
5191 baseui = repo and repo.baseui or ui
5187 optlist = ("name templates style address port prefix ipv6"
5192 optlist = ("name templates style address port prefix ipv6"
5188 " accesslog errorlog certificate encoding")
5193 " accesslog errorlog certificate encoding")
5189 for o in optlist.split():
5194 for o in optlist.split():
5190 val = opts.get(o, '')
5195 val = opts.get(o, '')
5191 if val in (None, ''): # should check against default options instead
5196 if val in (None, ''): # should check against default options instead
5192 continue
5197 continue
5193 baseui.setconfig("web", o, val)
5198 baseui.setconfig("web", o, val)
5194 if repo and repo.ui != baseui:
5199 if repo and repo.ui != baseui:
5195 repo.ui.setconfig("web", o, val)
5200 repo.ui.setconfig("web", o, val)
5196
5201
5197 o = opts.get('web_conf') or opts.get('webdir_conf')
5202 o = opts.get('web_conf') or opts.get('webdir_conf')
5198 if not o:
5203 if not o:
5199 if not repo:
5204 if not repo:
5200 raise error.RepoError(_("there is no Mercurial repository"
5205 raise error.RepoError(_("there is no Mercurial repository"
5201 " here (.hg not found)"))
5206 " here (.hg not found)"))
5202 o = repo.root
5207 o = repo.root
5203
5208
5204 app = hgweb.hgweb(o, baseui=ui)
5209 app = hgweb.hgweb(o, baseui=ui)
5205
5210
5206 class service(object):
5211 class service(object):
5207 def init(self):
5212 def init(self):
5208 util.setsignalhandler()
5213 util.setsignalhandler()
5209 self.httpd = hgweb.server.create_server(ui, app)
5214 self.httpd = hgweb.server.create_server(ui, app)
5210
5215
5211 if opts['port'] and not ui.verbose:
5216 if opts['port'] and not ui.verbose:
5212 return
5217 return
5213
5218
5214 if self.httpd.prefix:
5219 if self.httpd.prefix:
5215 prefix = self.httpd.prefix.strip('/') + '/'
5220 prefix = self.httpd.prefix.strip('/') + '/'
5216 else:
5221 else:
5217 prefix = ''
5222 prefix = ''
5218
5223
5219 port = ':%d' % self.httpd.port
5224 port = ':%d' % self.httpd.port
5220 if port == ':80':
5225 if port == ':80':
5221 port = ''
5226 port = ''
5222
5227
5223 bindaddr = self.httpd.addr
5228 bindaddr = self.httpd.addr
5224 if bindaddr == '0.0.0.0':
5229 if bindaddr == '0.0.0.0':
5225 bindaddr = '*'
5230 bindaddr = '*'
5226 elif ':' in bindaddr: # IPv6
5231 elif ':' in bindaddr: # IPv6
5227 bindaddr = '[%s]' % bindaddr
5232 bindaddr = '[%s]' % bindaddr
5228
5233
5229 fqaddr = self.httpd.fqaddr
5234 fqaddr = self.httpd.fqaddr
5230 if ':' in fqaddr:
5235 if ':' in fqaddr:
5231 fqaddr = '[%s]' % fqaddr
5236 fqaddr = '[%s]' % fqaddr
5232 if opts['port']:
5237 if opts['port']:
5233 write = ui.status
5238 write = ui.status
5234 else:
5239 else:
5235 write = ui.write
5240 write = ui.write
5236 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5241 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5237 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5242 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5238
5243
5239 def run(self):
5244 def run(self):
5240 self.httpd.serve_forever()
5245 self.httpd.serve_forever()
5241
5246
5242 service = service()
5247 service = service()
5243
5248
5244 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5249 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5245
5250
5246 @command('showconfig|debugconfig',
5251 @command('showconfig|debugconfig',
5247 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5252 [('u', 'untrusted', None, _('show untrusted configuration options'))],
5248 _('[-u] [NAME]...'))
5253 _('[-u] [NAME]...'))
5249 def showconfig(ui, repo, *values, **opts):
5254 def showconfig(ui, repo, *values, **opts):
5250 """show combined config settings from all hgrc files
5255 """show combined config settings from all hgrc files
5251
5256
5252 With no arguments, print names and values of all config items.
5257 With no arguments, print names and values of all config items.
5253
5258
5254 With one argument of the form section.name, print just the value
5259 With one argument of the form section.name, print just the value
5255 of that config item.
5260 of that config item.
5256
5261
5257 With multiple arguments, print names and values of all config
5262 With multiple arguments, print names and values of all config
5258 items with matching section names.
5263 items with matching section names.
5259
5264
5260 With --debug, the source (filename and line number) is printed
5265 With --debug, the source (filename and line number) is printed
5261 for each config item.
5266 for each config item.
5262
5267
5263 Returns 0 on success.
5268 Returns 0 on success.
5264 """
5269 """
5265
5270
5266 for f in scmutil.rcpath():
5271 for f in scmutil.rcpath():
5267 ui.debug('read config from: %s\n' % f)
5272 ui.debug('read config from: %s\n' % f)
5268 untrusted = bool(opts.get('untrusted'))
5273 untrusted = bool(opts.get('untrusted'))
5269 if values:
5274 if values:
5270 sections = [v for v in values if '.' not in v]
5275 sections = [v for v in values if '.' not in v]
5271 items = [v for v in values if '.' in v]
5276 items = [v for v in values if '.' in v]
5272 if len(items) > 1 or items and sections:
5277 if len(items) > 1 or items and sections:
5273 raise util.Abort(_('only one config item permitted'))
5278 raise util.Abort(_('only one config item permitted'))
5274 for section, name, value in ui.walkconfig(untrusted=untrusted):
5279 for section, name, value in ui.walkconfig(untrusted=untrusted):
5275 value = str(value).replace('\n', '\\n')
5280 value = str(value).replace('\n', '\\n')
5276 sectname = section + '.' + name
5281 sectname = section + '.' + name
5277 if values:
5282 if values:
5278 for v in values:
5283 for v in values:
5279 if v == section:
5284 if v == section:
5280 ui.debug('%s: ' %
5285 ui.debug('%s: ' %
5281 ui.configsource(section, name, untrusted))
5286 ui.configsource(section, name, untrusted))
5282 ui.write('%s=%s\n' % (sectname, value))
5287 ui.write('%s=%s\n' % (sectname, value))
5283 elif v == sectname:
5288 elif v == sectname:
5284 ui.debug('%s: ' %
5289 ui.debug('%s: ' %
5285 ui.configsource(section, name, untrusted))
5290 ui.configsource(section, name, untrusted))
5286 ui.write(value, '\n')
5291 ui.write(value, '\n')
5287 else:
5292 else:
5288 ui.debug('%s: ' %
5293 ui.debug('%s: ' %
5289 ui.configsource(section, name, untrusted))
5294 ui.configsource(section, name, untrusted))
5290 ui.write('%s=%s\n' % (sectname, value))
5295 ui.write('%s=%s\n' % (sectname, value))
5291
5296
5292 @command('^status|st',
5297 @command('^status|st',
5293 [('A', 'all', None, _('show status of all files')),
5298 [('A', 'all', None, _('show status of all files')),
5294 ('m', 'modified', None, _('show only modified files')),
5299 ('m', 'modified', None, _('show only modified files')),
5295 ('a', 'added', None, _('show only added files')),
5300 ('a', 'added', None, _('show only added files')),
5296 ('r', 'removed', None, _('show only removed files')),
5301 ('r', 'removed', None, _('show only removed files')),
5297 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5302 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5298 ('c', 'clean', None, _('show only files without changes')),
5303 ('c', 'clean', None, _('show only files without changes')),
5299 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5304 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5300 ('i', 'ignored', None, _('show only ignored files')),
5305 ('i', 'ignored', None, _('show only ignored files')),
5301 ('n', 'no-status', None, _('hide status prefix')),
5306 ('n', 'no-status', None, _('hide status prefix')),
5302 ('C', 'copies', None, _('show source of copied files')),
5307 ('C', 'copies', None, _('show source of copied files')),
5303 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5308 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5304 ('', 'rev', [], _('show difference from revision'), _('REV')),
5309 ('', 'rev', [], _('show difference from revision'), _('REV')),
5305 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5310 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5306 ] + walkopts + subrepoopts,
5311 ] + walkopts + subrepoopts,
5307 _('[OPTION]... [FILE]...'))
5312 _('[OPTION]... [FILE]...'))
5308 def status(ui, repo, *pats, **opts):
5313 def status(ui, repo, *pats, **opts):
5309 """show changed files in the working directory
5314 """show changed files in the working directory
5310
5315
5311 Show status of files in the repository. If names are given, only
5316 Show status of files in the repository. If names are given, only
5312 files that match are shown. Files that are clean or ignored or
5317 files that match are shown. Files that are clean or ignored or
5313 the source of a copy/move operation, are not listed unless
5318 the source of a copy/move operation, are not listed unless
5314 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5319 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5315 Unless options described with "show only ..." are given, the
5320 Unless options described with "show only ..." are given, the
5316 options -mardu are used.
5321 options -mardu are used.
5317
5322
5318 Option -q/--quiet hides untracked (unknown and ignored) files
5323 Option -q/--quiet hides untracked (unknown and ignored) files
5319 unless explicitly requested with -u/--unknown or -i/--ignored.
5324 unless explicitly requested with -u/--unknown or -i/--ignored.
5320
5325
5321 .. note::
5326 .. note::
5322 status may appear to disagree with diff if permissions have
5327 status may appear to disagree with diff if permissions have
5323 changed or a merge has occurred. The standard diff format does
5328 changed or a merge has occurred. The standard diff format does
5324 not report permission changes and diff only reports changes
5329 not report permission changes and diff only reports changes
5325 relative to one merge parent.
5330 relative to one merge parent.
5326
5331
5327 If one revision is given, it is used as the base revision.
5332 If one revision is given, it is used as the base revision.
5328 If two revisions are given, the differences between them are
5333 If two revisions are given, the differences between them are
5329 shown. The --change option can also be used as a shortcut to list
5334 shown. The --change option can also be used as a shortcut to list
5330 the changed files of a revision from its first parent.
5335 the changed files of a revision from its first parent.
5331
5336
5332 The codes used to show the status of files are::
5337 The codes used to show the status of files are::
5333
5338
5334 M = modified
5339 M = modified
5335 A = added
5340 A = added
5336 R = removed
5341 R = removed
5337 C = clean
5342 C = clean
5338 ! = missing (deleted by non-hg command, but still tracked)
5343 ! = missing (deleted by non-hg command, but still tracked)
5339 ? = not tracked
5344 ? = not tracked
5340 I = ignored
5345 I = ignored
5341 = origin of the previous file listed as A (added)
5346 = origin of the previous file listed as A (added)
5342
5347
5343 .. container:: verbose
5348 .. container:: verbose
5344
5349
5345 Examples:
5350 Examples:
5346
5351
5347 - show changes in the working directory relative to a
5352 - show changes in the working directory relative to a
5348 changeset::
5353 changeset::
5349
5354
5350 hg status --rev 9353
5355 hg status --rev 9353
5351
5356
5352 - show all changes including copies in an existing changeset::
5357 - show all changes including copies in an existing changeset::
5353
5358
5354 hg status --copies --change 9353
5359 hg status --copies --change 9353
5355
5360
5356 - get a NUL separated list of added files, suitable for xargs::
5361 - get a NUL separated list of added files, suitable for xargs::
5357
5362
5358 hg status -an0
5363 hg status -an0
5359
5364
5360 Returns 0 on success.
5365 Returns 0 on success.
5361 """
5366 """
5362
5367
5363 revs = opts.get('rev')
5368 revs = opts.get('rev')
5364 change = opts.get('change')
5369 change = opts.get('change')
5365
5370
5366 if revs and change:
5371 if revs and change:
5367 msg = _('cannot specify --rev and --change at the same time')
5372 msg = _('cannot specify --rev and --change at the same time')
5368 raise util.Abort(msg)
5373 raise util.Abort(msg)
5369 elif change:
5374 elif change:
5370 node2 = scmutil.revsingle(repo, change, None).node()
5375 node2 = scmutil.revsingle(repo, change, None).node()
5371 node1 = repo[node2].p1().node()
5376 node1 = repo[node2].p1().node()
5372 else:
5377 else:
5373 node1, node2 = scmutil.revpair(repo, revs)
5378 node1, node2 = scmutil.revpair(repo, revs)
5374
5379
5375 cwd = (pats and repo.getcwd()) or ''
5380 cwd = (pats and repo.getcwd()) or ''
5376 end = opts.get('print0') and '\0' or '\n'
5381 end = opts.get('print0') and '\0' or '\n'
5377 copy = {}
5382 copy = {}
5378 states = 'modified added removed deleted unknown ignored clean'.split()
5383 states = 'modified added removed deleted unknown ignored clean'.split()
5379 show = [k for k in states if opts.get(k)]
5384 show = [k for k in states if opts.get(k)]
5380 if opts.get('all'):
5385 if opts.get('all'):
5381 show += ui.quiet and (states[:4] + ['clean']) or states
5386 show += ui.quiet and (states[:4] + ['clean']) or states
5382 if not show:
5387 if not show:
5383 show = ui.quiet and states[:4] or states[:5]
5388 show = ui.quiet and states[:4] or states[:5]
5384
5389
5385 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5390 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5386 'ignored' in show, 'clean' in show, 'unknown' in show,
5391 'ignored' in show, 'clean' in show, 'unknown' in show,
5387 opts.get('subrepos'))
5392 opts.get('subrepos'))
5388 changestates = zip(states, 'MAR!?IC', stat)
5393 changestates = zip(states, 'MAR!?IC', stat)
5389
5394
5390 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5395 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5391 copy = copies.pathcopies(repo[node1], repo[node2])
5396 copy = copies.pathcopies(repo[node1], repo[node2])
5392
5397
5393 fm = ui.formatter('status', opts)
5398 fm = ui.formatter('status', opts)
5394 format = '%s %s' + end
5399 format = '%s %s' + end
5395 if opts.get('no_status'):
5400 if opts.get('no_status'):
5396 format = '%.0s%s' + end
5401 format = '%.0s%s' + end
5397
5402
5398 for state, char, files in changestates:
5403 for state, char, files in changestates:
5399 if state in show:
5404 if state in show:
5400 label = 'status.' + state
5405 label = 'status.' + state
5401 for f in files:
5406 for f in files:
5402 fm.startitem()
5407 fm.startitem()
5403 fm.write("status path", format, char,
5408 fm.write("status path", format, char,
5404 repo.pathto(f, cwd), label=label)
5409 repo.pathto(f, cwd), label=label)
5405 if f in copy:
5410 if f in copy:
5406 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5411 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5407 label='status.copied')
5412 label='status.copied')
5408 fm.end()
5413 fm.end()
5409
5414
5410 @command('^summary|sum',
5415 @command('^summary|sum',
5411 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5416 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5412 def summary(ui, repo, **opts):
5417 def summary(ui, repo, **opts):
5413 """summarize working directory state
5418 """summarize working directory state
5414
5419
5415 This generates a brief summary of the working directory state,
5420 This generates a brief summary of the working directory state,
5416 including parents, branch, commit status, and available updates.
5421 including parents, branch, commit status, and available updates.
5417
5422
5418 With the --remote option, this will check the default paths for
5423 With the --remote option, this will check the default paths for
5419 incoming and outgoing changes. This can be time-consuming.
5424 incoming and outgoing changes. This can be time-consuming.
5420
5425
5421 Returns 0 on success.
5426 Returns 0 on success.
5422 """
5427 """
5423
5428
5424 ctx = repo[None]
5429 ctx = repo[None]
5425 parents = ctx.parents()
5430 parents = ctx.parents()
5426 pnode = parents[0].node()
5431 pnode = parents[0].node()
5427 marks = []
5432 marks = []
5428
5433
5429 for p in parents:
5434 for p in parents:
5430 # label with log.changeset (instead of log.parent) since this
5435 # label with log.changeset (instead of log.parent) since this
5431 # shows a working directory parent *changeset*:
5436 # shows a working directory parent *changeset*:
5432 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5437 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5433 label='log.changeset changeset.%s' % p.phasestr())
5438 label='log.changeset changeset.%s' % p.phasestr())
5434 ui.write(' '.join(p.tags()), label='log.tag')
5439 ui.write(' '.join(p.tags()), label='log.tag')
5435 if p.bookmarks():
5440 if p.bookmarks():
5436 marks.extend(p.bookmarks())
5441 marks.extend(p.bookmarks())
5437 if p.rev() == -1:
5442 if p.rev() == -1:
5438 if not len(repo):
5443 if not len(repo):
5439 ui.write(_(' (empty repository)'))
5444 ui.write(_(' (empty repository)'))
5440 else:
5445 else:
5441 ui.write(_(' (no revision checked out)'))
5446 ui.write(_(' (no revision checked out)'))
5442 ui.write('\n')
5447 ui.write('\n')
5443 if p.description():
5448 if p.description():
5444 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5449 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5445 label='log.summary')
5450 label='log.summary')
5446
5451
5447 branch = ctx.branch()
5452 branch = ctx.branch()
5448 bheads = repo.branchheads(branch)
5453 bheads = repo.branchheads(branch)
5449 m = _('branch: %s\n') % branch
5454 m = _('branch: %s\n') % branch
5450 if branch != 'default':
5455 if branch != 'default':
5451 ui.write(m, label='log.branch')
5456 ui.write(m, label='log.branch')
5452 else:
5457 else:
5453 ui.status(m, label='log.branch')
5458 ui.status(m, label='log.branch')
5454
5459
5455 if marks:
5460 if marks:
5456 current = repo._bookmarkcurrent
5461 current = repo._bookmarkcurrent
5457 ui.write(_('bookmarks:'), label='log.bookmark')
5462 ui.write(_('bookmarks:'), label='log.bookmark')
5458 if current is not None:
5463 if current is not None:
5459 try:
5464 try:
5460 marks.remove(current)
5465 marks.remove(current)
5461 ui.write(' *' + current, label='bookmarks.current')
5466 ui.write(' *' + current, label='bookmarks.current')
5462 except ValueError:
5467 except ValueError:
5463 # current bookmark not in parent ctx marks
5468 # current bookmark not in parent ctx marks
5464 pass
5469 pass
5465 for m in marks:
5470 for m in marks:
5466 ui.write(' ' + m, label='log.bookmark')
5471 ui.write(' ' + m, label='log.bookmark')
5467 ui.write('\n', label='log.bookmark')
5472 ui.write('\n', label='log.bookmark')
5468
5473
5469 st = list(repo.status(unknown=True))[:6]
5474 st = list(repo.status(unknown=True))[:6]
5470
5475
5471 c = repo.dirstate.copies()
5476 c = repo.dirstate.copies()
5472 copied, renamed = [], []
5477 copied, renamed = [], []
5473 for d, s in c.iteritems():
5478 for d, s in c.iteritems():
5474 if s in st[2]:
5479 if s in st[2]:
5475 st[2].remove(s)
5480 st[2].remove(s)
5476 renamed.append(d)
5481 renamed.append(d)
5477 else:
5482 else:
5478 copied.append(d)
5483 copied.append(d)
5479 if d in st[1]:
5484 if d in st[1]:
5480 st[1].remove(d)
5485 st[1].remove(d)
5481 st.insert(3, renamed)
5486 st.insert(3, renamed)
5482 st.insert(4, copied)
5487 st.insert(4, copied)
5483
5488
5484 ms = mergemod.mergestate(repo)
5489 ms = mergemod.mergestate(repo)
5485 st.append([f for f in ms if ms[f] == 'u'])
5490 st.append([f for f in ms if ms[f] == 'u'])
5486
5491
5487 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5492 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5488 st.append(subs)
5493 st.append(subs)
5489
5494
5490 labels = [ui.label(_('%d modified'), 'status.modified'),
5495 labels = [ui.label(_('%d modified'), 'status.modified'),
5491 ui.label(_('%d added'), 'status.added'),
5496 ui.label(_('%d added'), 'status.added'),
5492 ui.label(_('%d removed'), 'status.removed'),
5497 ui.label(_('%d removed'), 'status.removed'),
5493 ui.label(_('%d renamed'), 'status.copied'),
5498 ui.label(_('%d renamed'), 'status.copied'),
5494 ui.label(_('%d copied'), 'status.copied'),
5499 ui.label(_('%d copied'), 'status.copied'),
5495 ui.label(_('%d deleted'), 'status.deleted'),
5500 ui.label(_('%d deleted'), 'status.deleted'),
5496 ui.label(_('%d unknown'), 'status.unknown'),
5501 ui.label(_('%d unknown'), 'status.unknown'),
5497 ui.label(_('%d ignored'), 'status.ignored'),
5502 ui.label(_('%d ignored'), 'status.ignored'),
5498 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5503 ui.label(_('%d unresolved'), 'resolve.unresolved'),
5499 ui.label(_('%d subrepos'), 'status.modified')]
5504 ui.label(_('%d subrepos'), 'status.modified')]
5500 t = []
5505 t = []
5501 for s, l in zip(st, labels):
5506 for s, l in zip(st, labels):
5502 if s:
5507 if s:
5503 t.append(l % len(s))
5508 t.append(l % len(s))
5504
5509
5505 t = ', '.join(t)
5510 t = ', '.join(t)
5506 cleanworkdir = False
5511 cleanworkdir = False
5507
5512
5508 if len(parents) > 1:
5513 if len(parents) > 1:
5509 t += _(' (merge)')
5514 t += _(' (merge)')
5510 elif branch != parents[0].branch():
5515 elif branch != parents[0].branch():
5511 t += _(' (new branch)')
5516 t += _(' (new branch)')
5512 elif (parents[0].closesbranch() and
5517 elif (parents[0].closesbranch() and
5513 pnode in repo.branchheads(branch, closed=True)):
5518 pnode in repo.branchheads(branch, closed=True)):
5514 t += _(' (head closed)')
5519 t += _(' (head closed)')
5515 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5520 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
5516 t += _(' (clean)')
5521 t += _(' (clean)')
5517 cleanworkdir = True
5522 cleanworkdir = True
5518 elif pnode not in bheads:
5523 elif pnode not in bheads:
5519 t += _(' (new branch head)')
5524 t += _(' (new branch head)')
5520
5525
5521 if cleanworkdir:
5526 if cleanworkdir:
5522 ui.status(_('commit: %s\n') % t.strip())
5527 ui.status(_('commit: %s\n') % t.strip())
5523 else:
5528 else:
5524 ui.write(_('commit: %s\n') % t.strip())
5529 ui.write(_('commit: %s\n') % t.strip())
5525
5530
5526 # all ancestors of branch heads - all ancestors of parent = new csets
5531 # all ancestors of branch heads - all ancestors of parent = new csets
5527 new = [0] * len(repo)
5532 new = [0] * len(repo)
5528 cl = repo.changelog
5533 cl = repo.changelog
5529 for a in [cl.rev(n) for n in bheads]:
5534 for a in [cl.rev(n) for n in bheads]:
5530 new[a] = 1
5535 new[a] = 1
5531 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5536 for a in cl.ancestors([cl.rev(n) for n in bheads]):
5532 new[a] = 1
5537 new[a] = 1
5533 for a in [p.rev() for p in parents]:
5538 for a in [p.rev() for p in parents]:
5534 if a >= 0:
5539 if a >= 0:
5535 new[a] = 0
5540 new[a] = 0
5536 for a in cl.ancestors([p.rev() for p in parents]):
5541 for a in cl.ancestors([p.rev() for p in parents]):
5537 new[a] = 0
5542 new[a] = 0
5538 new = sum(new)
5543 new = sum(new)
5539
5544
5540 if new == 0:
5545 if new == 0:
5541 ui.status(_('update: (current)\n'))
5546 ui.status(_('update: (current)\n'))
5542 elif pnode not in bheads:
5547 elif pnode not in bheads:
5543 ui.write(_('update: %d new changesets (update)\n') % new)
5548 ui.write(_('update: %d new changesets (update)\n') % new)
5544 else:
5549 else:
5545 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5550 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5546 (new, len(bheads)))
5551 (new, len(bheads)))
5547
5552
5548 if opts.get('remote'):
5553 if opts.get('remote'):
5549 t = []
5554 t = []
5550 source, branches = hg.parseurl(ui.expandpath('default'))
5555 source, branches = hg.parseurl(ui.expandpath('default'))
5551 other = hg.peer(repo, {}, source)
5556 other = hg.peer(repo, {}, source)
5552 revs, checkout = hg.addbranchrevs(repo, other, branches,
5557 revs, checkout = hg.addbranchrevs(repo, other, branches,
5553 opts.get('rev'))
5558 opts.get('rev'))
5554 ui.debug('comparing with %s\n' % util.hidepassword(source))
5559 ui.debug('comparing with %s\n' % util.hidepassword(source))
5555 repo.ui.pushbuffer()
5560 repo.ui.pushbuffer()
5556 commoninc = discovery.findcommonincoming(repo, other)
5561 commoninc = discovery.findcommonincoming(repo, other)
5557 _common, incoming, _rheads = commoninc
5562 _common, incoming, _rheads = commoninc
5558 repo.ui.popbuffer()
5563 repo.ui.popbuffer()
5559 if incoming:
5564 if incoming:
5560 t.append(_('1 or more incoming'))
5565 t.append(_('1 or more incoming'))
5561
5566
5562 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5567 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5563 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5568 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5564 if source != dest:
5569 if source != dest:
5565 other = hg.peer(repo, {}, dest)
5570 other = hg.peer(repo, {}, dest)
5566 commoninc = None
5571 commoninc = None
5567 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5572 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5568 repo.ui.pushbuffer()
5573 repo.ui.pushbuffer()
5569 outgoing = discovery.findcommonoutgoing(repo, other,
5574 outgoing = discovery.findcommonoutgoing(repo, other,
5570 commoninc=commoninc)
5575 commoninc=commoninc)
5571 repo.ui.popbuffer()
5576 repo.ui.popbuffer()
5572 o = outgoing.missing
5577 o = outgoing.missing
5573 if o:
5578 if o:
5574 t.append(_('%d outgoing') % len(o))
5579 t.append(_('%d outgoing') % len(o))
5575 if 'bookmarks' in other.listkeys('namespaces'):
5580 if 'bookmarks' in other.listkeys('namespaces'):
5576 lmarks = repo.listkeys('bookmarks')
5581 lmarks = repo.listkeys('bookmarks')
5577 rmarks = other.listkeys('bookmarks')
5582 rmarks = other.listkeys('bookmarks')
5578 diff = set(rmarks) - set(lmarks)
5583 diff = set(rmarks) - set(lmarks)
5579 if len(diff) > 0:
5584 if len(diff) > 0:
5580 t.append(_('%d incoming bookmarks') % len(diff))
5585 t.append(_('%d incoming bookmarks') % len(diff))
5581 diff = set(lmarks) - set(rmarks)
5586 diff = set(lmarks) - set(rmarks)
5582 if len(diff) > 0:
5587 if len(diff) > 0:
5583 t.append(_('%d outgoing bookmarks') % len(diff))
5588 t.append(_('%d outgoing bookmarks') % len(diff))
5584
5589
5585 if t:
5590 if t:
5586 ui.write(_('remote: %s\n') % (', '.join(t)))
5591 ui.write(_('remote: %s\n') % (', '.join(t)))
5587 else:
5592 else:
5588 ui.status(_('remote: (synced)\n'))
5593 ui.status(_('remote: (synced)\n'))
5589
5594
5590 @command('tag',
5595 @command('tag',
5591 [('f', 'force', None, _('force tag')),
5596 [('f', 'force', None, _('force tag')),
5592 ('l', 'local', None, _('make the tag local')),
5597 ('l', 'local', None, _('make the tag local')),
5593 ('r', 'rev', '', _('revision to tag'), _('REV')),
5598 ('r', 'rev', '', _('revision to tag'), _('REV')),
5594 ('', 'remove', None, _('remove a tag')),
5599 ('', 'remove', None, _('remove a tag')),
5595 # -l/--local is already there, commitopts cannot be used
5600 # -l/--local is already there, commitopts cannot be used
5596 ('e', 'edit', None, _('edit commit message')),
5601 ('e', 'edit', None, _('edit commit message')),
5597 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5602 ('m', 'message', '', _('use <text> as commit message'), _('TEXT')),
5598 ] + commitopts2,
5603 ] + commitopts2,
5599 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5604 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5600 def tag(ui, repo, name1, *names, **opts):
5605 def tag(ui, repo, name1, *names, **opts):
5601 """add one or more tags for the current or given revision
5606 """add one or more tags for the current or given revision
5602
5607
5603 Name a particular revision using <name>.
5608 Name a particular revision using <name>.
5604
5609
5605 Tags are used to name particular revisions of the repository and are
5610 Tags are used to name particular revisions of the repository and are
5606 very useful to compare different revisions, to go back to significant
5611 very useful to compare different revisions, to go back to significant
5607 earlier versions or to mark branch points as releases, etc. Changing
5612 earlier versions or to mark branch points as releases, etc. Changing
5608 an existing tag is normally disallowed; use -f/--force to override.
5613 an existing tag is normally disallowed; use -f/--force to override.
5609
5614
5610 If no revision is given, the parent of the working directory is
5615 If no revision is given, the parent of the working directory is
5611 used, or tip if no revision is checked out.
5616 used, or tip if no revision is checked out.
5612
5617
5613 To facilitate version control, distribution, and merging of tags,
5618 To facilitate version control, distribution, and merging of tags,
5614 they are stored as a file named ".hgtags" which is managed similarly
5619 they are stored as a file named ".hgtags" which is managed similarly
5615 to other project files and can be hand-edited if necessary. This
5620 to other project files and can be hand-edited if necessary. This
5616 also means that tagging creates a new commit. The file
5621 also means that tagging creates a new commit. The file
5617 ".hg/localtags" is used for local tags (not shared among
5622 ".hg/localtags" is used for local tags (not shared among
5618 repositories).
5623 repositories).
5619
5624
5620 Tag commits are usually made at the head of a branch. If the parent
5625 Tag commits are usually made at the head of a branch. If the parent
5621 of the working directory is not a branch head, :hg:`tag` aborts; use
5626 of the working directory is not a branch head, :hg:`tag` aborts; use
5622 -f/--force to force the tag commit to be based on a non-head
5627 -f/--force to force the tag commit to be based on a non-head
5623 changeset.
5628 changeset.
5624
5629
5625 See :hg:`help dates` for a list of formats valid for -d/--date.
5630 See :hg:`help dates` for a list of formats valid for -d/--date.
5626
5631
5627 Since tag names have priority over branch names during revision
5632 Since tag names have priority over branch names during revision
5628 lookup, using an existing branch name as a tag name is discouraged.
5633 lookup, using an existing branch name as a tag name is discouraged.
5629
5634
5630 Returns 0 on success.
5635 Returns 0 on success.
5631 """
5636 """
5632 wlock = lock = None
5637 wlock = lock = None
5633 try:
5638 try:
5634 wlock = repo.wlock()
5639 wlock = repo.wlock()
5635 lock = repo.lock()
5640 lock = repo.lock()
5636 rev_ = "."
5641 rev_ = "."
5637 names = [t.strip() for t in (name1,) + names]
5642 names = [t.strip() for t in (name1,) + names]
5638 if len(names) != len(set(names)):
5643 if len(names) != len(set(names)):
5639 raise util.Abort(_('tag names must be unique'))
5644 raise util.Abort(_('tag names must be unique'))
5640 for n in names:
5645 for n in names:
5641 if n in ['tip', '.', 'null']:
5646 if n in ['tip', '.', 'null']:
5642 raise util.Abort(_("the name '%s' is reserved") % n)
5647 raise util.Abort(_("the name '%s' is reserved") % n)
5643 if not n:
5648 if not n:
5644 raise util.Abort(_('tag names cannot consist entirely of '
5649 raise util.Abort(_('tag names cannot consist entirely of '
5645 'whitespace'))
5650 'whitespace'))
5646 if opts.get('rev') and opts.get('remove'):
5651 if opts.get('rev') and opts.get('remove'):
5647 raise util.Abort(_("--rev and --remove are incompatible"))
5652 raise util.Abort(_("--rev and --remove are incompatible"))
5648 if opts.get('rev'):
5653 if opts.get('rev'):
5649 rev_ = opts['rev']
5654 rev_ = opts['rev']
5650 message = opts.get('message')
5655 message = opts.get('message')
5651 if opts.get('remove'):
5656 if opts.get('remove'):
5652 expectedtype = opts.get('local') and 'local' or 'global'
5657 expectedtype = opts.get('local') and 'local' or 'global'
5653 for n in names:
5658 for n in names:
5654 if not repo.tagtype(n):
5659 if not repo.tagtype(n):
5655 raise util.Abort(_("tag '%s' does not exist") % n)
5660 raise util.Abort(_("tag '%s' does not exist") % n)
5656 if repo.tagtype(n) != expectedtype:
5661 if repo.tagtype(n) != expectedtype:
5657 if expectedtype == 'global':
5662 if expectedtype == 'global':
5658 raise util.Abort(_("tag '%s' is not a global tag") % n)
5663 raise util.Abort(_("tag '%s' is not a global tag") % n)
5659 else:
5664 else:
5660 raise util.Abort(_("tag '%s' is not a local tag") % n)
5665 raise util.Abort(_("tag '%s' is not a local tag") % n)
5661 rev_ = nullid
5666 rev_ = nullid
5662 if not message:
5667 if not message:
5663 # we don't translate commit messages
5668 # we don't translate commit messages
5664 message = 'Removed tag %s' % ', '.join(names)
5669 message = 'Removed tag %s' % ', '.join(names)
5665 elif not opts.get('force'):
5670 elif not opts.get('force'):
5666 for n in names:
5671 for n in names:
5667 if n in repo.tags():
5672 if n in repo.tags():
5668 raise util.Abort(_("tag '%s' already exists "
5673 raise util.Abort(_("tag '%s' already exists "
5669 "(use -f to force)") % n)
5674 "(use -f to force)") % n)
5670 if not opts.get('local'):
5675 if not opts.get('local'):
5671 p1, p2 = repo.dirstate.parents()
5676 p1, p2 = repo.dirstate.parents()
5672 if p2 != nullid:
5677 if p2 != nullid:
5673 raise util.Abort(_('uncommitted merge'))
5678 raise util.Abort(_('uncommitted merge'))
5674 bheads = repo.branchheads()
5679 bheads = repo.branchheads()
5675 if not opts.get('force') and bheads and p1 not in bheads:
5680 if not opts.get('force') and bheads and p1 not in bheads:
5676 raise util.Abort(_('not at a branch head (use -f to force)'))
5681 raise util.Abort(_('not at a branch head (use -f to force)'))
5677 r = scmutil.revsingle(repo, rev_).node()
5682 r = scmutil.revsingle(repo, rev_).node()
5678
5683
5679 if not message:
5684 if not message:
5680 # we don't translate commit messages
5685 # we don't translate commit messages
5681 message = ('Added tag %s for changeset %s' %
5686 message = ('Added tag %s for changeset %s' %
5682 (', '.join(names), short(r)))
5687 (', '.join(names), short(r)))
5683
5688
5684 date = opts.get('date')
5689 date = opts.get('date')
5685 if date:
5690 if date:
5686 date = util.parsedate(date)
5691 date = util.parsedate(date)
5687
5692
5688 if opts.get('edit'):
5693 if opts.get('edit'):
5689 message = ui.edit(message, ui.username())
5694 message = ui.edit(message, ui.username())
5690
5695
5691 # don't allow tagging the null rev
5696 # don't allow tagging the null rev
5692 if (not opts.get('remove') and
5697 if (not opts.get('remove') and
5693 scmutil.revsingle(repo, rev_).rev() == nullrev):
5698 scmutil.revsingle(repo, rev_).rev() == nullrev):
5694 raise util.Abort(_("null revision specified"))
5699 raise util.Abort(_("null revision specified"))
5695
5700
5696 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5701 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
5697 finally:
5702 finally:
5698 release(lock, wlock)
5703 release(lock, wlock)
5699
5704
5700 @command('tags', [], '')
5705 @command('tags', [], '')
5701 def tags(ui, repo):
5706 def tags(ui, repo):
5702 """list repository tags
5707 """list repository tags
5703
5708
5704 This lists both regular and local tags. When the -v/--verbose
5709 This lists both regular and local tags. When the -v/--verbose
5705 switch is used, a third column "local" is printed for local tags.
5710 switch is used, a third column "local" is printed for local tags.
5706
5711
5707 Returns 0 on success.
5712 Returns 0 on success.
5708 """
5713 """
5709
5714
5710 hexfunc = ui.debugflag and hex or short
5715 hexfunc = ui.debugflag and hex or short
5711 tagtype = ""
5716 tagtype = ""
5712
5717
5713 for t, n in reversed(repo.tagslist()):
5718 for t, n in reversed(repo.tagslist()):
5714 if ui.quiet:
5719 if ui.quiet:
5715 ui.write("%s\n" % t, label='tags.normal')
5720 ui.write("%s\n" % t, label='tags.normal')
5716 continue
5721 continue
5717
5722
5718 hn = hexfunc(n)
5723 hn = hexfunc(n)
5719 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5724 r = "%5d:%s" % (repo.changelog.rev(n), hn)
5720 rev = ui.label(r, 'log.changeset changeset.%s' % repo[n].phasestr())
5725 rev = ui.label(r, 'log.changeset changeset.%s' % repo[n].phasestr())
5721 spaces = " " * (30 - encoding.colwidth(t))
5726 spaces = " " * (30 - encoding.colwidth(t))
5722
5727
5723 tag = ui.label(t, 'tags.normal')
5728 tag = ui.label(t, 'tags.normal')
5724 if ui.verbose:
5729 if ui.verbose:
5725 if repo.tagtype(t) == 'local':
5730 if repo.tagtype(t) == 'local':
5726 tagtype = " local"
5731 tagtype = " local"
5727 tag = ui.label(t, 'tags.local')
5732 tag = ui.label(t, 'tags.local')
5728 else:
5733 else:
5729 tagtype = ""
5734 tagtype = ""
5730 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5735 ui.write("%s%s %s%s\n" % (tag, spaces, rev, tagtype))
5731
5736
5732 @command('tip',
5737 @command('tip',
5733 [('p', 'patch', None, _('show patch')),
5738 [('p', 'patch', None, _('show patch')),
5734 ('g', 'git', None, _('use git extended diff format')),
5739 ('g', 'git', None, _('use git extended diff format')),
5735 ] + templateopts,
5740 ] + templateopts,
5736 _('[-p] [-g]'))
5741 _('[-p] [-g]'))
5737 def tip(ui, repo, **opts):
5742 def tip(ui, repo, **opts):
5738 """show the tip revision
5743 """show the tip revision
5739
5744
5740 The tip revision (usually just called the tip) is the changeset
5745 The tip revision (usually just called the tip) is the changeset
5741 most recently added to the repository (and therefore the most
5746 most recently added to the repository (and therefore the most
5742 recently changed head).
5747 recently changed head).
5743
5748
5744 If you have just made a commit, that commit will be the tip. If
5749 If you have just made a commit, that commit will be the tip. If
5745 you have just pulled changes from another repository, the tip of
5750 you have just pulled changes from another repository, the tip of
5746 that repository becomes the current tip. The "tip" tag is special
5751 that repository becomes the current tip. The "tip" tag is special
5747 and cannot be renamed or assigned to a different changeset.
5752 and cannot be renamed or assigned to a different changeset.
5748
5753
5749 Returns 0 on success.
5754 Returns 0 on success.
5750 """
5755 """
5751 displayer = cmdutil.show_changeset(ui, repo, opts)
5756 displayer = cmdutil.show_changeset(ui, repo, opts)
5752 displayer.show(repo[len(repo) - 1])
5757 displayer.show(repo[len(repo) - 1])
5753 displayer.close()
5758 displayer.close()
5754
5759
5755 @command('unbundle',
5760 @command('unbundle',
5756 [('u', 'update', None,
5761 [('u', 'update', None,
5757 _('update to new branch head if changesets were unbundled'))],
5762 _('update to new branch head if changesets were unbundled'))],
5758 _('[-u] FILE...'))
5763 _('[-u] FILE...'))
5759 def unbundle(ui, repo, fname1, *fnames, **opts):
5764 def unbundle(ui, repo, fname1, *fnames, **opts):
5760 """apply one or more changegroup files
5765 """apply one or more changegroup files
5761
5766
5762 Apply one or more compressed changegroup files generated by the
5767 Apply one or more compressed changegroup files generated by the
5763 bundle command.
5768 bundle command.
5764
5769
5765 Returns 0 on success, 1 if an update has unresolved files.
5770 Returns 0 on success, 1 if an update has unresolved files.
5766 """
5771 """
5767 fnames = (fname1,) + fnames
5772 fnames = (fname1,) + fnames
5768
5773
5769 lock = repo.lock()
5774 lock = repo.lock()
5770 wc = repo['.']
5775 wc = repo['.']
5771 try:
5776 try:
5772 for fname in fnames:
5777 for fname in fnames:
5773 f = url.open(ui, fname)
5778 f = url.open(ui, fname)
5774 gen = changegroup.readbundle(f, fname)
5779 gen = changegroup.readbundle(f, fname)
5775 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5780 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
5776 finally:
5781 finally:
5777 lock.release()
5782 lock.release()
5778 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5783 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
5779 return postincoming(ui, repo, modheads, opts.get('update'), None)
5784 return postincoming(ui, repo, modheads, opts.get('update'), None)
5780
5785
5781 @command('^update|up|checkout|co',
5786 @command('^update|up|checkout|co',
5782 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5787 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
5783 ('c', 'check', None,
5788 ('c', 'check', None,
5784 _('update across branches if no uncommitted changes')),
5789 _('update across branches if no uncommitted changes')),
5785 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5790 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5786 ('r', 'rev', '', _('revision'), _('REV'))],
5791 ('r', 'rev', '', _('revision'), _('REV'))],
5787 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5792 _('[-c] [-C] [-d DATE] [[-r] REV]'))
5788 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5793 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
5789 """update working directory (or switch revisions)
5794 """update working directory (or switch revisions)
5790
5795
5791 Update the repository's working directory to the specified
5796 Update the repository's working directory to the specified
5792 changeset. If no changeset is specified, update to the tip of the
5797 changeset. If no changeset is specified, update to the tip of the
5793 current named branch and move the current bookmark (see :hg:`help
5798 current named branch and move the current bookmark (see :hg:`help
5794 bookmarks`).
5799 bookmarks`).
5795
5800
5796 Update sets the working directory's parent revision to the specified
5801 Update sets the working directory's parent revision to the specified
5797 changeset (see :hg:`help parents`).
5802 changeset (see :hg:`help parents`).
5798
5803
5799 If the changeset is not a descendant or ancestor of the working
5804 If the changeset is not a descendant or ancestor of the working
5800 directory's parent, the update is aborted. With the -c/--check
5805 directory's parent, the update is aborted. With the -c/--check
5801 option, the working directory is checked for uncommitted changes; if
5806 option, the working directory is checked for uncommitted changes; if
5802 none are found, the working directory is updated to the specified
5807 none are found, the working directory is updated to the specified
5803 changeset.
5808 changeset.
5804
5809
5805 .. container:: verbose
5810 .. container:: verbose
5806
5811
5807 The following rules apply when the working directory contains
5812 The following rules apply when the working directory contains
5808 uncommitted changes:
5813 uncommitted changes:
5809
5814
5810 1. If neither -c/--check nor -C/--clean is specified, and if
5815 1. If neither -c/--check nor -C/--clean is specified, and if
5811 the requested changeset is an ancestor or descendant of
5816 the requested changeset is an ancestor or descendant of
5812 the working directory's parent, the uncommitted changes
5817 the working directory's parent, the uncommitted changes
5813 are merged into the requested changeset and the merged
5818 are merged into the requested changeset and the merged
5814 result is left uncommitted. If the requested changeset is
5819 result is left uncommitted. If the requested changeset is
5815 not an ancestor or descendant (that is, it is on another
5820 not an ancestor or descendant (that is, it is on another
5816 branch), the update is aborted and the uncommitted changes
5821 branch), the update is aborted and the uncommitted changes
5817 are preserved.
5822 are preserved.
5818
5823
5819 2. With the -c/--check option, the update is aborted and the
5824 2. With the -c/--check option, the update is aborted and the
5820 uncommitted changes are preserved.
5825 uncommitted changes are preserved.
5821
5826
5822 3. With the -C/--clean option, uncommitted changes are discarded and
5827 3. With the -C/--clean option, uncommitted changes are discarded and
5823 the working directory is updated to the requested changeset.
5828 the working directory is updated to the requested changeset.
5824
5829
5825 To cancel an uncommitted merge (and lose your changes), use
5830 To cancel an uncommitted merge (and lose your changes), use
5826 :hg:`update --clean .`.
5831 :hg:`update --clean .`.
5827
5832
5828 Use null as the changeset to remove the working directory (like
5833 Use null as the changeset to remove the working directory (like
5829 :hg:`clone -U`).
5834 :hg:`clone -U`).
5830
5835
5831 If you want to revert just one file to an older revision, use
5836 If you want to revert just one file to an older revision, use
5832 :hg:`revert [-r REV] NAME`.
5837 :hg:`revert [-r REV] NAME`.
5833
5838
5834 See :hg:`help dates` for a list of formats valid for -d/--date.
5839 See :hg:`help dates` for a list of formats valid for -d/--date.
5835
5840
5836 Returns 0 on success, 1 if there are unresolved files.
5841 Returns 0 on success, 1 if there are unresolved files.
5837 """
5842 """
5838 if rev and node:
5843 if rev and node:
5839 raise util.Abort(_("please specify just one revision"))
5844 raise util.Abort(_("please specify just one revision"))
5840
5845
5841 if rev is None or rev == '':
5846 if rev is None or rev == '':
5842 rev = node
5847 rev = node
5843
5848
5844 # with no argument, we also move the current bookmark, if any
5849 # with no argument, we also move the current bookmark, if any
5845 movemarkfrom = None
5850 movemarkfrom = None
5846 if rev is None or node == '':
5851 if rev is None or node == '':
5847 movemarkfrom = repo['.'].node()
5852 movemarkfrom = repo['.'].node()
5848
5853
5849 # if we defined a bookmark, we have to remember the original bookmark name
5854 # if we defined a bookmark, we have to remember the original bookmark name
5850 brev = rev
5855 brev = rev
5851 rev = scmutil.revsingle(repo, rev, rev).rev()
5856 rev = scmutil.revsingle(repo, rev, rev).rev()
5852
5857
5853 if check and clean:
5858 if check and clean:
5854 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5859 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
5855
5860
5856 if date:
5861 if date:
5857 if rev is not None:
5862 if rev is not None:
5858 raise util.Abort(_("you can't specify a revision and a date"))
5863 raise util.Abort(_("you can't specify a revision and a date"))
5859 rev = cmdutil.finddate(ui, repo, date)
5864 rev = cmdutil.finddate(ui, repo, date)
5860
5865
5861 if check:
5866 if check:
5862 c = repo[None]
5867 c = repo[None]
5863 if c.dirty(merge=False, branch=False):
5868 if c.dirty(merge=False, branch=False):
5864 raise util.Abort(_("uncommitted local changes"))
5869 raise util.Abort(_("uncommitted local changes"))
5865 if rev is None:
5870 if rev is None:
5866 rev = repo[repo[None].branch()].rev()
5871 rev = repo[repo[None].branch()].rev()
5867 mergemod._checkunknown(repo, repo[None], repo[rev])
5872 mergemod._checkunknown(repo, repo[None], repo[rev])
5868
5873
5869 if clean:
5874 if clean:
5870 ret = hg.clean(repo, rev)
5875 ret = hg.clean(repo, rev)
5871 else:
5876 else:
5872 ret = hg.update(repo, rev)
5877 ret = hg.update(repo, rev)
5873
5878
5874 if not ret and movemarkfrom:
5879 if not ret and movemarkfrom:
5875 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5880 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
5876 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5881 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
5877 elif brev in repo._bookmarks:
5882 elif brev in repo._bookmarks:
5878 bookmarks.setcurrent(repo, brev)
5883 bookmarks.setcurrent(repo, brev)
5879 elif brev:
5884 elif brev:
5880 bookmarks.unsetcurrent(repo)
5885 bookmarks.unsetcurrent(repo)
5881
5886
5882 return ret
5887 return ret
5883
5888
5884 @command('verify', [])
5889 @command('verify', [])
5885 def verify(ui, repo):
5890 def verify(ui, repo):
5886 """verify the integrity of the repository
5891 """verify the integrity of the repository
5887
5892
5888 Verify the integrity of the current repository.
5893 Verify the integrity of the current repository.
5889
5894
5890 This will perform an extensive check of the repository's
5895 This will perform an extensive check of the repository's
5891 integrity, validating the hashes and checksums of each entry in
5896 integrity, validating the hashes and checksums of each entry in
5892 the changelog, manifest, and tracked files, as well as the
5897 the changelog, manifest, and tracked files, as well as the
5893 integrity of their crosslinks and indices.
5898 integrity of their crosslinks and indices.
5894
5899
5895 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5900 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
5896 for more information about recovery from corruption of the
5901 for more information about recovery from corruption of the
5897 repository.
5902 repository.
5898
5903
5899 Returns 0 on success, 1 if errors are encountered.
5904 Returns 0 on success, 1 if errors are encountered.
5900 """
5905 """
5901 return hg.verify(repo)
5906 return hg.verify(repo)
5902
5907
5903 @command('version', [])
5908 @command('version', [])
5904 def version_(ui):
5909 def version_(ui):
5905 """output version and copyright information"""
5910 """output version and copyright information"""
5906 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5911 ui.write(_("Mercurial Distributed SCM (version %s)\n")
5907 % util.version())
5912 % util.version())
5908 ui.status(_(
5913 ui.status(_(
5909 "(see http://mercurial.selenic.com for more information)\n"
5914 "(see http://mercurial.selenic.com for more information)\n"
5910 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5915 "\nCopyright (C) 2005-2012 Matt Mackall and others\n"
5911 "This is free software; see the source for copying conditions. "
5916 "This is free software; see the source for copying conditions. "
5912 "There is NO\nwarranty; "
5917 "There is NO\nwarranty; "
5913 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5918 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
5914 ))
5919 ))
5915
5920
5916 norepo = ("clone init version help debugcommands debugcomplete"
5921 norepo = ("clone init version help debugcommands debugcomplete"
5917 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5922 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
5918 " debugknown debuggetbundle debugbundle")
5923 " debugknown debuggetbundle debugbundle")
5919 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5924 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
5920 " debugdata debugindex debugindexdot debugrevlog")
5925 " debugdata debugindex debugindexdot debugrevlog")
5921 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5926 inferrepo = ("add addremove annotate cat commit diff grep forget log parents"
5922 " remove resolve status debugwalk")
5927 " remove resolve status debugwalk")
@@ -1,178 +1,178 b''
1 $ hg init t
1 $ hg init t
2 $ cd t
2 $ cd t
3 $ echo import > port
3 $ echo import > port
4 $ hg add port
4 $ hg add port
5 $ hg commit -m 0 -u spam -d '0 0'
5 $ hg commit -m 0 -u spam -d '0 0'
6 $ echo export >> port
6 $ echo export >> port
7 $ hg commit -m 1 -u eggs -d '1 0'
7 $ hg commit -m 1 -u eggs -d '1 0'
8 $ echo export > port
8 $ echo export > port
9 $ echo vaportight >> port
9 $ echo vaportight >> port
10 $ echo 'import/export' >> port
10 $ echo 'import/export' >> port
11 $ hg commit -m 2 -u spam -d '2 0'
11 $ hg commit -m 2 -u spam -d '2 0'
12 $ echo 'import/export' >> port
12 $ echo 'import/export' >> port
13 $ hg commit -m 3 -u eggs -d '3 0'
13 $ hg commit -m 3 -u eggs -d '3 0'
14 $ head -n 3 port > port1
14 $ head -n 3 port > port1
15 $ mv port1 port
15 $ mv port1 port
16 $ hg commit -m 4 -u spam -d '4 0'
16 $ hg commit -m 4 -u spam -d '4 0'
17
17
18 pattern error
18 pattern error
19
19
20 $ hg grep '**test**'
20 $ hg grep '**test**'
21 grep: invalid match pattern: nothing to repeat
21 grep: invalid match pattern: nothing to repeat
22 [1]
22 [1]
23
23
24 simple
24 simple
25
25
26 $ hg grep port port
26 $ hg grep port port
27 port:4:export
27 port:4:export
28 port:4:vaportight
28 port:4:vaportight
29 port:4:import/export
29 port:4:import/export
30
30
31 simple with color
31 simple with color
32
32
33 $ hg --config extensions.color= grep --config color.mode=ansi \
33 $ hg --config extensions.color= grep --config color.mode=ansi \
34 > --color=always port port
34 > --color=always port port
35 port:4:ex\x1b[0;31;1mport\x1b[0m (esc)
35 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32m4\x1b[0m\x1b[0;36m:\x1b[0mex\x1b[0;31;1mport\x1b[0m (esc)
36 port:4:va\x1b[0;31;1mport\x1b[0might (esc)
36 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32m4\x1b[0m\x1b[0;36m:\x1b[0mva\x1b[0;31;1mport\x1b[0might (esc)
37 port:4:im\x1b[0;31;1mport\x1b[0m/export (esc)
37 \x1b[0;35mport\x1b[0m\x1b[0;36m:\x1b[0m\x1b[0;32m4\x1b[0m\x1b[0;36m:\x1b[0mim\x1b[0;31;1mport\x1b[0m/export (esc)
38
38
39 all
39 all
40
40
41 $ hg grep --traceback --all -nu port port
41 $ hg grep --traceback --all -nu port port
42 port:4:4:-:spam:import/export
42 port:4:4:-:spam:import/export
43 port:3:4:+:eggs:import/export
43 port:3:4:+:eggs:import/export
44 port:2:1:-:spam:import
44 port:2:1:-:spam:import
45 port:2:2:-:spam:export
45 port:2:2:-:spam:export
46 port:2:1:+:spam:export
46 port:2:1:+:spam:export
47 port:2:2:+:spam:vaportight
47 port:2:2:+:spam:vaportight
48 port:2:3:+:spam:import/export
48 port:2:3:+:spam:import/export
49 port:1:2:+:eggs:export
49 port:1:2:+:eggs:export
50 port:0:1:+:spam:import
50 port:0:1:+:spam:import
51
51
52 other
52 other
53
53
54 $ hg grep -l port port
54 $ hg grep -l port port
55 port:4
55 port:4
56 $ hg grep import port
56 $ hg grep import port
57 port:4:import/export
57 port:4:import/export
58
58
59 $ hg cp port port2
59 $ hg cp port port2
60 $ hg commit -m 4 -u spam -d '5 0'
60 $ hg commit -m 4 -u spam -d '5 0'
61
61
62 follow
62 follow
63
63
64 $ hg grep --traceback -f 'import\n\Z' port2
64 $ hg grep --traceback -f 'import\n\Z' port2
65 port:0:import
65 port:0:import
66
66
67 $ echo deport >> port2
67 $ echo deport >> port2
68 $ hg commit -m 5 -u eggs -d '6 0'
68 $ hg commit -m 5 -u eggs -d '6 0'
69 $ hg grep -f --all -nu port port2
69 $ hg grep -f --all -nu port port2
70 port2:6:4:+:eggs:deport
70 port2:6:4:+:eggs:deport
71 port:4:4:-:spam:import/export
71 port:4:4:-:spam:import/export
72 port:3:4:+:eggs:import/export
72 port:3:4:+:eggs:import/export
73 port:2:1:-:spam:import
73 port:2:1:-:spam:import
74 port:2:2:-:spam:export
74 port:2:2:-:spam:export
75 port:2:1:+:spam:export
75 port:2:1:+:spam:export
76 port:2:2:+:spam:vaportight
76 port:2:2:+:spam:vaportight
77 port:2:3:+:spam:import/export
77 port:2:3:+:spam:import/export
78 port:1:2:+:eggs:export
78 port:1:2:+:eggs:export
79 port:0:1:+:spam:import
79 port:0:1:+:spam:import
80
80
81 $ cd ..
81 $ cd ..
82 $ hg init t2
82 $ hg init t2
83 $ cd t2
83 $ cd t2
84 $ hg grep foobar foo
84 $ hg grep foobar foo
85 [1]
85 [1]
86 $ hg grep foobar
86 $ hg grep foobar
87 [1]
87 [1]
88 $ echo blue >> color
88 $ echo blue >> color
89 $ echo black >> color
89 $ echo black >> color
90 $ hg add color
90 $ hg add color
91 $ hg ci -m 0
91 $ hg ci -m 0
92 $ echo orange >> color
92 $ echo orange >> color
93 $ hg ci -m 1
93 $ hg ci -m 1
94 $ echo black > color
94 $ echo black > color
95 $ hg ci -m 2
95 $ hg ci -m 2
96 $ echo orange >> color
96 $ echo orange >> color
97 $ echo blue >> color
97 $ echo blue >> color
98 $ hg ci -m 3
98 $ hg ci -m 3
99 $ hg grep orange
99 $ hg grep orange
100 color:3:orange
100 color:3:orange
101 $ hg grep --all orange
101 $ hg grep --all orange
102 color:3:+:orange
102 color:3:+:orange
103 color:2:-:orange
103 color:2:-:orange
104 color:1:+:orange
104 color:1:+:orange
105
105
106
106
107 match in last "line" without newline
107 match in last "line" without newline
108
108
109 $ python -c 'fp = open("noeol", "wb"); fp.write("no infinite loop"); fp.close();'
109 $ python -c 'fp = open("noeol", "wb"); fp.write("no infinite loop"); fp.close();'
110 $ hg ci -Amnoeol
110 $ hg ci -Amnoeol
111 adding noeol
111 adding noeol
112 $ hg grep loop
112 $ hg grep loop
113 noeol:4:no infinite loop
113 noeol:4:no infinite loop
114
114
115 $ cd ..
115 $ cd ..
116
116
117 Issue685: trackback in grep -r after rename
117 Issue685: trackback in grep -r after rename
118
118
119 Got a traceback when using grep on a single
119 Got a traceback when using grep on a single
120 revision with renamed files.
120 revision with renamed files.
121
121
122 $ hg init issue685
122 $ hg init issue685
123 $ cd issue685
123 $ cd issue685
124 $ echo octarine > color
124 $ echo octarine > color
125 $ hg ci -Amcolor
125 $ hg ci -Amcolor
126 adding color
126 adding color
127 $ hg rename color colour
127 $ hg rename color colour
128 $ hg ci -Am rename
128 $ hg ci -Am rename
129 $ hg grep octarine
129 $ hg grep octarine
130 colour:1:octarine
130 colour:1:octarine
131 color:0:octarine
131 color:0:octarine
132
132
133 Used to crash here
133 Used to crash here
134
134
135 $ hg grep -r 1 octarine
135 $ hg grep -r 1 octarine
136 colour:1:octarine
136 colour:1:octarine
137 $ cd ..
137 $ cd ..
138
138
139
139
140 Issue337: test that grep follows parent-child relationships instead
140 Issue337: test that grep follows parent-child relationships instead
141 of just using revision numbers.
141 of just using revision numbers.
142
142
143 $ hg init issue337
143 $ hg init issue337
144 $ cd issue337
144 $ cd issue337
145
145
146 $ echo white > color
146 $ echo white > color
147 $ hg commit -A -m "0 white"
147 $ hg commit -A -m "0 white"
148 adding color
148 adding color
149
149
150 $ echo red > color
150 $ echo red > color
151 $ hg commit -A -m "1 red"
151 $ hg commit -A -m "1 red"
152
152
153 $ hg update 0
153 $ hg update 0
154 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
154 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
155 $ echo black > color
155 $ echo black > color
156 $ hg commit -A -m "2 black"
156 $ hg commit -A -m "2 black"
157 created new head
157 created new head
158
158
159 $ hg update --clean 1
159 $ hg update --clean 1
160 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
160 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
161 $ echo blue > color
161 $ echo blue > color
162 $ hg commit -A -m "3 blue"
162 $ hg commit -A -m "3 blue"
163
163
164 $ hg grep --all red
164 $ hg grep --all red
165 color:3:-:red
165 color:3:-:red
166 color:1:+:red
166 color:1:+:red
167
167
168 $ cd ..
168 $ cd ..
169
169
170 $ hg init a
170 $ hg init a
171 $ cd a
171 $ cd a
172 $ cp "$TESTDIR/binfile.bin" .
172 $ cp "$TESTDIR/binfile.bin" .
173 $ hg add binfile.bin
173 $ hg add binfile.bin
174 $ hg ci -m 'add binfile.bin'
174 $ hg ci -m 'add binfile.bin'
175 $ hg grep "MaCam" --all
175 $ hg grep "MaCam" --all
176 binfile.bin:0:+: Binary file matches
176 binfile.bin:0:+: Binary file matches
177
177
178 $ cd ..
178 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now