##// END OF EJS Templates
bundle: optional advisory obsolescence parts...
Joerg Sonnenberger -
r46780:41d695a0 default
parent child Browse files
Show More

The requested changes are too big and content was truncated. Show full diff

@@ -1,2588 +1,2592
1 # bundle2.py - generic container format to transmit arbitrary data.
1 # bundle2.py - generic container format to transmit arbitrary data.
2 #
2 #
3 # Copyright 2013 Facebook, Inc.
3 # Copyright 2013 Facebook, Inc.
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 """Handling of the new bundle2 format
7 """Handling of the new bundle2 format
8
8
9 The goal of bundle2 is to act as an atomically packet to transmit a set of
9 The goal of bundle2 is to act as an atomically packet to transmit a set of
10 payloads in an application agnostic way. It consist in a sequence of "parts"
10 payloads in an application agnostic way. It consist in a sequence of "parts"
11 that will be handed to and processed by the application layer.
11 that will be handed to and processed by the application layer.
12
12
13
13
14 General format architecture
14 General format architecture
15 ===========================
15 ===========================
16
16
17 The format is architectured as follow
17 The format is architectured as follow
18
18
19 - magic string
19 - magic string
20 - stream level parameters
20 - stream level parameters
21 - payload parts (any number)
21 - payload parts (any number)
22 - end of stream marker.
22 - end of stream marker.
23
23
24 the Binary format
24 the Binary format
25 ============================
25 ============================
26
26
27 All numbers are unsigned and big-endian.
27 All numbers are unsigned and big-endian.
28
28
29 stream level parameters
29 stream level parameters
30 ------------------------
30 ------------------------
31
31
32 Binary format is as follow
32 Binary format is as follow
33
33
34 :params size: int32
34 :params size: int32
35
35
36 The total number of Bytes used by the parameters
36 The total number of Bytes used by the parameters
37
37
38 :params value: arbitrary number of Bytes
38 :params value: arbitrary number of Bytes
39
39
40 A blob of `params size` containing the serialized version of all stream level
40 A blob of `params size` containing the serialized version of all stream level
41 parameters.
41 parameters.
42
42
43 The blob contains a space separated list of parameters. Parameters with value
43 The blob contains a space separated list of parameters. Parameters with value
44 are stored in the form `<name>=<value>`. Both name and value are urlquoted.
44 are stored in the form `<name>=<value>`. Both name and value are urlquoted.
45
45
46 Empty name are obviously forbidden.
46 Empty name are obviously forbidden.
47
47
48 Name MUST start with a letter. If this first letter is lower case, the
48 Name MUST start with a letter. If this first letter is lower case, the
49 parameter is advisory and can be safely ignored. However when the first
49 parameter is advisory and can be safely ignored. However when the first
50 letter is capital, the parameter is mandatory and the bundling process MUST
50 letter is capital, the parameter is mandatory and the bundling process MUST
51 stop if he is not able to proceed it.
51 stop if he is not able to proceed it.
52
52
53 Stream parameters use a simple textual format for two main reasons:
53 Stream parameters use a simple textual format for two main reasons:
54
54
55 - Stream level parameters should remain simple and we want to discourage any
55 - Stream level parameters should remain simple and we want to discourage any
56 crazy usage.
56 crazy usage.
57 - Textual data allow easy human inspection of a bundle2 header in case of
57 - Textual data allow easy human inspection of a bundle2 header in case of
58 troubles.
58 troubles.
59
59
60 Any Applicative level options MUST go into a bundle2 part instead.
60 Any Applicative level options MUST go into a bundle2 part instead.
61
61
62 Payload part
62 Payload part
63 ------------------------
63 ------------------------
64
64
65 Binary format is as follow
65 Binary format is as follow
66
66
67 :header size: int32
67 :header size: int32
68
68
69 The total number of Bytes used by the part header. When the header is empty
69 The total number of Bytes used by the part header. When the header is empty
70 (size = 0) this is interpreted as the end of stream marker.
70 (size = 0) this is interpreted as the end of stream marker.
71
71
72 :header:
72 :header:
73
73
74 The header defines how to interpret the part. It contains two piece of
74 The header defines how to interpret the part. It contains two piece of
75 data: the part type, and the part parameters.
75 data: the part type, and the part parameters.
76
76
77 The part type is used to route an application level handler, that can
77 The part type is used to route an application level handler, that can
78 interpret payload.
78 interpret payload.
79
79
80 Part parameters are passed to the application level handler. They are
80 Part parameters are passed to the application level handler. They are
81 meant to convey information that will help the application level object to
81 meant to convey information that will help the application level object to
82 interpret the part payload.
82 interpret the part payload.
83
83
84 The binary format of the header is has follow
84 The binary format of the header is has follow
85
85
86 :typesize: (one byte)
86 :typesize: (one byte)
87
87
88 :parttype: alphanumerical part name (restricted to [a-zA-Z0-9_:-]*)
88 :parttype: alphanumerical part name (restricted to [a-zA-Z0-9_:-]*)
89
89
90 :partid: A 32bits integer (unique in the bundle) that can be used to refer
90 :partid: A 32bits integer (unique in the bundle) that can be used to refer
91 to this part.
91 to this part.
92
92
93 :parameters:
93 :parameters:
94
94
95 Part's parameter may have arbitrary content, the binary structure is::
95 Part's parameter may have arbitrary content, the binary structure is::
96
96
97 <mandatory-count><advisory-count><param-sizes><param-data>
97 <mandatory-count><advisory-count><param-sizes><param-data>
98
98
99 :mandatory-count: 1 byte, number of mandatory parameters
99 :mandatory-count: 1 byte, number of mandatory parameters
100
100
101 :advisory-count: 1 byte, number of advisory parameters
101 :advisory-count: 1 byte, number of advisory parameters
102
102
103 :param-sizes:
103 :param-sizes:
104
104
105 N couple of bytes, where N is the total number of parameters. Each
105 N couple of bytes, where N is the total number of parameters. Each
106 couple contains (<size-of-key>, <size-of-value) for one parameter.
106 couple contains (<size-of-key>, <size-of-value) for one parameter.
107
107
108 :param-data:
108 :param-data:
109
109
110 A blob of bytes from which each parameter key and value can be
110 A blob of bytes from which each parameter key and value can be
111 retrieved using the list of size couples stored in the previous
111 retrieved using the list of size couples stored in the previous
112 field.
112 field.
113
113
114 Mandatory parameters comes first, then the advisory ones.
114 Mandatory parameters comes first, then the advisory ones.
115
115
116 Each parameter's key MUST be unique within the part.
116 Each parameter's key MUST be unique within the part.
117
117
118 :payload:
118 :payload:
119
119
120 payload is a series of `<chunksize><chunkdata>`.
120 payload is a series of `<chunksize><chunkdata>`.
121
121
122 `chunksize` is an int32, `chunkdata` are plain bytes (as much as
122 `chunksize` is an int32, `chunkdata` are plain bytes (as much as
123 `chunksize` says)` The payload part is concluded by a zero size chunk.
123 `chunksize` says)` The payload part is concluded by a zero size chunk.
124
124
125 The current implementation always produces either zero or one chunk.
125 The current implementation always produces either zero or one chunk.
126 This is an implementation limitation that will ultimately be lifted.
126 This is an implementation limitation that will ultimately be lifted.
127
127
128 `chunksize` can be negative to trigger special case processing. No such
128 `chunksize` can be negative to trigger special case processing. No such
129 processing is in place yet.
129 processing is in place yet.
130
130
131 Bundle processing
131 Bundle processing
132 ============================
132 ============================
133
133
134 Each part is processed in order using a "part handler". Handler are registered
134 Each part is processed in order using a "part handler". Handler are registered
135 for a certain part type.
135 for a certain part type.
136
136
137 The matching of a part to its handler is case insensitive. The case of the
137 The matching of a part to its handler is case insensitive. The case of the
138 part type is used to know if a part is mandatory or advisory. If the Part type
138 part type is used to know if a part is mandatory or advisory. If the Part type
139 contains any uppercase char it is considered mandatory. When no handler is
139 contains any uppercase char it is considered mandatory. When no handler is
140 known for a Mandatory part, the process is aborted and an exception is raised.
140 known for a Mandatory part, the process is aborted and an exception is raised.
141 If the part is advisory and no handler is known, the part is ignored. When the
141 If the part is advisory and no handler is known, the part is ignored. When the
142 process is aborted, the full bundle is still read from the stream to keep the
142 process is aborted, the full bundle is still read from the stream to keep the
143 channel usable. But none of the part read from an abort are processed. In the
143 channel usable. But none of the part read from an abort are processed. In the
144 future, dropping the stream may become an option for channel we do not care to
144 future, dropping the stream may become an option for channel we do not care to
145 preserve.
145 preserve.
146 """
146 """
147
147
148 from __future__ import absolute_import, division
148 from __future__ import absolute_import, division
149
149
150 import collections
150 import collections
151 import errno
151 import errno
152 import os
152 import os
153 import re
153 import re
154 import string
154 import string
155 import struct
155 import struct
156 import sys
156 import sys
157
157
158 from .i18n import _
158 from .i18n import _
159 from .node import (
159 from .node import (
160 hex,
160 hex,
161 nullid,
161 nullid,
162 short,
162 short,
163 )
163 )
164 from . import (
164 from . import (
165 bookmarks,
165 bookmarks,
166 changegroup,
166 changegroup,
167 encoding,
167 encoding,
168 error,
168 error,
169 obsolete,
169 obsolete,
170 phases,
170 phases,
171 pushkey,
171 pushkey,
172 pycompat,
172 pycompat,
173 requirements,
173 requirements,
174 scmutil,
174 scmutil,
175 streamclone,
175 streamclone,
176 tags,
176 tags,
177 url,
177 url,
178 util,
178 util,
179 )
179 )
180 from .utils import stringutil
180 from .utils import stringutil
181
181
182 urlerr = util.urlerr
182 urlerr = util.urlerr
183 urlreq = util.urlreq
183 urlreq = util.urlreq
184
184
185 _pack = struct.pack
185 _pack = struct.pack
186 _unpack = struct.unpack
186 _unpack = struct.unpack
187
187
188 _fstreamparamsize = b'>i'
188 _fstreamparamsize = b'>i'
189 _fpartheadersize = b'>i'
189 _fpartheadersize = b'>i'
190 _fparttypesize = b'>B'
190 _fparttypesize = b'>B'
191 _fpartid = b'>I'
191 _fpartid = b'>I'
192 _fpayloadsize = b'>i'
192 _fpayloadsize = b'>i'
193 _fpartparamcount = b'>BB'
193 _fpartparamcount = b'>BB'
194
194
195 preferedchunksize = 32768
195 preferedchunksize = 32768
196
196
197 _parttypeforbidden = re.compile(b'[^a-zA-Z0-9_:-]')
197 _parttypeforbidden = re.compile(b'[^a-zA-Z0-9_:-]')
198
198
199
199
200 def outdebug(ui, message):
200 def outdebug(ui, message):
201 """debug regarding output stream (bundling)"""
201 """debug regarding output stream (bundling)"""
202 if ui.configbool(b'devel', b'bundle2.debug'):
202 if ui.configbool(b'devel', b'bundle2.debug'):
203 ui.debug(b'bundle2-output: %s\n' % message)
203 ui.debug(b'bundle2-output: %s\n' % message)
204
204
205
205
206 def indebug(ui, message):
206 def indebug(ui, message):
207 """debug on input stream (unbundling)"""
207 """debug on input stream (unbundling)"""
208 if ui.configbool(b'devel', b'bundle2.debug'):
208 if ui.configbool(b'devel', b'bundle2.debug'):
209 ui.debug(b'bundle2-input: %s\n' % message)
209 ui.debug(b'bundle2-input: %s\n' % message)
210
210
211
211
212 def validateparttype(parttype):
212 def validateparttype(parttype):
213 """raise ValueError if a parttype contains invalid character"""
213 """raise ValueError if a parttype contains invalid character"""
214 if _parttypeforbidden.search(parttype):
214 if _parttypeforbidden.search(parttype):
215 raise ValueError(parttype)
215 raise ValueError(parttype)
216
216
217
217
218 def _makefpartparamsizes(nbparams):
218 def _makefpartparamsizes(nbparams):
219 """return a struct format to read part parameter sizes
219 """return a struct format to read part parameter sizes
220
220
221 The number parameters is variable so we need to build that format
221 The number parameters is variable so we need to build that format
222 dynamically.
222 dynamically.
223 """
223 """
224 return b'>' + (b'BB' * nbparams)
224 return b'>' + (b'BB' * nbparams)
225
225
226
226
227 parthandlermapping = {}
227 parthandlermapping = {}
228
228
229
229
230 def parthandler(parttype, params=()):
230 def parthandler(parttype, params=()):
231 """decorator that register a function as a bundle2 part handler
231 """decorator that register a function as a bundle2 part handler
232
232
233 eg::
233 eg::
234
234
235 @parthandler('myparttype', ('mandatory', 'param', 'handled'))
235 @parthandler('myparttype', ('mandatory', 'param', 'handled'))
236 def myparttypehandler(...):
236 def myparttypehandler(...):
237 '''process a part of type "my part".'''
237 '''process a part of type "my part".'''
238 ...
238 ...
239 """
239 """
240 validateparttype(parttype)
240 validateparttype(parttype)
241
241
242 def _decorator(func):
242 def _decorator(func):
243 lparttype = parttype.lower() # enforce lower case matching.
243 lparttype = parttype.lower() # enforce lower case matching.
244 assert lparttype not in parthandlermapping
244 assert lparttype not in parthandlermapping
245 parthandlermapping[lparttype] = func
245 parthandlermapping[lparttype] = func
246 func.params = frozenset(params)
246 func.params = frozenset(params)
247 return func
247 return func
248
248
249 return _decorator
249 return _decorator
250
250
251
251
252 class unbundlerecords(object):
252 class unbundlerecords(object):
253 """keep record of what happens during and unbundle
253 """keep record of what happens during and unbundle
254
254
255 New records are added using `records.add('cat', obj)`. Where 'cat' is a
255 New records are added using `records.add('cat', obj)`. Where 'cat' is a
256 category of record and obj is an arbitrary object.
256 category of record and obj is an arbitrary object.
257
257
258 `records['cat']` will return all entries of this category 'cat'.
258 `records['cat']` will return all entries of this category 'cat'.
259
259
260 Iterating on the object itself will yield `('category', obj)` tuples
260 Iterating on the object itself will yield `('category', obj)` tuples
261 for all entries.
261 for all entries.
262
262
263 All iterations happens in chronological order.
263 All iterations happens in chronological order.
264 """
264 """
265
265
266 def __init__(self):
266 def __init__(self):
267 self._categories = {}
267 self._categories = {}
268 self._sequences = []
268 self._sequences = []
269 self._replies = {}
269 self._replies = {}
270
270
271 def add(self, category, entry, inreplyto=None):
271 def add(self, category, entry, inreplyto=None):
272 """add a new record of a given category.
272 """add a new record of a given category.
273
273
274 The entry can then be retrieved in the list returned by
274 The entry can then be retrieved in the list returned by
275 self['category']."""
275 self['category']."""
276 self._categories.setdefault(category, []).append(entry)
276 self._categories.setdefault(category, []).append(entry)
277 self._sequences.append((category, entry))
277 self._sequences.append((category, entry))
278 if inreplyto is not None:
278 if inreplyto is not None:
279 self.getreplies(inreplyto).add(category, entry)
279 self.getreplies(inreplyto).add(category, entry)
280
280
281 def getreplies(self, partid):
281 def getreplies(self, partid):
282 """get the records that are replies to a specific part"""
282 """get the records that are replies to a specific part"""
283 return self._replies.setdefault(partid, unbundlerecords())
283 return self._replies.setdefault(partid, unbundlerecords())
284
284
285 def __getitem__(self, cat):
285 def __getitem__(self, cat):
286 return tuple(self._categories.get(cat, ()))
286 return tuple(self._categories.get(cat, ()))
287
287
288 def __iter__(self):
288 def __iter__(self):
289 return iter(self._sequences)
289 return iter(self._sequences)
290
290
291 def __len__(self):
291 def __len__(self):
292 return len(self._sequences)
292 return len(self._sequences)
293
293
294 def __nonzero__(self):
294 def __nonzero__(self):
295 return bool(self._sequences)
295 return bool(self._sequences)
296
296
297 __bool__ = __nonzero__
297 __bool__ = __nonzero__
298
298
299
299
300 class bundleoperation(object):
300 class bundleoperation(object):
301 """an object that represents a single bundling process
301 """an object that represents a single bundling process
302
302
303 Its purpose is to carry unbundle-related objects and states.
303 Its purpose is to carry unbundle-related objects and states.
304
304
305 A new object should be created at the beginning of each bundle processing.
305 A new object should be created at the beginning of each bundle processing.
306 The object is to be returned by the processing function.
306 The object is to be returned by the processing function.
307
307
308 The object has very little content now it will ultimately contain:
308 The object has very little content now it will ultimately contain:
309 * an access to the repo the bundle is applied to,
309 * an access to the repo the bundle is applied to,
310 * a ui object,
310 * a ui object,
311 * a way to retrieve a transaction to add changes to the repo,
311 * a way to retrieve a transaction to add changes to the repo,
312 * a way to record the result of processing each part,
312 * a way to record the result of processing each part,
313 * a way to construct a bundle response when applicable.
313 * a way to construct a bundle response when applicable.
314 """
314 """
315
315
316 def __init__(self, repo, transactiongetter, captureoutput=True, source=b''):
316 def __init__(self, repo, transactiongetter, captureoutput=True, source=b''):
317 self.repo = repo
317 self.repo = repo
318 self.ui = repo.ui
318 self.ui = repo.ui
319 self.records = unbundlerecords()
319 self.records = unbundlerecords()
320 self.reply = None
320 self.reply = None
321 self.captureoutput = captureoutput
321 self.captureoutput = captureoutput
322 self.hookargs = {}
322 self.hookargs = {}
323 self._gettransaction = transactiongetter
323 self._gettransaction = transactiongetter
324 # carries value that can modify part behavior
324 # carries value that can modify part behavior
325 self.modes = {}
325 self.modes = {}
326 self.source = source
326 self.source = source
327
327
328 def gettransaction(self):
328 def gettransaction(self):
329 transaction = self._gettransaction()
329 transaction = self._gettransaction()
330
330
331 if self.hookargs:
331 if self.hookargs:
332 # the ones added to the transaction supercede those added
332 # the ones added to the transaction supercede those added
333 # to the operation.
333 # to the operation.
334 self.hookargs.update(transaction.hookargs)
334 self.hookargs.update(transaction.hookargs)
335 transaction.hookargs = self.hookargs
335 transaction.hookargs = self.hookargs
336
336
337 # mark the hookargs as flushed. further attempts to add to
337 # mark the hookargs as flushed. further attempts to add to
338 # hookargs will result in an abort.
338 # hookargs will result in an abort.
339 self.hookargs = None
339 self.hookargs = None
340
340
341 return transaction
341 return transaction
342
342
343 def addhookargs(self, hookargs):
343 def addhookargs(self, hookargs):
344 if self.hookargs is None:
344 if self.hookargs is None:
345 raise error.ProgrammingError(
345 raise error.ProgrammingError(
346 b'attempted to add hookargs to '
346 b'attempted to add hookargs to '
347 b'operation after transaction started'
347 b'operation after transaction started'
348 )
348 )
349 self.hookargs.update(hookargs)
349 self.hookargs.update(hookargs)
350
350
351
351
352 class TransactionUnavailable(RuntimeError):
352 class TransactionUnavailable(RuntimeError):
353 pass
353 pass
354
354
355
355
356 def _notransaction():
356 def _notransaction():
357 """default method to get a transaction while processing a bundle
357 """default method to get a transaction while processing a bundle
358
358
359 Raise an exception to highlight the fact that no transaction was expected
359 Raise an exception to highlight the fact that no transaction was expected
360 to be created"""
360 to be created"""
361 raise TransactionUnavailable()
361 raise TransactionUnavailable()
362
362
363
363
364 def applybundle(repo, unbundler, tr, source, url=None, **kwargs):
364 def applybundle(repo, unbundler, tr, source, url=None, **kwargs):
365 # transform me into unbundler.apply() as soon as the freeze is lifted
365 # transform me into unbundler.apply() as soon as the freeze is lifted
366 if isinstance(unbundler, unbundle20):
366 if isinstance(unbundler, unbundle20):
367 tr.hookargs[b'bundle2'] = b'1'
367 tr.hookargs[b'bundle2'] = b'1'
368 if source is not None and b'source' not in tr.hookargs:
368 if source is not None and b'source' not in tr.hookargs:
369 tr.hookargs[b'source'] = source
369 tr.hookargs[b'source'] = source
370 if url is not None and b'url' not in tr.hookargs:
370 if url is not None and b'url' not in tr.hookargs:
371 tr.hookargs[b'url'] = url
371 tr.hookargs[b'url'] = url
372 return processbundle(repo, unbundler, lambda: tr, source=source)
372 return processbundle(repo, unbundler, lambda: tr, source=source)
373 else:
373 else:
374 # the transactiongetter won't be used, but we might as well set it
374 # the transactiongetter won't be used, but we might as well set it
375 op = bundleoperation(repo, lambda: tr, source=source)
375 op = bundleoperation(repo, lambda: tr, source=source)
376 _processchangegroup(op, unbundler, tr, source, url, **kwargs)
376 _processchangegroup(op, unbundler, tr, source, url, **kwargs)
377 return op
377 return op
378
378
379
379
380 class partiterator(object):
380 class partiterator(object):
381 def __init__(self, repo, op, unbundler):
381 def __init__(self, repo, op, unbundler):
382 self.repo = repo
382 self.repo = repo
383 self.op = op
383 self.op = op
384 self.unbundler = unbundler
384 self.unbundler = unbundler
385 self.iterator = None
385 self.iterator = None
386 self.count = 0
386 self.count = 0
387 self.current = None
387 self.current = None
388
388
389 def __enter__(self):
389 def __enter__(self):
390 def func():
390 def func():
391 itr = enumerate(self.unbundler.iterparts(), 1)
391 itr = enumerate(self.unbundler.iterparts(), 1)
392 for count, p in itr:
392 for count, p in itr:
393 self.count = count
393 self.count = count
394 self.current = p
394 self.current = p
395 yield p
395 yield p
396 p.consume()
396 p.consume()
397 self.current = None
397 self.current = None
398
398
399 self.iterator = func()
399 self.iterator = func()
400 return self.iterator
400 return self.iterator
401
401
402 def __exit__(self, type, exc, tb):
402 def __exit__(self, type, exc, tb):
403 if not self.iterator:
403 if not self.iterator:
404 return
404 return
405
405
406 # Only gracefully abort in a normal exception situation. User aborts
406 # Only gracefully abort in a normal exception situation. User aborts
407 # like Ctrl+C throw a KeyboardInterrupt which is not a base Exception,
407 # like Ctrl+C throw a KeyboardInterrupt which is not a base Exception,
408 # and should not gracefully cleanup.
408 # and should not gracefully cleanup.
409 if isinstance(exc, Exception):
409 if isinstance(exc, Exception):
410 # Any exceptions seeking to the end of the bundle at this point are
410 # Any exceptions seeking to the end of the bundle at this point are
411 # almost certainly related to the underlying stream being bad.
411 # almost certainly related to the underlying stream being bad.
412 # And, chances are that the exception we're handling is related to
412 # And, chances are that the exception we're handling is related to
413 # getting in that bad state. So, we swallow the seeking error and
413 # getting in that bad state. So, we swallow the seeking error and
414 # re-raise the original error.
414 # re-raise the original error.
415 seekerror = False
415 seekerror = False
416 try:
416 try:
417 if self.current:
417 if self.current:
418 # consume the part content to not corrupt the stream.
418 # consume the part content to not corrupt the stream.
419 self.current.consume()
419 self.current.consume()
420
420
421 for part in self.iterator:
421 for part in self.iterator:
422 # consume the bundle content
422 # consume the bundle content
423 part.consume()
423 part.consume()
424 except Exception:
424 except Exception:
425 seekerror = True
425 seekerror = True
426
426
427 # Small hack to let caller code distinguish exceptions from bundle2
427 # Small hack to let caller code distinguish exceptions from bundle2
428 # processing from processing the old format. This is mostly needed
428 # processing from processing the old format. This is mostly needed
429 # to handle different return codes to unbundle according to the type
429 # to handle different return codes to unbundle according to the type
430 # of bundle. We should probably clean up or drop this return code
430 # of bundle. We should probably clean up or drop this return code
431 # craziness in a future version.
431 # craziness in a future version.
432 exc.duringunbundle2 = True
432 exc.duringunbundle2 = True
433 salvaged = []
433 salvaged = []
434 replycaps = None
434 replycaps = None
435 if self.op.reply is not None:
435 if self.op.reply is not None:
436 salvaged = self.op.reply.salvageoutput()
436 salvaged = self.op.reply.salvageoutput()
437 replycaps = self.op.reply.capabilities
437 replycaps = self.op.reply.capabilities
438 exc._replycaps = replycaps
438 exc._replycaps = replycaps
439 exc._bundle2salvagedoutput = salvaged
439 exc._bundle2salvagedoutput = salvaged
440
440
441 # Re-raising from a variable loses the original stack. So only use
441 # Re-raising from a variable loses the original stack. So only use
442 # that form if we need to.
442 # that form if we need to.
443 if seekerror:
443 if seekerror:
444 raise exc
444 raise exc
445
445
446 self.repo.ui.debug(
446 self.repo.ui.debug(
447 b'bundle2-input-bundle: %i parts total\n' % self.count
447 b'bundle2-input-bundle: %i parts total\n' % self.count
448 )
448 )
449
449
450
450
451 def processbundle(repo, unbundler, transactiongetter=None, op=None, source=b''):
451 def processbundle(repo, unbundler, transactiongetter=None, op=None, source=b''):
452 """This function process a bundle, apply effect to/from a repo
452 """This function process a bundle, apply effect to/from a repo
453
453
454 It iterates over each part then searches for and uses the proper handling
454 It iterates over each part then searches for and uses the proper handling
455 code to process the part. Parts are processed in order.
455 code to process the part. Parts are processed in order.
456
456
457 Unknown Mandatory part will abort the process.
457 Unknown Mandatory part will abort the process.
458
458
459 It is temporarily possible to provide a prebuilt bundleoperation to the
459 It is temporarily possible to provide a prebuilt bundleoperation to the
460 function. This is used to ensure output is properly propagated in case of
460 function. This is used to ensure output is properly propagated in case of
461 an error during the unbundling. This output capturing part will likely be
461 an error during the unbundling. This output capturing part will likely be
462 reworked and this ability will probably go away in the process.
462 reworked and this ability will probably go away in the process.
463 """
463 """
464 if op is None:
464 if op is None:
465 if transactiongetter is None:
465 if transactiongetter is None:
466 transactiongetter = _notransaction
466 transactiongetter = _notransaction
467 op = bundleoperation(repo, transactiongetter, source=source)
467 op = bundleoperation(repo, transactiongetter, source=source)
468 # todo:
468 # todo:
469 # - replace this is a init function soon.
469 # - replace this is a init function soon.
470 # - exception catching
470 # - exception catching
471 unbundler.params
471 unbundler.params
472 if repo.ui.debugflag:
472 if repo.ui.debugflag:
473 msg = [b'bundle2-input-bundle:']
473 msg = [b'bundle2-input-bundle:']
474 if unbundler.params:
474 if unbundler.params:
475 msg.append(b' %i params' % len(unbundler.params))
475 msg.append(b' %i params' % len(unbundler.params))
476 if op._gettransaction is None or op._gettransaction is _notransaction:
476 if op._gettransaction is None or op._gettransaction is _notransaction:
477 msg.append(b' no-transaction')
477 msg.append(b' no-transaction')
478 else:
478 else:
479 msg.append(b' with-transaction')
479 msg.append(b' with-transaction')
480 msg.append(b'\n')
480 msg.append(b'\n')
481 repo.ui.debug(b''.join(msg))
481 repo.ui.debug(b''.join(msg))
482
482
483 processparts(repo, op, unbundler)
483 processparts(repo, op, unbundler)
484
484
485 return op
485 return op
486
486
487
487
488 def processparts(repo, op, unbundler):
488 def processparts(repo, op, unbundler):
489 with partiterator(repo, op, unbundler) as parts:
489 with partiterator(repo, op, unbundler) as parts:
490 for part in parts:
490 for part in parts:
491 _processpart(op, part)
491 _processpart(op, part)
492
492
493
493
494 def _processchangegroup(op, cg, tr, source, url, **kwargs):
494 def _processchangegroup(op, cg, tr, source, url, **kwargs):
495 ret = cg.apply(op.repo, tr, source, url, **kwargs)
495 ret = cg.apply(op.repo, tr, source, url, **kwargs)
496 op.records.add(
496 op.records.add(
497 b'changegroup',
497 b'changegroup',
498 {
498 {
499 b'return': ret,
499 b'return': ret,
500 },
500 },
501 )
501 )
502 return ret
502 return ret
503
503
504
504
505 def _gethandler(op, part):
505 def _gethandler(op, part):
506 status = b'unknown' # used by debug output
506 status = b'unknown' # used by debug output
507 try:
507 try:
508 handler = parthandlermapping.get(part.type)
508 handler = parthandlermapping.get(part.type)
509 if handler is None:
509 if handler is None:
510 status = b'unsupported-type'
510 status = b'unsupported-type'
511 raise error.BundleUnknownFeatureError(parttype=part.type)
511 raise error.BundleUnknownFeatureError(parttype=part.type)
512 indebug(op.ui, b'found a handler for part %s' % part.type)
512 indebug(op.ui, b'found a handler for part %s' % part.type)
513 unknownparams = part.mandatorykeys - handler.params
513 unknownparams = part.mandatorykeys - handler.params
514 if unknownparams:
514 if unknownparams:
515 unknownparams = list(unknownparams)
515 unknownparams = list(unknownparams)
516 unknownparams.sort()
516 unknownparams.sort()
517 status = b'unsupported-params (%s)' % b', '.join(unknownparams)
517 status = b'unsupported-params (%s)' % b', '.join(unknownparams)
518 raise error.BundleUnknownFeatureError(
518 raise error.BundleUnknownFeatureError(
519 parttype=part.type, params=unknownparams
519 parttype=part.type, params=unknownparams
520 )
520 )
521 status = b'supported'
521 status = b'supported'
522 except error.BundleUnknownFeatureError as exc:
522 except error.BundleUnknownFeatureError as exc:
523 if part.mandatory: # mandatory parts
523 if part.mandatory: # mandatory parts
524 raise
524 raise
525 indebug(op.ui, b'ignoring unsupported advisory part %s' % exc)
525 indebug(op.ui, b'ignoring unsupported advisory part %s' % exc)
526 return # skip to part processing
526 return # skip to part processing
527 finally:
527 finally:
528 if op.ui.debugflag:
528 if op.ui.debugflag:
529 msg = [b'bundle2-input-part: "%s"' % part.type]
529 msg = [b'bundle2-input-part: "%s"' % part.type]
530 if not part.mandatory:
530 if not part.mandatory:
531 msg.append(b' (advisory)')
531 msg.append(b' (advisory)')
532 nbmp = len(part.mandatorykeys)
532 nbmp = len(part.mandatorykeys)
533 nbap = len(part.params) - nbmp
533 nbap = len(part.params) - nbmp
534 if nbmp or nbap:
534 if nbmp or nbap:
535 msg.append(b' (params:')
535 msg.append(b' (params:')
536 if nbmp:
536 if nbmp:
537 msg.append(b' %i mandatory' % nbmp)
537 msg.append(b' %i mandatory' % nbmp)
538 if nbap:
538 if nbap:
539 msg.append(b' %i advisory' % nbmp)
539 msg.append(b' %i advisory' % nbmp)
540 msg.append(b')')
540 msg.append(b')')
541 msg.append(b' %s\n' % status)
541 msg.append(b' %s\n' % status)
542 op.ui.debug(b''.join(msg))
542 op.ui.debug(b''.join(msg))
543
543
544 return handler
544 return handler
545
545
546
546
547 def _processpart(op, part):
547 def _processpart(op, part):
548 """process a single part from a bundle
548 """process a single part from a bundle
549
549
550 The part is guaranteed to have been fully consumed when the function exits
550 The part is guaranteed to have been fully consumed when the function exits
551 (even if an exception is raised)."""
551 (even if an exception is raised)."""
552 handler = _gethandler(op, part)
552 handler = _gethandler(op, part)
553 if handler is None:
553 if handler is None:
554 return
554 return
555
555
556 # handler is called outside the above try block so that we don't
556 # handler is called outside the above try block so that we don't
557 # risk catching KeyErrors from anything other than the
557 # risk catching KeyErrors from anything other than the
558 # parthandlermapping lookup (any KeyError raised by handler()
558 # parthandlermapping lookup (any KeyError raised by handler()
559 # itself represents a defect of a different variety).
559 # itself represents a defect of a different variety).
560 output = None
560 output = None
561 if op.captureoutput and op.reply is not None:
561 if op.captureoutput and op.reply is not None:
562 op.ui.pushbuffer(error=True, subproc=True)
562 op.ui.pushbuffer(error=True, subproc=True)
563 output = b''
563 output = b''
564 try:
564 try:
565 handler(op, part)
565 handler(op, part)
566 finally:
566 finally:
567 if output is not None:
567 if output is not None:
568 output = op.ui.popbuffer()
568 output = op.ui.popbuffer()
569 if output:
569 if output:
570 outpart = op.reply.newpart(b'output', data=output, mandatory=False)
570 outpart = op.reply.newpart(b'output', data=output, mandatory=False)
571 outpart.addparam(
571 outpart.addparam(
572 b'in-reply-to', pycompat.bytestr(part.id), mandatory=False
572 b'in-reply-to', pycompat.bytestr(part.id), mandatory=False
573 )
573 )
574
574
575
575
576 def decodecaps(blob):
576 def decodecaps(blob):
577 """decode a bundle2 caps bytes blob into a dictionary
577 """decode a bundle2 caps bytes blob into a dictionary
578
578
579 The blob is a list of capabilities (one per line)
579 The blob is a list of capabilities (one per line)
580 Capabilities may have values using a line of the form::
580 Capabilities may have values using a line of the form::
581
581
582 capability=value1,value2,value3
582 capability=value1,value2,value3
583
583
584 The values are always a list."""
584 The values are always a list."""
585 caps = {}
585 caps = {}
586 for line in blob.splitlines():
586 for line in blob.splitlines():
587 if not line:
587 if not line:
588 continue
588 continue
589 if b'=' not in line:
589 if b'=' not in line:
590 key, vals = line, ()
590 key, vals = line, ()
591 else:
591 else:
592 key, vals = line.split(b'=', 1)
592 key, vals = line.split(b'=', 1)
593 vals = vals.split(b',')
593 vals = vals.split(b',')
594 key = urlreq.unquote(key)
594 key = urlreq.unquote(key)
595 vals = [urlreq.unquote(v) for v in vals]
595 vals = [urlreq.unquote(v) for v in vals]
596 caps[key] = vals
596 caps[key] = vals
597 return caps
597 return caps
598
598
599
599
600 def encodecaps(caps):
600 def encodecaps(caps):
601 """encode a bundle2 caps dictionary into a bytes blob"""
601 """encode a bundle2 caps dictionary into a bytes blob"""
602 chunks = []
602 chunks = []
603 for ca in sorted(caps):
603 for ca in sorted(caps):
604 vals = caps[ca]
604 vals = caps[ca]
605 ca = urlreq.quote(ca)
605 ca = urlreq.quote(ca)
606 vals = [urlreq.quote(v) for v in vals]
606 vals = [urlreq.quote(v) for v in vals]
607 if vals:
607 if vals:
608 ca = b"%s=%s" % (ca, b','.join(vals))
608 ca = b"%s=%s" % (ca, b','.join(vals))
609 chunks.append(ca)
609 chunks.append(ca)
610 return b'\n'.join(chunks)
610 return b'\n'.join(chunks)
611
611
612
612
613 bundletypes = {
613 bundletypes = {
614 b"": (b"", b'UN'), # only when using unbundle on ssh and old http servers
614 b"": (b"", b'UN'), # only when using unbundle on ssh and old http servers
615 # since the unification ssh accepts a header but there
615 # since the unification ssh accepts a header but there
616 # is no capability signaling it.
616 # is no capability signaling it.
617 b"HG20": (), # special-cased below
617 b"HG20": (), # special-cased below
618 b"HG10UN": (b"HG10UN", b'UN'),
618 b"HG10UN": (b"HG10UN", b'UN'),
619 b"HG10BZ": (b"HG10", b'BZ'),
619 b"HG10BZ": (b"HG10", b'BZ'),
620 b"HG10GZ": (b"HG10GZ", b'GZ'),
620 b"HG10GZ": (b"HG10GZ", b'GZ'),
621 }
621 }
622
622
623 # hgweb uses this list to communicate its preferred type
623 # hgweb uses this list to communicate its preferred type
624 bundlepriority = [b'HG10GZ', b'HG10BZ', b'HG10UN']
624 bundlepriority = [b'HG10GZ', b'HG10BZ', b'HG10UN']
625
625
626
626
627 class bundle20(object):
627 class bundle20(object):
628 """represent an outgoing bundle2 container
628 """represent an outgoing bundle2 container
629
629
630 Use the `addparam` method to add stream level parameter. and `newpart` to
630 Use the `addparam` method to add stream level parameter. and `newpart` to
631 populate it. Then call `getchunks` to retrieve all the binary chunks of
631 populate it. Then call `getchunks` to retrieve all the binary chunks of
632 data that compose the bundle2 container."""
632 data that compose the bundle2 container."""
633
633
634 _magicstring = b'HG20'
634 _magicstring = b'HG20'
635
635
636 def __init__(self, ui, capabilities=()):
636 def __init__(self, ui, capabilities=()):
637 self.ui = ui
637 self.ui = ui
638 self._params = []
638 self._params = []
639 self._parts = []
639 self._parts = []
640 self.capabilities = dict(capabilities)
640 self.capabilities = dict(capabilities)
641 self._compengine = util.compengines.forbundletype(b'UN')
641 self._compengine = util.compengines.forbundletype(b'UN')
642 self._compopts = None
642 self._compopts = None
643 # If compression is being handled by a consumer of the raw
643 # If compression is being handled by a consumer of the raw
644 # data (e.g. the wire protocol), unsetting this flag tells
644 # data (e.g. the wire protocol), unsetting this flag tells
645 # consumers that the bundle is best left uncompressed.
645 # consumers that the bundle is best left uncompressed.
646 self.prefercompressed = True
646 self.prefercompressed = True
647
647
648 def setcompression(self, alg, compopts=None):
648 def setcompression(self, alg, compopts=None):
649 """setup core part compression to <alg>"""
649 """setup core part compression to <alg>"""
650 if alg in (None, b'UN'):
650 if alg in (None, b'UN'):
651 return
651 return
652 assert not any(n.lower() == b'compression' for n, v in self._params)
652 assert not any(n.lower() == b'compression' for n, v in self._params)
653 self.addparam(b'Compression', alg)
653 self.addparam(b'Compression', alg)
654 self._compengine = util.compengines.forbundletype(alg)
654 self._compengine = util.compengines.forbundletype(alg)
655 self._compopts = compopts
655 self._compopts = compopts
656
656
657 @property
657 @property
658 def nbparts(self):
658 def nbparts(self):
659 """total number of parts added to the bundler"""
659 """total number of parts added to the bundler"""
660 return len(self._parts)
660 return len(self._parts)
661
661
662 # methods used to defines the bundle2 content
662 # methods used to defines the bundle2 content
663 def addparam(self, name, value=None):
663 def addparam(self, name, value=None):
664 """add a stream level parameter"""
664 """add a stream level parameter"""
665 if not name:
665 if not name:
666 raise error.ProgrammingError(b'empty parameter name')
666 raise error.ProgrammingError(b'empty parameter name')
667 if name[0:1] not in pycompat.bytestr(
667 if name[0:1] not in pycompat.bytestr(
668 string.ascii_letters # pytype: disable=wrong-arg-types
668 string.ascii_letters # pytype: disable=wrong-arg-types
669 ):
669 ):
670 raise error.ProgrammingError(
670 raise error.ProgrammingError(
671 b'non letter first character: %s' % name
671 b'non letter first character: %s' % name
672 )
672 )
673 self._params.append((name, value))
673 self._params.append((name, value))
674
674
675 def addpart(self, part):
675 def addpart(self, part):
676 """add a new part to the bundle2 container
676 """add a new part to the bundle2 container
677
677
678 Parts contains the actual applicative payload."""
678 Parts contains the actual applicative payload."""
679 assert part.id is None
679 assert part.id is None
680 part.id = len(self._parts) # very cheap counter
680 part.id = len(self._parts) # very cheap counter
681 self._parts.append(part)
681 self._parts.append(part)
682
682
683 def newpart(self, typeid, *args, **kwargs):
683 def newpart(self, typeid, *args, **kwargs):
684 """create a new part and add it to the containers
684 """create a new part and add it to the containers
685
685
686 As the part is directly added to the containers. For now, this means
686 As the part is directly added to the containers. For now, this means
687 that any failure to properly initialize the part after calling
687 that any failure to properly initialize the part after calling
688 ``newpart`` should result in a failure of the whole bundling process.
688 ``newpart`` should result in a failure of the whole bundling process.
689
689
690 You can still fall back to manually create and add if you need better
690 You can still fall back to manually create and add if you need better
691 control."""
691 control."""
692 part = bundlepart(typeid, *args, **kwargs)
692 part = bundlepart(typeid, *args, **kwargs)
693 self.addpart(part)
693 self.addpart(part)
694 return part
694 return part
695
695
696 # methods used to generate the bundle2 stream
696 # methods used to generate the bundle2 stream
697 def getchunks(self):
697 def getchunks(self):
698 if self.ui.debugflag:
698 if self.ui.debugflag:
699 msg = [b'bundle2-output-bundle: "%s",' % self._magicstring]
699 msg = [b'bundle2-output-bundle: "%s",' % self._magicstring]
700 if self._params:
700 if self._params:
701 msg.append(b' (%i params)' % len(self._params))
701 msg.append(b' (%i params)' % len(self._params))
702 msg.append(b' %i parts total\n' % len(self._parts))
702 msg.append(b' %i parts total\n' % len(self._parts))
703 self.ui.debug(b''.join(msg))
703 self.ui.debug(b''.join(msg))
704 outdebug(self.ui, b'start emission of %s stream' % self._magicstring)
704 outdebug(self.ui, b'start emission of %s stream' % self._magicstring)
705 yield self._magicstring
705 yield self._magicstring
706 param = self._paramchunk()
706 param = self._paramchunk()
707 outdebug(self.ui, b'bundle parameter: %s' % param)
707 outdebug(self.ui, b'bundle parameter: %s' % param)
708 yield _pack(_fstreamparamsize, len(param))
708 yield _pack(_fstreamparamsize, len(param))
709 if param:
709 if param:
710 yield param
710 yield param
711 for chunk in self._compengine.compressstream(
711 for chunk in self._compengine.compressstream(
712 self._getcorechunk(), self._compopts
712 self._getcorechunk(), self._compopts
713 ):
713 ):
714 yield chunk
714 yield chunk
715
715
716 def _paramchunk(self):
716 def _paramchunk(self):
717 """return a encoded version of all stream parameters"""
717 """return a encoded version of all stream parameters"""
718 blocks = []
718 blocks = []
719 for par, value in self._params:
719 for par, value in self._params:
720 par = urlreq.quote(par)
720 par = urlreq.quote(par)
721 if value is not None:
721 if value is not None:
722 value = urlreq.quote(value)
722 value = urlreq.quote(value)
723 par = b'%s=%s' % (par, value)
723 par = b'%s=%s' % (par, value)
724 blocks.append(par)
724 blocks.append(par)
725 return b' '.join(blocks)
725 return b' '.join(blocks)
726
726
727 def _getcorechunk(self):
727 def _getcorechunk(self):
728 """yield chunk for the core part of the bundle
728 """yield chunk for the core part of the bundle
729
729
730 (all but headers and parameters)"""
730 (all but headers and parameters)"""
731 outdebug(self.ui, b'start of parts')
731 outdebug(self.ui, b'start of parts')
732 for part in self._parts:
732 for part in self._parts:
733 outdebug(self.ui, b'bundle part: "%s"' % part.type)
733 outdebug(self.ui, b'bundle part: "%s"' % part.type)
734 for chunk in part.getchunks(ui=self.ui):
734 for chunk in part.getchunks(ui=self.ui):
735 yield chunk
735 yield chunk
736 outdebug(self.ui, b'end of bundle')
736 outdebug(self.ui, b'end of bundle')
737 yield _pack(_fpartheadersize, 0)
737 yield _pack(_fpartheadersize, 0)
738
738
739 def salvageoutput(self):
739 def salvageoutput(self):
740 """return a list with a copy of all output parts in the bundle
740 """return a list with a copy of all output parts in the bundle
741
741
742 This is meant to be used during error handling to make sure we preserve
742 This is meant to be used during error handling to make sure we preserve
743 server output"""
743 server output"""
744 salvaged = []
744 salvaged = []
745 for part in self._parts:
745 for part in self._parts:
746 if part.type.startswith(b'output'):
746 if part.type.startswith(b'output'):
747 salvaged.append(part.copy())
747 salvaged.append(part.copy())
748 return salvaged
748 return salvaged
749
749
750
750
751 class unpackermixin(object):
751 class unpackermixin(object):
752 """A mixin to extract bytes and struct data from a stream"""
752 """A mixin to extract bytes and struct data from a stream"""
753
753
754 def __init__(self, fp):
754 def __init__(self, fp):
755 self._fp = fp
755 self._fp = fp
756
756
757 def _unpack(self, format):
757 def _unpack(self, format):
758 """unpack this struct format from the stream
758 """unpack this struct format from the stream
759
759
760 This method is meant for internal usage by the bundle2 protocol only.
760 This method is meant for internal usage by the bundle2 protocol only.
761 They directly manipulate the low level stream including bundle2 level
761 They directly manipulate the low level stream including bundle2 level
762 instruction.
762 instruction.
763
763
764 Do not use it to implement higher-level logic or methods."""
764 Do not use it to implement higher-level logic or methods."""
765 data = self._readexact(struct.calcsize(format))
765 data = self._readexact(struct.calcsize(format))
766 return _unpack(format, data)
766 return _unpack(format, data)
767
767
768 def _readexact(self, size):
768 def _readexact(self, size):
769 """read exactly <size> bytes from the stream
769 """read exactly <size> bytes from the stream
770
770
771 This method is meant for internal usage by the bundle2 protocol only.
771 This method is meant for internal usage by the bundle2 protocol only.
772 They directly manipulate the low level stream including bundle2 level
772 They directly manipulate the low level stream including bundle2 level
773 instruction.
773 instruction.
774
774
775 Do not use it to implement higher-level logic or methods."""
775 Do not use it to implement higher-level logic or methods."""
776 return changegroup.readexactly(self._fp, size)
776 return changegroup.readexactly(self._fp, size)
777
777
778
778
779 def getunbundler(ui, fp, magicstring=None):
779 def getunbundler(ui, fp, magicstring=None):
780 """return a valid unbundler object for a given magicstring"""
780 """return a valid unbundler object for a given magicstring"""
781 if magicstring is None:
781 if magicstring is None:
782 magicstring = changegroup.readexactly(fp, 4)
782 magicstring = changegroup.readexactly(fp, 4)
783 magic, version = magicstring[0:2], magicstring[2:4]
783 magic, version = magicstring[0:2], magicstring[2:4]
784 if magic != b'HG':
784 if magic != b'HG':
785 ui.debug(
785 ui.debug(
786 b"error: invalid magic: %r (version %r), should be 'HG'\n"
786 b"error: invalid magic: %r (version %r), should be 'HG'\n"
787 % (magic, version)
787 % (magic, version)
788 )
788 )
789 raise error.Abort(_(b'not a Mercurial bundle'))
789 raise error.Abort(_(b'not a Mercurial bundle'))
790 unbundlerclass = formatmap.get(version)
790 unbundlerclass = formatmap.get(version)
791 if unbundlerclass is None:
791 if unbundlerclass is None:
792 raise error.Abort(_(b'unknown bundle version %s') % version)
792 raise error.Abort(_(b'unknown bundle version %s') % version)
793 unbundler = unbundlerclass(ui, fp)
793 unbundler = unbundlerclass(ui, fp)
794 indebug(ui, b'start processing of %s stream' % magicstring)
794 indebug(ui, b'start processing of %s stream' % magicstring)
795 return unbundler
795 return unbundler
796
796
797
797
798 class unbundle20(unpackermixin):
798 class unbundle20(unpackermixin):
799 """interpret a bundle2 stream
799 """interpret a bundle2 stream
800
800
801 This class is fed with a binary stream and yields parts through its
801 This class is fed with a binary stream and yields parts through its
802 `iterparts` methods."""
802 `iterparts` methods."""
803
803
804 _magicstring = b'HG20'
804 _magicstring = b'HG20'
805
805
806 def __init__(self, ui, fp):
806 def __init__(self, ui, fp):
807 """If header is specified, we do not read it out of the stream."""
807 """If header is specified, we do not read it out of the stream."""
808 self.ui = ui
808 self.ui = ui
809 self._compengine = util.compengines.forbundletype(b'UN')
809 self._compengine = util.compengines.forbundletype(b'UN')
810 self._compressed = None
810 self._compressed = None
811 super(unbundle20, self).__init__(fp)
811 super(unbundle20, self).__init__(fp)
812
812
813 @util.propertycache
813 @util.propertycache
814 def params(self):
814 def params(self):
815 """dictionary of stream level parameters"""
815 """dictionary of stream level parameters"""
816 indebug(self.ui, b'reading bundle2 stream parameters')
816 indebug(self.ui, b'reading bundle2 stream parameters')
817 params = {}
817 params = {}
818 paramssize = self._unpack(_fstreamparamsize)[0]
818 paramssize = self._unpack(_fstreamparamsize)[0]
819 if paramssize < 0:
819 if paramssize < 0:
820 raise error.BundleValueError(
820 raise error.BundleValueError(
821 b'negative bundle param size: %i' % paramssize
821 b'negative bundle param size: %i' % paramssize
822 )
822 )
823 if paramssize:
823 if paramssize:
824 params = self._readexact(paramssize)
824 params = self._readexact(paramssize)
825 params = self._processallparams(params)
825 params = self._processallparams(params)
826 return params
826 return params
827
827
828 def _processallparams(self, paramsblock):
828 def _processallparams(self, paramsblock):
829 """"""
829 """"""
830 params = util.sortdict()
830 params = util.sortdict()
831 for p in paramsblock.split(b' '):
831 for p in paramsblock.split(b' '):
832 p = p.split(b'=', 1)
832 p = p.split(b'=', 1)
833 p = [urlreq.unquote(i) for i in p]
833 p = [urlreq.unquote(i) for i in p]
834 if len(p) < 2:
834 if len(p) < 2:
835 p.append(None)
835 p.append(None)
836 self._processparam(*p)
836 self._processparam(*p)
837 params[p[0]] = p[1]
837 params[p[0]] = p[1]
838 return params
838 return params
839
839
840 def _processparam(self, name, value):
840 def _processparam(self, name, value):
841 """process a parameter, applying its effect if needed
841 """process a parameter, applying its effect if needed
842
842
843 Parameter starting with a lower case letter are advisory and will be
843 Parameter starting with a lower case letter are advisory and will be
844 ignored when unknown. Those starting with an upper case letter are
844 ignored when unknown. Those starting with an upper case letter are
845 mandatory and will this function will raise a KeyError when unknown.
845 mandatory and will this function will raise a KeyError when unknown.
846
846
847 Note: no option are currently supported. Any input will be either
847 Note: no option are currently supported. Any input will be either
848 ignored or failing.
848 ignored or failing.
849 """
849 """
850 if not name:
850 if not name:
851 raise ValueError('empty parameter name')
851 raise ValueError('empty parameter name')
852 if name[0:1] not in pycompat.bytestr(
852 if name[0:1] not in pycompat.bytestr(
853 string.ascii_letters # pytype: disable=wrong-arg-types
853 string.ascii_letters # pytype: disable=wrong-arg-types
854 ):
854 ):
855 raise ValueError('non letter first character: %s' % name)
855 raise ValueError('non letter first character: %s' % name)
856 try:
856 try:
857 handler = b2streamparamsmap[name.lower()]
857 handler = b2streamparamsmap[name.lower()]
858 except KeyError:
858 except KeyError:
859 if name[0:1].islower():
859 if name[0:1].islower():
860 indebug(self.ui, b"ignoring unknown parameter %s" % name)
860 indebug(self.ui, b"ignoring unknown parameter %s" % name)
861 else:
861 else:
862 raise error.BundleUnknownFeatureError(params=(name,))
862 raise error.BundleUnknownFeatureError(params=(name,))
863 else:
863 else:
864 handler(self, name, value)
864 handler(self, name, value)
865
865
866 def _forwardchunks(self):
866 def _forwardchunks(self):
867 """utility to transfer a bundle2 as binary
867 """utility to transfer a bundle2 as binary
868
868
869 This is made necessary by the fact the 'getbundle' command over 'ssh'
869 This is made necessary by the fact the 'getbundle' command over 'ssh'
870 have no way to know then the reply end, relying on the bundle to be
870 have no way to know then the reply end, relying on the bundle to be
871 interpreted to know its end. This is terrible and we are sorry, but we
871 interpreted to know its end. This is terrible and we are sorry, but we
872 needed to move forward to get general delta enabled.
872 needed to move forward to get general delta enabled.
873 """
873 """
874 yield self._magicstring
874 yield self._magicstring
875 assert 'params' not in vars(self)
875 assert 'params' not in vars(self)
876 paramssize = self._unpack(_fstreamparamsize)[0]
876 paramssize = self._unpack(_fstreamparamsize)[0]
877 if paramssize < 0:
877 if paramssize < 0:
878 raise error.BundleValueError(
878 raise error.BundleValueError(
879 b'negative bundle param size: %i' % paramssize
879 b'negative bundle param size: %i' % paramssize
880 )
880 )
881 if paramssize:
881 if paramssize:
882 params = self._readexact(paramssize)
882 params = self._readexact(paramssize)
883 self._processallparams(params)
883 self._processallparams(params)
884 # The payload itself is decompressed below, so drop
884 # The payload itself is decompressed below, so drop
885 # the compression parameter passed down to compensate.
885 # the compression parameter passed down to compensate.
886 outparams = []
886 outparams = []
887 for p in params.split(b' '):
887 for p in params.split(b' '):
888 k, v = p.split(b'=', 1)
888 k, v = p.split(b'=', 1)
889 if k.lower() != b'compression':
889 if k.lower() != b'compression':
890 outparams.append(p)
890 outparams.append(p)
891 outparams = b' '.join(outparams)
891 outparams = b' '.join(outparams)
892 yield _pack(_fstreamparamsize, len(outparams))
892 yield _pack(_fstreamparamsize, len(outparams))
893 yield outparams
893 yield outparams
894 else:
894 else:
895 yield _pack(_fstreamparamsize, paramssize)
895 yield _pack(_fstreamparamsize, paramssize)
896 # From there, payload might need to be decompressed
896 # From there, payload might need to be decompressed
897 self._fp = self._compengine.decompressorreader(self._fp)
897 self._fp = self._compengine.decompressorreader(self._fp)
898 emptycount = 0
898 emptycount = 0
899 while emptycount < 2:
899 while emptycount < 2:
900 # so we can brainlessly loop
900 # so we can brainlessly loop
901 assert _fpartheadersize == _fpayloadsize
901 assert _fpartheadersize == _fpayloadsize
902 size = self._unpack(_fpartheadersize)[0]
902 size = self._unpack(_fpartheadersize)[0]
903 yield _pack(_fpartheadersize, size)
903 yield _pack(_fpartheadersize, size)
904 if size:
904 if size:
905 emptycount = 0
905 emptycount = 0
906 else:
906 else:
907 emptycount += 1
907 emptycount += 1
908 continue
908 continue
909 if size == flaginterrupt:
909 if size == flaginterrupt:
910 continue
910 continue
911 elif size < 0:
911 elif size < 0:
912 raise error.BundleValueError(b'negative chunk size: %i')
912 raise error.BundleValueError(b'negative chunk size: %i')
913 yield self._readexact(size)
913 yield self._readexact(size)
914
914
915 def iterparts(self, seekable=False):
915 def iterparts(self, seekable=False):
916 """yield all parts contained in the stream"""
916 """yield all parts contained in the stream"""
917 cls = seekableunbundlepart if seekable else unbundlepart
917 cls = seekableunbundlepart if seekable else unbundlepart
918 # make sure param have been loaded
918 # make sure param have been loaded
919 self.params
919 self.params
920 # From there, payload need to be decompressed
920 # From there, payload need to be decompressed
921 self._fp = self._compengine.decompressorreader(self._fp)
921 self._fp = self._compengine.decompressorreader(self._fp)
922 indebug(self.ui, b'start extraction of bundle2 parts')
922 indebug(self.ui, b'start extraction of bundle2 parts')
923 headerblock = self._readpartheader()
923 headerblock = self._readpartheader()
924 while headerblock is not None:
924 while headerblock is not None:
925 part = cls(self.ui, headerblock, self._fp)
925 part = cls(self.ui, headerblock, self._fp)
926 yield part
926 yield part
927 # Ensure part is fully consumed so we can start reading the next
927 # Ensure part is fully consumed so we can start reading the next
928 # part.
928 # part.
929 part.consume()
929 part.consume()
930
930
931 headerblock = self._readpartheader()
931 headerblock = self._readpartheader()
932 indebug(self.ui, b'end of bundle2 stream')
932 indebug(self.ui, b'end of bundle2 stream')
933
933
934 def _readpartheader(self):
934 def _readpartheader(self):
935 """reads a part header size and return the bytes blob
935 """reads a part header size and return the bytes blob
936
936
937 returns None if empty"""
937 returns None if empty"""
938 headersize = self._unpack(_fpartheadersize)[0]
938 headersize = self._unpack(_fpartheadersize)[0]
939 if headersize < 0:
939 if headersize < 0:
940 raise error.BundleValueError(
940 raise error.BundleValueError(
941 b'negative part header size: %i' % headersize
941 b'negative part header size: %i' % headersize
942 )
942 )
943 indebug(self.ui, b'part header size: %i' % headersize)
943 indebug(self.ui, b'part header size: %i' % headersize)
944 if headersize:
944 if headersize:
945 return self._readexact(headersize)
945 return self._readexact(headersize)
946 return None
946 return None
947
947
948 def compressed(self):
948 def compressed(self):
949 self.params # load params
949 self.params # load params
950 return self._compressed
950 return self._compressed
951
951
952 def close(self):
952 def close(self):
953 """close underlying file"""
953 """close underlying file"""
954 if util.safehasattr(self._fp, 'close'):
954 if util.safehasattr(self._fp, 'close'):
955 return self._fp.close()
955 return self._fp.close()
956
956
957
957
958 formatmap = {b'20': unbundle20}
958 formatmap = {b'20': unbundle20}
959
959
960 b2streamparamsmap = {}
960 b2streamparamsmap = {}
961
961
962
962
963 def b2streamparamhandler(name):
963 def b2streamparamhandler(name):
964 """register a handler for a stream level parameter"""
964 """register a handler for a stream level parameter"""
965
965
966 def decorator(func):
966 def decorator(func):
967 assert name not in formatmap
967 assert name not in formatmap
968 b2streamparamsmap[name] = func
968 b2streamparamsmap[name] = func
969 return func
969 return func
970
970
971 return decorator
971 return decorator
972
972
973
973
974 @b2streamparamhandler(b'compression')
974 @b2streamparamhandler(b'compression')
975 def processcompression(unbundler, param, value):
975 def processcompression(unbundler, param, value):
976 """read compression parameter and install payload decompression"""
976 """read compression parameter and install payload decompression"""
977 if value not in util.compengines.supportedbundletypes:
977 if value not in util.compengines.supportedbundletypes:
978 raise error.BundleUnknownFeatureError(params=(param,), values=(value,))
978 raise error.BundleUnknownFeatureError(params=(param,), values=(value,))
979 unbundler._compengine = util.compengines.forbundletype(value)
979 unbundler._compengine = util.compengines.forbundletype(value)
980 if value is not None:
980 if value is not None:
981 unbundler._compressed = True
981 unbundler._compressed = True
982
982
983
983
984 class bundlepart(object):
984 class bundlepart(object):
985 """A bundle2 part contains application level payload
985 """A bundle2 part contains application level payload
986
986
987 The part `type` is used to route the part to the application level
987 The part `type` is used to route the part to the application level
988 handler.
988 handler.
989
989
990 The part payload is contained in ``part.data``. It could be raw bytes or a
990 The part payload is contained in ``part.data``. It could be raw bytes or a
991 generator of byte chunks.
991 generator of byte chunks.
992
992
993 You can add parameters to the part using the ``addparam`` method.
993 You can add parameters to the part using the ``addparam`` method.
994 Parameters can be either mandatory (default) or advisory. Remote side
994 Parameters can be either mandatory (default) or advisory. Remote side
995 should be able to safely ignore the advisory ones.
995 should be able to safely ignore the advisory ones.
996
996
997 Both data and parameters cannot be modified after the generation has begun.
997 Both data and parameters cannot be modified after the generation has begun.
998 """
998 """
999
999
1000 def __init__(
1000 def __init__(
1001 self,
1001 self,
1002 parttype,
1002 parttype,
1003 mandatoryparams=(),
1003 mandatoryparams=(),
1004 advisoryparams=(),
1004 advisoryparams=(),
1005 data=b'',
1005 data=b'',
1006 mandatory=True,
1006 mandatory=True,
1007 ):
1007 ):
1008 validateparttype(parttype)
1008 validateparttype(parttype)
1009 self.id = None
1009 self.id = None
1010 self.type = parttype
1010 self.type = parttype
1011 self._data = data
1011 self._data = data
1012 self._mandatoryparams = list(mandatoryparams)
1012 self._mandatoryparams = list(mandatoryparams)
1013 self._advisoryparams = list(advisoryparams)
1013 self._advisoryparams = list(advisoryparams)
1014 # checking for duplicated entries
1014 # checking for duplicated entries
1015 self._seenparams = set()
1015 self._seenparams = set()
1016 for pname, __ in self._mandatoryparams + self._advisoryparams:
1016 for pname, __ in self._mandatoryparams + self._advisoryparams:
1017 if pname in self._seenparams:
1017 if pname in self._seenparams:
1018 raise error.ProgrammingError(b'duplicated params: %s' % pname)
1018 raise error.ProgrammingError(b'duplicated params: %s' % pname)
1019 self._seenparams.add(pname)
1019 self._seenparams.add(pname)
1020 # status of the part's generation:
1020 # status of the part's generation:
1021 # - None: not started,
1021 # - None: not started,
1022 # - False: currently generated,
1022 # - False: currently generated,
1023 # - True: generation done.
1023 # - True: generation done.
1024 self._generated = None
1024 self._generated = None
1025 self.mandatory = mandatory
1025 self.mandatory = mandatory
1026
1026
1027 def __repr__(self):
1027 def __repr__(self):
1028 cls = "%s.%s" % (self.__class__.__module__, self.__class__.__name__)
1028 cls = "%s.%s" % (self.__class__.__module__, self.__class__.__name__)
1029 return '<%s object at %x; id: %s; type: %s; mandatory: %s>' % (
1029 return '<%s object at %x; id: %s; type: %s; mandatory: %s>' % (
1030 cls,
1030 cls,
1031 id(self),
1031 id(self),
1032 self.id,
1032 self.id,
1033 self.type,
1033 self.type,
1034 self.mandatory,
1034 self.mandatory,
1035 )
1035 )
1036
1036
1037 def copy(self):
1037 def copy(self):
1038 """return a copy of the part
1038 """return a copy of the part
1039
1039
1040 The new part have the very same content but no partid assigned yet.
1040 The new part have the very same content but no partid assigned yet.
1041 Parts with generated data cannot be copied."""
1041 Parts with generated data cannot be copied."""
1042 assert not util.safehasattr(self.data, 'next')
1042 assert not util.safehasattr(self.data, 'next')
1043 return self.__class__(
1043 return self.__class__(
1044 self.type,
1044 self.type,
1045 self._mandatoryparams,
1045 self._mandatoryparams,
1046 self._advisoryparams,
1046 self._advisoryparams,
1047 self._data,
1047 self._data,
1048 self.mandatory,
1048 self.mandatory,
1049 )
1049 )
1050
1050
1051 # methods used to defines the part content
1051 # methods used to defines the part content
1052 @property
1052 @property
1053 def data(self):
1053 def data(self):
1054 return self._data
1054 return self._data
1055
1055
1056 @data.setter
1056 @data.setter
1057 def data(self, data):
1057 def data(self, data):
1058 if self._generated is not None:
1058 if self._generated is not None:
1059 raise error.ReadOnlyPartError(b'part is being generated')
1059 raise error.ReadOnlyPartError(b'part is being generated')
1060 self._data = data
1060 self._data = data
1061
1061
1062 @property
1062 @property
1063 def mandatoryparams(self):
1063 def mandatoryparams(self):
1064 # make it an immutable tuple to force people through ``addparam``
1064 # make it an immutable tuple to force people through ``addparam``
1065 return tuple(self._mandatoryparams)
1065 return tuple(self._mandatoryparams)
1066
1066
1067 @property
1067 @property
1068 def advisoryparams(self):
1068 def advisoryparams(self):
1069 # make it an immutable tuple to force people through ``addparam``
1069 # make it an immutable tuple to force people through ``addparam``
1070 return tuple(self._advisoryparams)
1070 return tuple(self._advisoryparams)
1071
1071
1072 def addparam(self, name, value=b'', mandatory=True):
1072 def addparam(self, name, value=b'', mandatory=True):
1073 """add a parameter to the part
1073 """add a parameter to the part
1074
1074
1075 If 'mandatory' is set to True, the remote handler must claim support
1075 If 'mandatory' is set to True, the remote handler must claim support
1076 for this parameter or the unbundling will be aborted.
1076 for this parameter or the unbundling will be aborted.
1077
1077
1078 The 'name' and 'value' cannot exceed 255 bytes each.
1078 The 'name' and 'value' cannot exceed 255 bytes each.
1079 """
1079 """
1080 if self._generated is not None:
1080 if self._generated is not None:
1081 raise error.ReadOnlyPartError(b'part is being generated')
1081 raise error.ReadOnlyPartError(b'part is being generated')
1082 if name in self._seenparams:
1082 if name in self._seenparams:
1083 raise ValueError(b'duplicated params: %s' % name)
1083 raise ValueError(b'duplicated params: %s' % name)
1084 self._seenparams.add(name)
1084 self._seenparams.add(name)
1085 params = self._advisoryparams
1085 params = self._advisoryparams
1086 if mandatory:
1086 if mandatory:
1087 params = self._mandatoryparams
1087 params = self._mandatoryparams
1088 params.append((name, value))
1088 params.append((name, value))
1089
1089
1090 # methods used to generates the bundle2 stream
1090 # methods used to generates the bundle2 stream
1091 def getchunks(self, ui):
1091 def getchunks(self, ui):
1092 if self._generated is not None:
1092 if self._generated is not None:
1093 raise error.ProgrammingError(b'part can only be consumed once')
1093 raise error.ProgrammingError(b'part can only be consumed once')
1094 self._generated = False
1094 self._generated = False
1095
1095
1096 if ui.debugflag:
1096 if ui.debugflag:
1097 msg = [b'bundle2-output-part: "%s"' % self.type]
1097 msg = [b'bundle2-output-part: "%s"' % self.type]
1098 if not self.mandatory:
1098 if not self.mandatory:
1099 msg.append(b' (advisory)')
1099 msg.append(b' (advisory)')
1100 nbmp = len(self.mandatoryparams)
1100 nbmp = len(self.mandatoryparams)
1101 nbap = len(self.advisoryparams)
1101 nbap = len(self.advisoryparams)
1102 if nbmp or nbap:
1102 if nbmp or nbap:
1103 msg.append(b' (params:')
1103 msg.append(b' (params:')
1104 if nbmp:
1104 if nbmp:
1105 msg.append(b' %i mandatory' % nbmp)
1105 msg.append(b' %i mandatory' % nbmp)
1106 if nbap:
1106 if nbap:
1107 msg.append(b' %i advisory' % nbmp)
1107 msg.append(b' %i advisory' % nbmp)
1108 msg.append(b')')
1108 msg.append(b')')
1109 if not self.data:
1109 if not self.data:
1110 msg.append(b' empty payload')
1110 msg.append(b' empty payload')
1111 elif util.safehasattr(self.data, 'next') or util.safehasattr(
1111 elif util.safehasattr(self.data, 'next') or util.safehasattr(
1112 self.data, b'__next__'
1112 self.data, b'__next__'
1113 ):
1113 ):
1114 msg.append(b' streamed payload')
1114 msg.append(b' streamed payload')
1115 else:
1115 else:
1116 msg.append(b' %i bytes payload' % len(self.data))
1116 msg.append(b' %i bytes payload' % len(self.data))
1117 msg.append(b'\n')
1117 msg.append(b'\n')
1118 ui.debug(b''.join(msg))
1118 ui.debug(b''.join(msg))
1119
1119
1120 #### header
1120 #### header
1121 if self.mandatory:
1121 if self.mandatory:
1122 parttype = self.type.upper()
1122 parttype = self.type.upper()
1123 else:
1123 else:
1124 parttype = self.type.lower()
1124 parttype = self.type.lower()
1125 outdebug(ui, b'part %s: "%s"' % (pycompat.bytestr(self.id), parttype))
1125 outdebug(ui, b'part %s: "%s"' % (pycompat.bytestr(self.id), parttype))
1126 ## parttype
1126 ## parttype
1127 header = [
1127 header = [
1128 _pack(_fparttypesize, len(parttype)),
1128 _pack(_fparttypesize, len(parttype)),
1129 parttype,
1129 parttype,
1130 _pack(_fpartid, self.id),
1130 _pack(_fpartid, self.id),
1131 ]
1131 ]
1132 ## parameters
1132 ## parameters
1133 # count
1133 # count
1134 manpar = self.mandatoryparams
1134 manpar = self.mandatoryparams
1135 advpar = self.advisoryparams
1135 advpar = self.advisoryparams
1136 header.append(_pack(_fpartparamcount, len(manpar), len(advpar)))
1136 header.append(_pack(_fpartparamcount, len(manpar), len(advpar)))
1137 # size
1137 # size
1138 parsizes = []
1138 parsizes = []
1139 for key, value in manpar:
1139 for key, value in manpar:
1140 parsizes.append(len(key))
1140 parsizes.append(len(key))
1141 parsizes.append(len(value))
1141 parsizes.append(len(value))
1142 for key, value in advpar:
1142 for key, value in advpar:
1143 parsizes.append(len(key))
1143 parsizes.append(len(key))
1144 parsizes.append(len(value))
1144 parsizes.append(len(value))
1145 paramsizes = _pack(_makefpartparamsizes(len(parsizes) // 2), *parsizes)
1145 paramsizes = _pack(_makefpartparamsizes(len(parsizes) // 2), *parsizes)
1146 header.append(paramsizes)
1146 header.append(paramsizes)
1147 # key, value
1147 # key, value
1148 for key, value in manpar:
1148 for key, value in manpar:
1149 header.append(key)
1149 header.append(key)
1150 header.append(value)
1150 header.append(value)
1151 for key, value in advpar:
1151 for key, value in advpar:
1152 header.append(key)
1152 header.append(key)
1153 header.append(value)
1153 header.append(value)
1154 ## finalize header
1154 ## finalize header
1155 try:
1155 try:
1156 headerchunk = b''.join(header)
1156 headerchunk = b''.join(header)
1157 except TypeError:
1157 except TypeError:
1158 raise TypeError(
1158 raise TypeError(
1159 'Found a non-bytes trying to '
1159 'Found a non-bytes trying to '
1160 'build bundle part header: %r' % header
1160 'build bundle part header: %r' % header
1161 )
1161 )
1162 outdebug(ui, b'header chunk size: %i' % len(headerchunk))
1162 outdebug(ui, b'header chunk size: %i' % len(headerchunk))
1163 yield _pack(_fpartheadersize, len(headerchunk))
1163 yield _pack(_fpartheadersize, len(headerchunk))
1164 yield headerchunk
1164 yield headerchunk
1165 ## payload
1165 ## payload
1166 try:
1166 try:
1167 for chunk in self._payloadchunks():
1167 for chunk in self._payloadchunks():
1168 outdebug(ui, b'payload chunk size: %i' % len(chunk))
1168 outdebug(ui, b'payload chunk size: %i' % len(chunk))
1169 yield _pack(_fpayloadsize, len(chunk))
1169 yield _pack(_fpayloadsize, len(chunk))
1170 yield chunk
1170 yield chunk
1171 except GeneratorExit:
1171 except GeneratorExit:
1172 # GeneratorExit means that nobody is listening for our
1172 # GeneratorExit means that nobody is listening for our
1173 # results anyway, so just bail quickly rather than trying
1173 # results anyway, so just bail quickly rather than trying
1174 # to produce an error part.
1174 # to produce an error part.
1175 ui.debug(b'bundle2-generatorexit\n')
1175 ui.debug(b'bundle2-generatorexit\n')
1176 raise
1176 raise
1177 except BaseException as exc:
1177 except BaseException as exc:
1178 bexc = stringutil.forcebytestr(exc)
1178 bexc = stringutil.forcebytestr(exc)
1179 # backup exception data for later
1179 # backup exception data for later
1180 ui.debug(
1180 ui.debug(
1181 b'bundle2-input-stream-interrupt: encoding exception %s' % bexc
1181 b'bundle2-input-stream-interrupt: encoding exception %s' % bexc
1182 )
1182 )
1183 tb = sys.exc_info()[2]
1183 tb = sys.exc_info()[2]
1184 msg = b'unexpected error: %s' % bexc
1184 msg = b'unexpected error: %s' % bexc
1185 interpart = bundlepart(
1185 interpart = bundlepart(
1186 b'error:abort', [(b'message', msg)], mandatory=False
1186 b'error:abort', [(b'message', msg)], mandatory=False
1187 )
1187 )
1188 interpart.id = 0
1188 interpart.id = 0
1189 yield _pack(_fpayloadsize, -1)
1189 yield _pack(_fpayloadsize, -1)
1190 for chunk in interpart.getchunks(ui=ui):
1190 for chunk in interpart.getchunks(ui=ui):
1191 yield chunk
1191 yield chunk
1192 outdebug(ui, b'closing payload chunk')
1192 outdebug(ui, b'closing payload chunk')
1193 # abort current part payload
1193 # abort current part payload
1194 yield _pack(_fpayloadsize, 0)
1194 yield _pack(_fpayloadsize, 0)
1195 pycompat.raisewithtb(exc, tb)
1195 pycompat.raisewithtb(exc, tb)
1196 # end of payload
1196 # end of payload
1197 outdebug(ui, b'closing payload chunk')
1197 outdebug(ui, b'closing payload chunk')
1198 yield _pack(_fpayloadsize, 0)
1198 yield _pack(_fpayloadsize, 0)
1199 self._generated = True
1199 self._generated = True
1200
1200
1201 def _payloadchunks(self):
1201 def _payloadchunks(self):
1202 """yield chunks of a the part payload
1202 """yield chunks of a the part payload
1203
1203
1204 Exists to handle the different methods to provide data to a part."""
1204 Exists to handle the different methods to provide data to a part."""
1205 # we only support fixed size data now.
1205 # we only support fixed size data now.
1206 # This will be improved in the future.
1206 # This will be improved in the future.
1207 if util.safehasattr(self.data, 'next') or util.safehasattr(
1207 if util.safehasattr(self.data, 'next') or util.safehasattr(
1208 self.data, b'__next__'
1208 self.data, b'__next__'
1209 ):
1209 ):
1210 buff = util.chunkbuffer(self.data)
1210 buff = util.chunkbuffer(self.data)
1211 chunk = buff.read(preferedchunksize)
1211 chunk = buff.read(preferedchunksize)
1212 while chunk:
1212 while chunk:
1213 yield chunk
1213 yield chunk
1214 chunk = buff.read(preferedchunksize)
1214 chunk = buff.read(preferedchunksize)
1215 elif len(self.data):
1215 elif len(self.data):
1216 yield self.data
1216 yield self.data
1217
1217
1218
1218
1219 flaginterrupt = -1
1219 flaginterrupt = -1
1220
1220
1221
1221
1222 class interrupthandler(unpackermixin):
1222 class interrupthandler(unpackermixin):
1223 """read one part and process it with restricted capability
1223 """read one part and process it with restricted capability
1224
1224
1225 This allows to transmit exception raised on the producer size during part
1225 This allows to transmit exception raised on the producer size during part
1226 iteration while the consumer is reading a part.
1226 iteration while the consumer is reading a part.
1227
1227
1228 Part processed in this manner only have access to a ui object,"""
1228 Part processed in this manner only have access to a ui object,"""
1229
1229
1230 def __init__(self, ui, fp):
1230 def __init__(self, ui, fp):
1231 super(interrupthandler, self).__init__(fp)
1231 super(interrupthandler, self).__init__(fp)
1232 self.ui = ui
1232 self.ui = ui
1233
1233
1234 def _readpartheader(self):
1234 def _readpartheader(self):
1235 """reads a part header size and return the bytes blob
1235 """reads a part header size and return the bytes blob
1236
1236
1237 returns None if empty"""
1237 returns None if empty"""
1238 headersize = self._unpack(_fpartheadersize)[0]
1238 headersize = self._unpack(_fpartheadersize)[0]
1239 if headersize < 0:
1239 if headersize < 0:
1240 raise error.BundleValueError(
1240 raise error.BundleValueError(
1241 b'negative part header size: %i' % headersize
1241 b'negative part header size: %i' % headersize
1242 )
1242 )
1243 indebug(self.ui, b'part header size: %i\n' % headersize)
1243 indebug(self.ui, b'part header size: %i\n' % headersize)
1244 if headersize:
1244 if headersize:
1245 return self._readexact(headersize)
1245 return self._readexact(headersize)
1246 return None
1246 return None
1247
1247
1248 def __call__(self):
1248 def __call__(self):
1249
1249
1250 self.ui.debug(
1250 self.ui.debug(
1251 b'bundle2-input-stream-interrupt: opening out of band context\n'
1251 b'bundle2-input-stream-interrupt: opening out of band context\n'
1252 )
1252 )
1253 indebug(self.ui, b'bundle2 stream interruption, looking for a part.')
1253 indebug(self.ui, b'bundle2 stream interruption, looking for a part.')
1254 headerblock = self._readpartheader()
1254 headerblock = self._readpartheader()
1255 if headerblock is None:
1255 if headerblock is None:
1256 indebug(self.ui, b'no part found during interruption.')
1256 indebug(self.ui, b'no part found during interruption.')
1257 return
1257 return
1258 part = unbundlepart(self.ui, headerblock, self._fp)
1258 part = unbundlepart(self.ui, headerblock, self._fp)
1259 op = interruptoperation(self.ui)
1259 op = interruptoperation(self.ui)
1260 hardabort = False
1260 hardabort = False
1261 try:
1261 try:
1262 _processpart(op, part)
1262 _processpart(op, part)
1263 except (SystemExit, KeyboardInterrupt):
1263 except (SystemExit, KeyboardInterrupt):
1264 hardabort = True
1264 hardabort = True
1265 raise
1265 raise
1266 finally:
1266 finally:
1267 if not hardabort:
1267 if not hardabort:
1268 part.consume()
1268 part.consume()
1269 self.ui.debug(
1269 self.ui.debug(
1270 b'bundle2-input-stream-interrupt: closing out of band context\n'
1270 b'bundle2-input-stream-interrupt: closing out of band context\n'
1271 )
1271 )
1272
1272
1273
1273
1274 class interruptoperation(object):
1274 class interruptoperation(object):
1275 """A limited operation to be use by part handler during interruption
1275 """A limited operation to be use by part handler during interruption
1276
1276
1277 It only have access to an ui object.
1277 It only have access to an ui object.
1278 """
1278 """
1279
1279
1280 def __init__(self, ui):
1280 def __init__(self, ui):
1281 self.ui = ui
1281 self.ui = ui
1282 self.reply = None
1282 self.reply = None
1283 self.captureoutput = False
1283 self.captureoutput = False
1284
1284
1285 @property
1285 @property
1286 def repo(self):
1286 def repo(self):
1287 raise error.ProgrammingError(b'no repo access from stream interruption')
1287 raise error.ProgrammingError(b'no repo access from stream interruption')
1288
1288
1289 def gettransaction(self):
1289 def gettransaction(self):
1290 raise TransactionUnavailable(b'no repo access from stream interruption')
1290 raise TransactionUnavailable(b'no repo access from stream interruption')
1291
1291
1292
1292
1293 def decodepayloadchunks(ui, fh):
1293 def decodepayloadchunks(ui, fh):
1294 """Reads bundle2 part payload data into chunks.
1294 """Reads bundle2 part payload data into chunks.
1295
1295
1296 Part payload data consists of framed chunks. This function takes
1296 Part payload data consists of framed chunks. This function takes
1297 a file handle and emits those chunks.
1297 a file handle and emits those chunks.
1298 """
1298 """
1299 dolog = ui.configbool(b'devel', b'bundle2.debug')
1299 dolog = ui.configbool(b'devel', b'bundle2.debug')
1300 debug = ui.debug
1300 debug = ui.debug
1301
1301
1302 headerstruct = struct.Struct(_fpayloadsize)
1302 headerstruct = struct.Struct(_fpayloadsize)
1303 headersize = headerstruct.size
1303 headersize = headerstruct.size
1304 unpack = headerstruct.unpack
1304 unpack = headerstruct.unpack
1305
1305
1306 readexactly = changegroup.readexactly
1306 readexactly = changegroup.readexactly
1307 read = fh.read
1307 read = fh.read
1308
1308
1309 chunksize = unpack(readexactly(fh, headersize))[0]
1309 chunksize = unpack(readexactly(fh, headersize))[0]
1310 indebug(ui, b'payload chunk size: %i' % chunksize)
1310 indebug(ui, b'payload chunk size: %i' % chunksize)
1311
1311
1312 # changegroup.readexactly() is inlined below for performance.
1312 # changegroup.readexactly() is inlined below for performance.
1313 while chunksize:
1313 while chunksize:
1314 if chunksize >= 0:
1314 if chunksize >= 0:
1315 s = read(chunksize)
1315 s = read(chunksize)
1316 if len(s) < chunksize:
1316 if len(s) < chunksize:
1317 raise error.Abort(
1317 raise error.Abort(
1318 _(
1318 _(
1319 b'stream ended unexpectedly '
1319 b'stream ended unexpectedly '
1320 b' (got %d bytes, expected %d)'
1320 b' (got %d bytes, expected %d)'
1321 )
1321 )
1322 % (len(s), chunksize)
1322 % (len(s), chunksize)
1323 )
1323 )
1324
1324
1325 yield s
1325 yield s
1326 elif chunksize == flaginterrupt:
1326 elif chunksize == flaginterrupt:
1327 # Interrupt "signal" detected. The regular stream is interrupted
1327 # Interrupt "signal" detected. The regular stream is interrupted
1328 # and a bundle2 part follows. Consume it.
1328 # and a bundle2 part follows. Consume it.
1329 interrupthandler(ui, fh)()
1329 interrupthandler(ui, fh)()
1330 else:
1330 else:
1331 raise error.BundleValueError(
1331 raise error.BundleValueError(
1332 b'negative payload chunk size: %s' % chunksize
1332 b'negative payload chunk size: %s' % chunksize
1333 )
1333 )
1334
1334
1335 s = read(headersize)
1335 s = read(headersize)
1336 if len(s) < headersize:
1336 if len(s) < headersize:
1337 raise error.Abort(
1337 raise error.Abort(
1338 _(b'stream ended unexpectedly (got %d bytes, expected %d)')
1338 _(b'stream ended unexpectedly (got %d bytes, expected %d)')
1339 % (len(s), chunksize)
1339 % (len(s), chunksize)
1340 )
1340 )
1341
1341
1342 chunksize = unpack(s)[0]
1342 chunksize = unpack(s)[0]
1343
1343
1344 # indebug() inlined for performance.
1344 # indebug() inlined for performance.
1345 if dolog:
1345 if dolog:
1346 debug(b'bundle2-input: payload chunk size: %i\n' % chunksize)
1346 debug(b'bundle2-input: payload chunk size: %i\n' % chunksize)
1347
1347
1348
1348
1349 class unbundlepart(unpackermixin):
1349 class unbundlepart(unpackermixin):
1350 """a bundle part read from a bundle"""
1350 """a bundle part read from a bundle"""
1351
1351
1352 def __init__(self, ui, header, fp):
1352 def __init__(self, ui, header, fp):
1353 super(unbundlepart, self).__init__(fp)
1353 super(unbundlepart, self).__init__(fp)
1354 self._seekable = util.safehasattr(fp, 'seek') and util.safehasattr(
1354 self._seekable = util.safehasattr(fp, 'seek') and util.safehasattr(
1355 fp, b'tell'
1355 fp, b'tell'
1356 )
1356 )
1357 self.ui = ui
1357 self.ui = ui
1358 # unbundle state attr
1358 # unbundle state attr
1359 self._headerdata = header
1359 self._headerdata = header
1360 self._headeroffset = 0
1360 self._headeroffset = 0
1361 self._initialized = False
1361 self._initialized = False
1362 self.consumed = False
1362 self.consumed = False
1363 # part data
1363 # part data
1364 self.id = None
1364 self.id = None
1365 self.type = None
1365 self.type = None
1366 self.mandatoryparams = None
1366 self.mandatoryparams = None
1367 self.advisoryparams = None
1367 self.advisoryparams = None
1368 self.params = None
1368 self.params = None
1369 self.mandatorykeys = ()
1369 self.mandatorykeys = ()
1370 self._readheader()
1370 self._readheader()
1371 self._mandatory = None
1371 self._mandatory = None
1372 self._pos = 0
1372 self._pos = 0
1373
1373
1374 def _fromheader(self, size):
1374 def _fromheader(self, size):
1375 """return the next <size> byte from the header"""
1375 """return the next <size> byte from the header"""
1376 offset = self._headeroffset
1376 offset = self._headeroffset
1377 data = self._headerdata[offset : (offset + size)]
1377 data = self._headerdata[offset : (offset + size)]
1378 self._headeroffset = offset + size
1378 self._headeroffset = offset + size
1379 return data
1379 return data
1380
1380
1381 def _unpackheader(self, format):
1381 def _unpackheader(self, format):
1382 """read given format from header
1382 """read given format from header
1383
1383
1384 This automatically compute the size of the format to read."""
1384 This automatically compute the size of the format to read."""
1385 data = self._fromheader(struct.calcsize(format))
1385 data = self._fromheader(struct.calcsize(format))
1386 return _unpack(format, data)
1386 return _unpack(format, data)
1387
1387
1388 def _initparams(self, mandatoryparams, advisoryparams):
1388 def _initparams(self, mandatoryparams, advisoryparams):
1389 """internal function to setup all logic related parameters"""
1389 """internal function to setup all logic related parameters"""
1390 # make it read only to prevent people touching it by mistake.
1390 # make it read only to prevent people touching it by mistake.
1391 self.mandatoryparams = tuple(mandatoryparams)
1391 self.mandatoryparams = tuple(mandatoryparams)
1392 self.advisoryparams = tuple(advisoryparams)
1392 self.advisoryparams = tuple(advisoryparams)
1393 # user friendly UI
1393 # user friendly UI
1394 self.params = util.sortdict(self.mandatoryparams)
1394 self.params = util.sortdict(self.mandatoryparams)
1395 self.params.update(self.advisoryparams)
1395 self.params.update(self.advisoryparams)
1396 self.mandatorykeys = frozenset(p[0] for p in mandatoryparams)
1396 self.mandatorykeys = frozenset(p[0] for p in mandatoryparams)
1397
1397
1398 def _readheader(self):
1398 def _readheader(self):
1399 """read the header and setup the object"""
1399 """read the header and setup the object"""
1400 typesize = self._unpackheader(_fparttypesize)[0]
1400 typesize = self._unpackheader(_fparttypesize)[0]
1401 self.type = self._fromheader(typesize)
1401 self.type = self._fromheader(typesize)
1402 indebug(self.ui, b'part type: "%s"' % self.type)
1402 indebug(self.ui, b'part type: "%s"' % self.type)
1403 self.id = self._unpackheader(_fpartid)[0]
1403 self.id = self._unpackheader(_fpartid)[0]
1404 indebug(self.ui, b'part id: "%s"' % pycompat.bytestr(self.id))
1404 indebug(self.ui, b'part id: "%s"' % pycompat.bytestr(self.id))
1405 # extract mandatory bit from type
1405 # extract mandatory bit from type
1406 self.mandatory = self.type != self.type.lower()
1406 self.mandatory = self.type != self.type.lower()
1407 self.type = self.type.lower()
1407 self.type = self.type.lower()
1408 ## reading parameters
1408 ## reading parameters
1409 # param count
1409 # param count
1410 mancount, advcount = self._unpackheader(_fpartparamcount)
1410 mancount, advcount = self._unpackheader(_fpartparamcount)
1411 indebug(self.ui, b'part parameters: %i' % (mancount + advcount))
1411 indebug(self.ui, b'part parameters: %i' % (mancount + advcount))
1412 # param size
1412 # param size
1413 fparamsizes = _makefpartparamsizes(mancount + advcount)
1413 fparamsizes = _makefpartparamsizes(mancount + advcount)
1414 paramsizes = self._unpackheader(fparamsizes)
1414 paramsizes = self._unpackheader(fparamsizes)
1415 # make it a list of couple again
1415 # make it a list of couple again
1416 paramsizes = list(zip(paramsizes[::2], paramsizes[1::2]))
1416 paramsizes = list(zip(paramsizes[::2], paramsizes[1::2]))
1417 # split mandatory from advisory
1417 # split mandatory from advisory
1418 mansizes = paramsizes[:mancount]
1418 mansizes = paramsizes[:mancount]
1419 advsizes = paramsizes[mancount:]
1419 advsizes = paramsizes[mancount:]
1420 # retrieve param value
1420 # retrieve param value
1421 manparams = []
1421 manparams = []
1422 for key, value in mansizes:
1422 for key, value in mansizes:
1423 manparams.append((self._fromheader(key), self._fromheader(value)))
1423 manparams.append((self._fromheader(key), self._fromheader(value)))
1424 advparams = []
1424 advparams = []
1425 for key, value in advsizes:
1425 for key, value in advsizes:
1426 advparams.append((self._fromheader(key), self._fromheader(value)))
1426 advparams.append((self._fromheader(key), self._fromheader(value)))
1427 self._initparams(manparams, advparams)
1427 self._initparams(manparams, advparams)
1428 ## part payload
1428 ## part payload
1429 self._payloadstream = util.chunkbuffer(self._payloadchunks())
1429 self._payloadstream = util.chunkbuffer(self._payloadchunks())
1430 # we read the data, tell it
1430 # we read the data, tell it
1431 self._initialized = True
1431 self._initialized = True
1432
1432
1433 def _payloadchunks(self):
1433 def _payloadchunks(self):
1434 """Generator of decoded chunks in the payload."""
1434 """Generator of decoded chunks in the payload."""
1435 return decodepayloadchunks(self.ui, self._fp)
1435 return decodepayloadchunks(self.ui, self._fp)
1436
1436
1437 def consume(self):
1437 def consume(self):
1438 """Read the part payload until completion.
1438 """Read the part payload until completion.
1439
1439
1440 By consuming the part data, the underlying stream read offset will
1440 By consuming the part data, the underlying stream read offset will
1441 be advanced to the next part (or end of stream).
1441 be advanced to the next part (or end of stream).
1442 """
1442 """
1443 if self.consumed:
1443 if self.consumed:
1444 return
1444 return
1445
1445
1446 chunk = self.read(32768)
1446 chunk = self.read(32768)
1447 while chunk:
1447 while chunk:
1448 self._pos += len(chunk)
1448 self._pos += len(chunk)
1449 chunk = self.read(32768)
1449 chunk = self.read(32768)
1450
1450
1451 def read(self, size=None):
1451 def read(self, size=None):
1452 """read payload data"""
1452 """read payload data"""
1453 if not self._initialized:
1453 if not self._initialized:
1454 self._readheader()
1454 self._readheader()
1455 if size is None:
1455 if size is None:
1456 data = self._payloadstream.read()
1456 data = self._payloadstream.read()
1457 else:
1457 else:
1458 data = self._payloadstream.read(size)
1458 data = self._payloadstream.read(size)
1459 self._pos += len(data)
1459 self._pos += len(data)
1460 if size is None or len(data) < size:
1460 if size is None or len(data) < size:
1461 if not self.consumed and self._pos:
1461 if not self.consumed and self._pos:
1462 self.ui.debug(
1462 self.ui.debug(
1463 b'bundle2-input-part: total payload size %i\n' % self._pos
1463 b'bundle2-input-part: total payload size %i\n' % self._pos
1464 )
1464 )
1465 self.consumed = True
1465 self.consumed = True
1466 return data
1466 return data
1467
1467
1468
1468
1469 class seekableunbundlepart(unbundlepart):
1469 class seekableunbundlepart(unbundlepart):
1470 """A bundle2 part in a bundle that is seekable.
1470 """A bundle2 part in a bundle that is seekable.
1471
1471
1472 Regular ``unbundlepart`` instances can only be read once. This class
1472 Regular ``unbundlepart`` instances can only be read once. This class
1473 extends ``unbundlepart`` to enable bi-directional seeking within the
1473 extends ``unbundlepart`` to enable bi-directional seeking within the
1474 part.
1474 part.
1475
1475
1476 Bundle2 part data consists of framed chunks. Offsets when seeking
1476 Bundle2 part data consists of framed chunks. Offsets when seeking
1477 refer to the decoded data, not the offsets in the underlying bundle2
1477 refer to the decoded data, not the offsets in the underlying bundle2
1478 stream.
1478 stream.
1479
1479
1480 To facilitate quickly seeking within the decoded data, instances of this
1480 To facilitate quickly seeking within the decoded data, instances of this
1481 class maintain a mapping between offsets in the underlying stream and
1481 class maintain a mapping between offsets in the underlying stream and
1482 the decoded payload. This mapping will consume memory in proportion
1482 the decoded payload. This mapping will consume memory in proportion
1483 to the number of chunks within the payload (which almost certainly
1483 to the number of chunks within the payload (which almost certainly
1484 increases in proportion with the size of the part).
1484 increases in proportion with the size of the part).
1485 """
1485 """
1486
1486
1487 def __init__(self, ui, header, fp):
1487 def __init__(self, ui, header, fp):
1488 # (payload, file) offsets for chunk starts.
1488 # (payload, file) offsets for chunk starts.
1489 self._chunkindex = []
1489 self._chunkindex = []
1490
1490
1491 super(seekableunbundlepart, self).__init__(ui, header, fp)
1491 super(seekableunbundlepart, self).__init__(ui, header, fp)
1492
1492
1493 def _payloadchunks(self, chunknum=0):
1493 def _payloadchunks(self, chunknum=0):
1494 '''seek to specified chunk and start yielding data'''
1494 '''seek to specified chunk and start yielding data'''
1495 if len(self._chunkindex) == 0:
1495 if len(self._chunkindex) == 0:
1496 assert chunknum == 0, b'Must start with chunk 0'
1496 assert chunknum == 0, b'Must start with chunk 0'
1497 self._chunkindex.append((0, self._tellfp()))
1497 self._chunkindex.append((0, self._tellfp()))
1498 else:
1498 else:
1499 assert chunknum < len(self._chunkindex), (
1499 assert chunknum < len(self._chunkindex), (
1500 b'Unknown chunk %d' % chunknum
1500 b'Unknown chunk %d' % chunknum
1501 )
1501 )
1502 self._seekfp(self._chunkindex[chunknum][1])
1502 self._seekfp(self._chunkindex[chunknum][1])
1503
1503
1504 pos = self._chunkindex[chunknum][0]
1504 pos = self._chunkindex[chunknum][0]
1505
1505
1506 for chunk in decodepayloadchunks(self.ui, self._fp):
1506 for chunk in decodepayloadchunks(self.ui, self._fp):
1507 chunknum += 1
1507 chunknum += 1
1508 pos += len(chunk)
1508 pos += len(chunk)
1509 if chunknum == len(self._chunkindex):
1509 if chunknum == len(self._chunkindex):
1510 self._chunkindex.append((pos, self._tellfp()))
1510 self._chunkindex.append((pos, self._tellfp()))
1511
1511
1512 yield chunk
1512 yield chunk
1513
1513
1514 def _findchunk(self, pos):
1514 def _findchunk(self, pos):
1515 '''for a given payload position, return a chunk number and offset'''
1515 '''for a given payload position, return a chunk number and offset'''
1516 for chunk, (ppos, fpos) in enumerate(self._chunkindex):
1516 for chunk, (ppos, fpos) in enumerate(self._chunkindex):
1517 if ppos == pos:
1517 if ppos == pos:
1518 return chunk, 0
1518 return chunk, 0
1519 elif ppos > pos:
1519 elif ppos > pos:
1520 return chunk - 1, pos - self._chunkindex[chunk - 1][0]
1520 return chunk - 1, pos - self._chunkindex[chunk - 1][0]
1521 raise ValueError(b'Unknown chunk')
1521 raise ValueError(b'Unknown chunk')
1522
1522
1523 def tell(self):
1523 def tell(self):
1524 return self._pos
1524 return self._pos
1525
1525
1526 def seek(self, offset, whence=os.SEEK_SET):
1526 def seek(self, offset, whence=os.SEEK_SET):
1527 if whence == os.SEEK_SET:
1527 if whence == os.SEEK_SET:
1528 newpos = offset
1528 newpos = offset
1529 elif whence == os.SEEK_CUR:
1529 elif whence == os.SEEK_CUR:
1530 newpos = self._pos + offset
1530 newpos = self._pos + offset
1531 elif whence == os.SEEK_END:
1531 elif whence == os.SEEK_END:
1532 if not self.consumed:
1532 if not self.consumed:
1533 # Can't use self.consume() here because it advances self._pos.
1533 # Can't use self.consume() here because it advances self._pos.
1534 chunk = self.read(32768)
1534 chunk = self.read(32768)
1535 while chunk:
1535 while chunk:
1536 chunk = self.read(32768)
1536 chunk = self.read(32768)
1537 newpos = self._chunkindex[-1][0] - offset
1537 newpos = self._chunkindex[-1][0] - offset
1538 else:
1538 else:
1539 raise ValueError(b'Unknown whence value: %r' % (whence,))
1539 raise ValueError(b'Unknown whence value: %r' % (whence,))
1540
1540
1541 if newpos > self._chunkindex[-1][0] and not self.consumed:
1541 if newpos > self._chunkindex[-1][0] and not self.consumed:
1542 # Can't use self.consume() here because it advances self._pos.
1542 # Can't use self.consume() here because it advances self._pos.
1543 chunk = self.read(32768)
1543 chunk = self.read(32768)
1544 while chunk:
1544 while chunk:
1545 chunk = self.read(32668)
1545 chunk = self.read(32668)
1546
1546
1547 if not 0 <= newpos <= self._chunkindex[-1][0]:
1547 if not 0 <= newpos <= self._chunkindex[-1][0]:
1548 raise ValueError(b'Offset out of range')
1548 raise ValueError(b'Offset out of range')
1549
1549
1550 if self._pos != newpos:
1550 if self._pos != newpos:
1551 chunk, internaloffset = self._findchunk(newpos)
1551 chunk, internaloffset = self._findchunk(newpos)
1552 self._payloadstream = util.chunkbuffer(self._payloadchunks(chunk))
1552 self._payloadstream = util.chunkbuffer(self._payloadchunks(chunk))
1553 adjust = self.read(internaloffset)
1553 adjust = self.read(internaloffset)
1554 if len(adjust) != internaloffset:
1554 if len(adjust) != internaloffset:
1555 raise error.Abort(_(b'Seek failed\n'))
1555 raise error.Abort(_(b'Seek failed\n'))
1556 self._pos = newpos
1556 self._pos = newpos
1557
1557
1558 def _seekfp(self, offset, whence=0):
1558 def _seekfp(self, offset, whence=0):
1559 """move the underlying file pointer
1559 """move the underlying file pointer
1560
1560
1561 This method is meant for internal usage by the bundle2 protocol only.
1561 This method is meant for internal usage by the bundle2 protocol only.
1562 They directly manipulate the low level stream including bundle2 level
1562 They directly manipulate the low level stream including bundle2 level
1563 instruction.
1563 instruction.
1564
1564
1565 Do not use it to implement higher-level logic or methods."""
1565 Do not use it to implement higher-level logic or methods."""
1566 if self._seekable:
1566 if self._seekable:
1567 return self._fp.seek(offset, whence)
1567 return self._fp.seek(offset, whence)
1568 else:
1568 else:
1569 raise NotImplementedError(_(b'File pointer is not seekable'))
1569 raise NotImplementedError(_(b'File pointer is not seekable'))
1570
1570
1571 def _tellfp(self):
1571 def _tellfp(self):
1572 """return the file offset, or None if file is not seekable
1572 """return the file offset, or None if file is not seekable
1573
1573
1574 This method is meant for internal usage by the bundle2 protocol only.
1574 This method is meant for internal usage by the bundle2 protocol only.
1575 They directly manipulate the low level stream including bundle2 level
1575 They directly manipulate the low level stream including bundle2 level
1576 instruction.
1576 instruction.
1577
1577
1578 Do not use it to implement higher-level logic or methods."""
1578 Do not use it to implement higher-level logic or methods."""
1579 if self._seekable:
1579 if self._seekable:
1580 try:
1580 try:
1581 return self._fp.tell()
1581 return self._fp.tell()
1582 except IOError as e:
1582 except IOError as e:
1583 if e.errno == errno.ESPIPE:
1583 if e.errno == errno.ESPIPE:
1584 self._seekable = False
1584 self._seekable = False
1585 else:
1585 else:
1586 raise
1586 raise
1587 return None
1587 return None
1588
1588
1589
1589
1590 # These are only the static capabilities.
1590 # These are only the static capabilities.
1591 # Check the 'getrepocaps' function for the rest.
1591 # Check the 'getrepocaps' function for the rest.
1592 capabilities = {
1592 capabilities = {
1593 b'HG20': (),
1593 b'HG20': (),
1594 b'bookmarks': (),
1594 b'bookmarks': (),
1595 b'error': (b'abort', b'unsupportedcontent', b'pushraced', b'pushkey'),
1595 b'error': (b'abort', b'unsupportedcontent', b'pushraced', b'pushkey'),
1596 b'listkeys': (),
1596 b'listkeys': (),
1597 b'pushkey': (),
1597 b'pushkey': (),
1598 b'digests': tuple(sorted(util.DIGESTS.keys())),
1598 b'digests': tuple(sorted(util.DIGESTS.keys())),
1599 b'remote-changegroup': (b'http', b'https'),
1599 b'remote-changegroup': (b'http', b'https'),
1600 b'hgtagsfnodes': (),
1600 b'hgtagsfnodes': (),
1601 b'rev-branch-cache': (),
1601 b'rev-branch-cache': (),
1602 b'phases': (b'heads',),
1602 b'phases': (b'heads',),
1603 b'stream': (b'v2',),
1603 b'stream': (b'v2',),
1604 }
1604 }
1605
1605
1606
1606
1607 def getrepocaps(repo, allowpushback=False, role=None):
1607 def getrepocaps(repo, allowpushback=False, role=None):
1608 """return the bundle2 capabilities for a given repo
1608 """return the bundle2 capabilities for a given repo
1609
1609
1610 Exists to allow extensions (like evolution) to mutate the capabilities.
1610 Exists to allow extensions (like evolution) to mutate the capabilities.
1611
1611
1612 The returned value is used for servers advertising their capabilities as
1612 The returned value is used for servers advertising their capabilities as
1613 well as clients advertising their capabilities to servers as part of
1613 well as clients advertising their capabilities to servers as part of
1614 bundle2 requests. The ``role`` argument specifies which is which.
1614 bundle2 requests. The ``role`` argument specifies which is which.
1615 """
1615 """
1616 if role not in (b'client', b'server'):
1616 if role not in (b'client', b'server'):
1617 raise error.ProgrammingError(b'role argument must be client or server')
1617 raise error.ProgrammingError(b'role argument must be client or server')
1618
1618
1619 caps = capabilities.copy()
1619 caps = capabilities.copy()
1620 caps[b'changegroup'] = tuple(
1620 caps[b'changegroup'] = tuple(
1621 sorted(changegroup.supportedincomingversions(repo))
1621 sorted(changegroup.supportedincomingversions(repo))
1622 )
1622 )
1623 if obsolete.isenabled(repo, obsolete.exchangeopt):
1623 if obsolete.isenabled(repo, obsolete.exchangeopt):
1624 supportedformat = tuple(b'V%i' % v for v in obsolete.formats)
1624 supportedformat = tuple(b'V%i' % v for v in obsolete.formats)
1625 caps[b'obsmarkers'] = supportedformat
1625 caps[b'obsmarkers'] = supportedformat
1626 if allowpushback:
1626 if allowpushback:
1627 caps[b'pushback'] = ()
1627 caps[b'pushback'] = ()
1628 cpmode = repo.ui.config(b'server', b'concurrent-push-mode')
1628 cpmode = repo.ui.config(b'server', b'concurrent-push-mode')
1629 if cpmode == b'check-related':
1629 if cpmode == b'check-related':
1630 caps[b'checkheads'] = (b'related',)
1630 caps[b'checkheads'] = (b'related',)
1631 if b'phases' in repo.ui.configlist(b'devel', b'legacy.exchange'):
1631 if b'phases' in repo.ui.configlist(b'devel', b'legacy.exchange'):
1632 caps.pop(b'phases')
1632 caps.pop(b'phases')
1633
1633
1634 # Don't advertise stream clone support in server mode if not configured.
1634 # Don't advertise stream clone support in server mode if not configured.
1635 if role == b'server':
1635 if role == b'server':
1636 streamsupported = repo.ui.configbool(
1636 streamsupported = repo.ui.configbool(
1637 b'server', b'uncompressed', untrusted=True
1637 b'server', b'uncompressed', untrusted=True
1638 )
1638 )
1639 featuresupported = repo.ui.configbool(b'server', b'bundle2.stream')
1639 featuresupported = repo.ui.configbool(b'server', b'bundle2.stream')
1640
1640
1641 if not streamsupported or not featuresupported:
1641 if not streamsupported or not featuresupported:
1642 caps.pop(b'stream')
1642 caps.pop(b'stream')
1643 # Else always advertise support on client, because payload support
1643 # Else always advertise support on client, because payload support
1644 # should always be advertised.
1644 # should always be advertised.
1645
1645
1646 return caps
1646 return caps
1647
1647
1648
1648
1649 def bundle2caps(remote):
1649 def bundle2caps(remote):
1650 """return the bundle capabilities of a peer as dict"""
1650 """return the bundle capabilities of a peer as dict"""
1651 raw = remote.capable(b'bundle2')
1651 raw = remote.capable(b'bundle2')
1652 if not raw and raw != b'':
1652 if not raw and raw != b'':
1653 return {}
1653 return {}
1654 capsblob = urlreq.unquote(remote.capable(b'bundle2'))
1654 capsblob = urlreq.unquote(remote.capable(b'bundle2'))
1655 return decodecaps(capsblob)
1655 return decodecaps(capsblob)
1656
1656
1657
1657
1658 def obsmarkersversion(caps):
1658 def obsmarkersversion(caps):
1659 """extract the list of supported obsmarkers versions from a bundle2caps dict"""
1659 """extract the list of supported obsmarkers versions from a bundle2caps dict"""
1660 obscaps = caps.get(b'obsmarkers', ())
1660 obscaps = caps.get(b'obsmarkers', ())
1661 return [int(c[1:]) for c in obscaps if c.startswith(b'V')]
1661 return [int(c[1:]) for c in obscaps if c.startswith(b'V')]
1662
1662
1663
1663
1664 def writenewbundle(
1664 def writenewbundle(
1665 ui,
1665 ui,
1666 repo,
1666 repo,
1667 source,
1667 source,
1668 filename,
1668 filename,
1669 bundletype,
1669 bundletype,
1670 outgoing,
1670 outgoing,
1671 opts,
1671 opts,
1672 vfs=None,
1672 vfs=None,
1673 compression=None,
1673 compression=None,
1674 compopts=None,
1674 compopts=None,
1675 ):
1675 ):
1676 if bundletype.startswith(b'HG10'):
1676 if bundletype.startswith(b'HG10'):
1677 cg = changegroup.makechangegroup(repo, outgoing, b'01', source)
1677 cg = changegroup.makechangegroup(repo, outgoing, b'01', source)
1678 return writebundle(
1678 return writebundle(
1679 ui,
1679 ui,
1680 cg,
1680 cg,
1681 filename,
1681 filename,
1682 bundletype,
1682 bundletype,
1683 vfs=vfs,
1683 vfs=vfs,
1684 compression=compression,
1684 compression=compression,
1685 compopts=compopts,
1685 compopts=compopts,
1686 )
1686 )
1687 elif not bundletype.startswith(b'HG20'):
1687 elif not bundletype.startswith(b'HG20'):
1688 raise error.ProgrammingError(b'unknown bundle type: %s' % bundletype)
1688 raise error.ProgrammingError(b'unknown bundle type: %s' % bundletype)
1689
1689
1690 caps = {}
1690 caps = {}
1691 if b'obsolescence' in opts:
1691 if b'obsolescence' in opts:
1692 caps[b'obsmarkers'] = (b'V1',)
1692 caps[b'obsmarkers'] = (b'V1',)
1693 bundle = bundle20(ui, caps)
1693 bundle = bundle20(ui, caps)
1694 bundle.setcompression(compression, compopts)
1694 bundle.setcompression(compression, compopts)
1695 _addpartsfromopts(ui, repo, bundle, source, outgoing, opts)
1695 _addpartsfromopts(ui, repo, bundle, source, outgoing, opts)
1696 chunkiter = bundle.getchunks()
1696 chunkiter = bundle.getchunks()
1697
1697
1698 return changegroup.writechunks(ui, chunkiter, filename, vfs=vfs)
1698 return changegroup.writechunks(ui, chunkiter, filename, vfs=vfs)
1699
1699
1700
1700
1701 def _addpartsfromopts(ui, repo, bundler, source, outgoing, opts):
1701 def _addpartsfromopts(ui, repo, bundler, source, outgoing, opts):
1702 # We should eventually reconcile this logic with the one behind
1702 # We should eventually reconcile this logic with the one behind
1703 # 'exchange.getbundle2partsgenerator'.
1703 # 'exchange.getbundle2partsgenerator'.
1704 #
1704 #
1705 # The type of input from 'getbundle' and 'writenewbundle' are a bit
1705 # The type of input from 'getbundle' and 'writenewbundle' are a bit
1706 # different right now. So we keep them separated for now for the sake of
1706 # different right now. So we keep them separated for now for the sake of
1707 # simplicity.
1707 # simplicity.
1708
1708
1709 # we might not always want a changegroup in such bundle, for example in
1709 # we might not always want a changegroup in such bundle, for example in
1710 # stream bundles
1710 # stream bundles
1711 if opts.get(b'changegroup', True):
1711 if opts.get(b'changegroup', True):
1712 cgversion = opts.get(b'cg.version')
1712 cgversion = opts.get(b'cg.version')
1713 if cgversion is None:
1713 if cgversion is None:
1714 cgversion = changegroup.safeversion(repo)
1714 cgversion = changegroup.safeversion(repo)
1715 cg = changegroup.makechangegroup(repo, outgoing, cgversion, source)
1715 cg = changegroup.makechangegroup(repo, outgoing, cgversion, source)
1716 part = bundler.newpart(b'changegroup', data=cg.getchunks())
1716 part = bundler.newpart(b'changegroup', data=cg.getchunks())
1717 part.addparam(b'version', cg.version)
1717 part.addparam(b'version', cg.version)
1718 if b'clcount' in cg.extras:
1718 if b'clcount' in cg.extras:
1719 part.addparam(
1719 part.addparam(
1720 b'nbchanges', b'%d' % cg.extras[b'clcount'], mandatory=False
1720 b'nbchanges', b'%d' % cg.extras[b'clcount'], mandatory=False
1721 )
1721 )
1722 if opts.get(b'phases') and repo.revs(
1722 if opts.get(b'phases') and repo.revs(
1723 b'%ln and secret()', outgoing.ancestorsof
1723 b'%ln and secret()', outgoing.ancestorsof
1724 ):
1724 ):
1725 part.addparam(
1725 part.addparam(
1726 b'targetphase', b'%d' % phases.secret, mandatory=False
1726 b'targetphase', b'%d' % phases.secret, mandatory=False
1727 )
1727 )
1728 if b'exp-sidedata-flag' in repo.requirements:
1728 if b'exp-sidedata-flag' in repo.requirements:
1729 part.addparam(b'exp-sidedata', b'1')
1729 part.addparam(b'exp-sidedata', b'1')
1730
1730
1731 if opts.get(b'streamv2', False):
1731 if opts.get(b'streamv2', False):
1732 addpartbundlestream2(bundler, repo, stream=True)
1732 addpartbundlestream2(bundler, repo, stream=True)
1733
1733
1734 if opts.get(b'tagsfnodescache', True):
1734 if opts.get(b'tagsfnodescache', True):
1735 addparttagsfnodescache(repo, bundler, outgoing)
1735 addparttagsfnodescache(repo, bundler, outgoing)
1736
1736
1737 if opts.get(b'revbranchcache', True):
1737 if opts.get(b'revbranchcache', True):
1738 addpartrevbranchcache(repo, bundler, outgoing)
1738 addpartrevbranchcache(repo, bundler, outgoing)
1739
1739
1740 if opts.get(b'obsolescence', False):
1740 if opts.get(b'obsolescence', False):
1741 obsmarkers = repo.obsstore.relevantmarkers(outgoing.missing)
1741 obsmarkers = repo.obsstore.relevantmarkers(outgoing.missing)
1742 buildobsmarkerspart(bundler, obsmarkers)
1742 buildobsmarkerspart(
1743 bundler,
1744 obsmarkers,
1745 mandatory=opts.get(b'obsolescence-mandatory', True),
1746 )
1743
1747
1744 if opts.get(b'phases', False):
1748 if opts.get(b'phases', False):
1745 headsbyphase = phases.subsetphaseheads(repo, outgoing.missing)
1749 headsbyphase = phases.subsetphaseheads(repo, outgoing.missing)
1746 phasedata = phases.binaryencode(headsbyphase)
1750 phasedata = phases.binaryencode(headsbyphase)
1747 bundler.newpart(b'phase-heads', data=phasedata)
1751 bundler.newpart(b'phase-heads', data=phasedata)
1748
1752
1749
1753
1750 def addparttagsfnodescache(repo, bundler, outgoing):
1754 def addparttagsfnodescache(repo, bundler, outgoing):
1751 # we include the tags fnode cache for the bundle changeset
1755 # we include the tags fnode cache for the bundle changeset
1752 # (as an optional parts)
1756 # (as an optional parts)
1753 cache = tags.hgtagsfnodescache(repo.unfiltered())
1757 cache = tags.hgtagsfnodescache(repo.unfiltered())
1754 chunks = []
1758 chunks = []
1755
1759
1756 # .hgtags fnodes are only relevant for head changesets. While we could
1760 # .hgtags fnodes are only relevant for head changesets. While we could
1757 # transfer values for all known nodes, there will likely be little to
1761 # transfer values for all known nodes, there will likely be little to
1758 # no benefit.
1762 # no benefit.
1759 #
1763 #
1760 # We don't bother using a generator to produce output data because
1764 # We don't bother using a generator to produce output data because
1761 # a) we only have 40 bytes per head and even esoteric numbers of heads
1765 # a) we only have 40 bytes per head and even esoteric numbers of heads
1762 # consume little memory (1M heads is 40MB) b) we don't want to send the
1766 # consume little memory (1M heads is 40MB) b) we don't want to send the
1763 # part if we don't have entries and knowing if we have entries requires
1767 # part if we don't have entries and knowing if we have entries requires
1764 # cache lookups.
1768 # cache lookups.
1765 for node in outgoing.ancestorsof:
1769 for node in outgoing.ancestorsof:
1766 # Don't compute missing, as this may slow down serving.
1770 # Don't compute missing, as this may slow down serving.
1767 fnode = cache.getfnode(node, computemissing=False)
1771 fnode = cache.getfnode(node, computemissing=False)
1768 if fnode is not None:
1772 if fnode is not None:
1769 chunks.extend([node, fnode])
1773 chunks.extend([node, fnode])
1770
1774
1771 if chunks:
1775 if chunks:
1772 bundler.newpart(b'hgtagsfnodes', data=b''.join(chunks))
1776 bundler.newpart(b'hgtagsfnodes', data=b''.join(chunks))
1773
1777
1774
1778
1775 def addpartrevbranchcache(repo, bundler, outgoing):
1779 def addpartrevbranchcache(repo, bundler, outgoing):
1776 # we include the rev branch cache for the bundle changeset
1780 # we include the rev branch cache for the bundle changeset
1777 # (as an optional parts)
1781 # (as an optional parts)
1778 cache = repo.revbranchcache()
1782 cache = repo.revbranchcache()
1779 cl = repo.unfiltered().changelog
1783 cl = repo.unfiltered().changelog
1780 branchesdata = collections.defaultdict(lambda: (set(), set()))
1784 branchesdata = collections.defaultdict(lambda: (set(), set()))
1781 for node in outgoing.missing:
1785 for node in outgoing.missing:
1782 branch, close = cache.branchinfo(cl.rev(node))
1786 branch, close = cache.branchinfo(cl.rev(node))
1783 branchesdata[branch][close].add(node)
1787 branchesdata[branch][close].add(node)
1784
1788
1785 def generate():
1789 def generate():
1786 for branch, (nodes, closed) in sorted(branchesdata.items()):
1790 for branch, (nodes, closed) in sorted(branchesdata.items()):
1787 utf8branch = encoding.fromlocal(branch)
1791 utf8branch = encoding.fromlocal(branch)
1788 yield rbcstruct.pack(len(utf8branch), len(nodes), len(closed))
1792 yield rbcstruct.pack(len(utf8branch), len(nodes), len(closed))
1789 yield utf8branch
1793 yield utf8branch
1790 for n in sorted(nodes):
1794 for n in sorted(nodes):
1791 yield n
1795 yield n
1792 for n in sorted(closed):
1796 for n in sorted(closed):
1793 yield n
1797 yield n
1794
1798
1795 bundler.newpart(b'cache:rev-branch-cache', data=generate(), mandatory=False)
1799 bundler.newpart(b'cache:rev-branch-cache', data=generate(), mandatory=False)
1796
1800
1797
1801
1798 def _formatrequirementsspec(requirements):
1802 def _formatrequirementsspec(requirements):
1799 requirements = [req for req in requirements if req != b"shared"]
1803 requirements = [req for req in requirements if req != b"shared"]
1800 return urlreq.quote(b','.join(sorted(requirements)))
1804 return urlreq.quote(b','.join(sorted(requirements)))
1801
1805
1802
1806
1803 def _formatrequirementsparams(requirements):
1807 def _formatrequirementsparams(requirements):
1804 requirements = _formatrequirementsspec(requirements)
1808 requirements = _formatrequirementsspec(requirements)
1805 params = b"%s%s" % (urlreq.quote(b"requirements="), requirements)
1809 params = b"%s%s" % (urlreq.quote(b"requirements="), requirements)
1806 return params
1810 return params
1807
1811
1808
1812
1809 def addpartbundlestream2(bundler, repo, **kwargs):
1813 def addpartbundlestream2(bundler, repo, **kwargs):
1810 if not kwargs.get('stream', False):
1814 if not kwargs.get('stream', False):
1811 return
1815 return
1812
1816
1813 if not streamclone.allowservergeneration(repo):
1817 if not streamclone.allowservergeneration(repo):
1814 raise error.Abort(
1818 raise error.Abort(
1815 _(
1819 _(
1816 b'stream data requested but server does not allow '
1820 b'stream data requested but server does not allow '
1817 b'this feature'
1821 b'this feature'
1818 ),
1822 ),
1819 hint=_(
1823 hint=_(
1820 b'well-behaved clients should not be '
1824 b'well-behaved clients should not be '
1821 b'requesting stream data from servers not '
1825 b'requesting stream data from servers not '
1822 b'advertising it; the client may be buggy'
1826 b'advertising it; the client may be buggy'
1823 ),
1827 ),
1824 )
1828 )
1825
1829
1826 # Stream clones don't compress well. And compression undermines a
1830 # Stream clones don't compress well. And compression undermines a
1827 # goal of stream clones, which is to be fast. Communicate the desire
1831 # goal of stream clones, which is to be fast. Communicate the desire
1828 # to avoid compression to consumers of the bundle.
1832 # to avoid compression to consumers of the bundle.
1829 bundler.prefercompressed = False
1833 bundler.prefercompressed = False
1830
1834
1831 # get the includes and excludes
1835 # get the includes and excludes
1832 includepats = kwargs.get('includepats')
1836 includepats = kwargs.get('includepats')
1833 excludepats = kwargs.get('excludepats')
1837 excludepats = kwargs.get('excludepats')
1834
1838
1835 narrowstream = repo.ui.configbool(
1839 narrowstream = repo.ui.configbool(
1836 b'experimental', b'server.stream-narrow-clones'
1840 b'experimental', b'server.stream-narrow-clones'
1837 )
1841 )
1838
1842
1839 if (includepats or excludepats) and not narrowstream:
1843 if (includepats or excludepats) and not narrowstream:
1840 raise error.Abort(_(b'server does not support narrow stream clones'))
1844 raise error.Abort(_(b'server does not support narrow stream clones'))
1841
1845
1842 includeobsmarkers = False
1846 includeobsmarkers = False
1843 if repo.obsstore:
1847 if repo.obsstore:
1844 remoteversions = obsmarkersversion(bundler.capabilities)
1848 remoteversions = obsmarkersversion(bundler.capabilities)
1845 if not remoteversions:
1849 if not remoteversions:
1846 raise error.Abort(
1850 raise error.Abort(
1847 _(
1851 _(
1848 b'server has obsolescence markers, but client '
1852 b'server has obsolescence markers, but client '
1849 b'cannot receive them via stream clone'
1853 b'cannot receive them via stream clone'
1850 )
1854 )
1851 )
1855 )
1852 elif repo.obsstore._version in remoteversions:
1856 elif repo.obsstore._version in remoteversions:
1853 includeobsmarkers = True
1857 includeobsmarkers = True
1854
1858
1855 filecount, bytecount, it = streamclone.generatev2(
1859 filecount, bytecount, it = streamclone.generatev2(
1856 repo, includepats, excludepats, includeobsmarkers
1860 repo, includepats, excludepats, includeobsmarkers
1857 )
1861 )
1858 requirements = _formatrequirementsspec(repo.requirements)
1862 requirements = _formatrequirementsspec(repo.requirements)
1859 part = bundler.newpart(b'stream2', data=it)
1863 part = bundler.newpart(b'stream2', data=it)
1860 part.addparam(b'bytecount', b'%d' % bytecount, mandatory=True)
1864 part.addparam(b'bytecount', b'%d' % bytecount, mandatory=True)
1861 part.addparam(b'filecount', b'%d' % filecount, mandatory=True)
1865 part.addparam(b'filecount', b'%d' % filecount, mandatory=True)
1862 part.addparam(b'requirements', requirements, mandatory=True)
1866 part.addparam(b'requirements', requirements, mandatory=True)
1863
1867
1864
1868
1865 def buildobsmarkerspart(bundler, markers):
1869 def buildobsmarkerspart(bundler, markers, mandatory=True):
1866 """add an obsmarker part to the bundler with <markers>
1870 """add an obsmarker part to the bundler with <markers>
1867
1871
1868 No part is created if markers is empty.
1872 No part is created if markers is empty.
1869 Raises ValueError if the bundler doesn't support any known obsmarker format.
1873 Raises ValueError if the bundler doesn't support any known obsmarker format.
1870 """
1874 """
1871 if not markers:
1875 if not markers:
1872 return None
1876 return None
1873
1877
1874 remoteversions = obsmarkersversion(bundler.capabilities)
1878 remoteversions = obsmarkersversion(bundler.capabilities)
1875 version = obsolete.commonversion(remoteversions)
1879 version = obsolete.commonversion(remoteversions)
1876 if version is None:
1880 if version is None:
1877 raise ValueError(b'bundler does not support common obsmarker format')
1881 raise ValueError(b'bundler does not support common obsmarker format')
1878 stream = obsolete.encodemarkers(markers, True, version=version)
1882 stream = obsolete.encodemarkers(markers, True, version=version)
1879 return bundler.newpart(b'obsmarkers', data=stream)
1883 return bundler.newpart(b'obsmarkers', data=stream, mandatory=mandatory)
1880
1884
1881
1885
1882 def writebundle(
1886 def writebundle(
1883 ui, cg, filename, bundletype, vfs=None, compression=None, compopts=None
1887 ui, cg, filename, bundletype, vfs=None, compression=None, compopts=None
1884 ):
1888 ):
1885 """Write a bundle file and return its filename.
1889 """Write a bundle file and return its filename.
1886
1890
1887 Existing files will not be overwritten.
1891 Existing files will not be overwritten.
1888 If no filename is specified, a temporary file is created.
1892 If no filename is specified, a temporary file is created.
1889 bz2 compression can be turned off.
1893 bz2 compression can be turned off.
1890 The bundle file will be deleted in case of errors.
1894 The bundle file will be deleted in case of errors.
1891 """
1895 """
1892
1896
1893 if bundletype == b"HG20":
1897 if bundletype == b"HG20":
1894 bundle = bundle20(ui)
1898 bundle = bundle20(ui)
1895 bundle.setcompression(compression, compopts)
1899 bundle.setcompression(compression, compopts)
1896 part = bundle.newpart(b'changegroup', data=cg.getchunks())
1900 part = bundle.newpart(b'changegroup', data=cg.getchunks())
1897 part.addparam(b'version', cg.version)
1901 part.addparam(b'version', cg.version)
1898 if b'clcount' in cg.extras:
1902 if b'clcount' in cg.extras:
1899 part.addparam(
1903 part.addparam(
1900 b'nbchanges', b'%d' % cg.extras[b'clcount'], mandatory=False
1904 b'nbchanges', b'%d' % cg.extras[b'clcount'], mandatory=False
1901 )
1905 )
1902 chunkiter = bundle.getchunks()
1906 chunkiter = bundle.getchunks()
1903 else:
1907 else:
1904 # compression argument is only for the bundle2 case
1908 # compression argument is only for the bundle2 case
1905 assert compression is None
1909 assert compression is None
1906 if cg.version != b'01':
1910 if cg.version != b'01':
1907 raise error.Abort(
1911 raise error.Abort(
1908 _(b'old bundle types only supports v1 changegroups')
1912 _(b'old bundle types only supports v1 changegroups')
1909 )
1913 )
1910 header, comp = bundletypes[bundletype]
1914 header, comp = bundletypes[bundletype]
1911 if comp not in util.compengines.supportedbundletypes:
1915 if comp not in util.compengines.supportedbundletypes:
1912 raise error.Abort(_(b'unknown stream compression type: %s') % comp)
1916 raise error.Abort(_(b'unknown stream compression type: %s') % comp)
1913 compengine = util.compengines.forbundletype(comp)
1917 compengine = util.compengines.forbundletype(comp)
1914
1918
1915 def chunkiter():
1919 def chunkiter():
1916 yield header
1920 yield header
1917 for chunk in compengine.compressstream(cg.getchunks(), compopts):
1921 for chunk in compengine.compressstream(cg.getchunks(), compopts):
1918 yield chunk
1922 yield chunk
1919
1923
1920 chunkiter = chunkiter()
1924 chunkiter = chunkiter()
1921
1925
1922 # parse the changegroup data, otherwise we will block
1926 # parse the changegroup data, otherwise we will block
1923 # in case of sshrepo because we don't know the end of the stream
1927 # in case of sshrepo because we don't know the end of the stream
1924 return changegroup.writechunks(ui, chunkiter, filename, vfs=vfs)
1928 return changegroup.writechunks(ui, chunkiter, filename, vfs=vfs)
1925
1929
1926
1930
1927 def combinechangegroupresults(op):
1931 def combinechangegroupresults(op):
1928 """logic to combine 0 or more addchangegroup results into one"""
1932 """logic to combine 0 or more addchangegroup results into one"""
1929 results = [r.get(b'return', 0) for r in op.records[b'changegroup']]
1933 results = [r.get(b'return', 0) for r in op.records[b'changegroup']]
1930 changedheads = 0
1934 changedheads = 0
1931 result = 1
1935 result = 1
1932 for ret in results:
1936 for ret in results:
1933 # If any changegroup result is 0, return 0
1937 # If any changegroup result is 0, return 0
1934 if ret == 0:
1938 if ret == 0:
1935 result = 0
1939 result = 0
1936 break
1940 break
1937 if ret < -1:
1941 if ret < -1:
1938 changedheads += ret + 1
1942 changedheads += ret + 1
1939 elif ret > 1:
1943 elif ret > 1:
1940 changedheads += ret - 1
1944 changedheads += ret - 1
1941 if changedheads > 0:
1945 if changedheads > 0:
1942 result = 1 + changedheads
1946 result = 1 + changedheads
1943 elif changedheads < 0:
1947 elif changedheads < 0:
1944 result = -1 + changedheads
1948 result = -1 + changedheads
1945 return result
1949 return result
1946
1950
1947
1951
1948 @parthandler(
1952 @parthandler(
1949 b'changegroup',
1953 b'changegroup',
1950 (
1954 (
1951 b'version',
1955 b'version',
1952 b'nbchanges',
1956 b'nbchanges',
1953 b'exp-sidedata',
1957 b'exp-sidedata',
1954 b'treemanifest',
1958 b'treemanifest',
1955 b'targetphase',
1959 b'targetphase',
1956 ),
1960 ),
1957 )
1961 )
1958 def handlechangegroup(op, inpart):
1962 def handlechangegroup(op, inpart):
1959 """apply a changegroup part on the repo
1963 """apply a changegroup part on the repo
1960
1964
1961 This is a very early implementation that will massive rework before being
1965 This is a very early implementation that will massive rework before being
1962 inflicted to any end-user.
1966 inflicted to any end-user.
1963 """
1967 """
1964 from . import localrepo
1968 from . import localrepo
1965
1969
1966 tr = op.gettransaction()
1970 tr = op.gettransaction()
1967 unpackerversion = inpart.params.get(b'version', b'01')
1971 unpackerversion = inpart.params.get(b'version', b'01')
1968 # We should raise an appropriate exception here
1972 # We should raise an appropriate exception here
1969 cg = changegroup.getunbundler(unpackerversion, inpart, None)
1973 cg = changegroup.getunbundler(unpackerversion, inpart, None)
1970 # the source and url passed here are overwritten by the one contained in
1974 # the source and url passed here are overwritten by the one contained in
1971 # the transaction.hookargs argument. So 'bundle2' is a placeholder
1975 # the transaction.hookargs argument. So 'bundle2' is a placeholder
1972 nbchangesets = None
1976 nbchangesets = None
1973 if b'nbchanges' in inpart.params:
1977 if b'nbchanges' in inpart.params:
1974 nbchangesets = int(inpart.params.get(b'nbchanges'))
1978 nbchangesets = int(inpart.params.get(b'nbchanges'))
1975 if b'treemanifest' in inpart.params and not scmutil.istreemanifest(op.repo):
1979 if b'treemanifest' in inpart.params and not scmutil.istreemanifest(op.repo):
1976 if len(op.repo.changelog) != 0:
1980 if len(op.repo.changelog) != 0:
1977 raise error.Abort(
1981 raise error.Abort(
1978 _(
1982 _(
1979 b"bundle contains tree manifests, but local repo is "
1983 b"bundle contains tree manifests, but local repo is "
1980 b"non-empty and does not use tree manifests"
1984 b"non-empty and does not use tree manifests"
1981 )
1985 )
1982 )
1986 )
1983 op.repo.requirements.add(requirements.TREEMANIFEST_REQUIREMENT)
1987 op.repo.requirements.add(requirements.TREEMANIFEST_REQUIREMENT)
1984 op.repo.svfs.options = localrepo.resolvestorevfsoptions(
1988 op.repo.svfs.options = localrepo.resolvestorevfsoptions(
1985 op.repo.ui, op.repo.requirements, op.repo.features
1989 op.repo.ui, op.repo.requirements, op.repo.features
1986 )
1990 )
1987 scmutil.writereporequirements(op.repo)
1991 scmutil.writereporequirements(op.repo)
1988
1992
1989 bundlesidedata = bool(b'exp-sidedata' in inpart.params)
1993 bundlesidedata = bool(b'exp-sidedata' in inpart.params)
1990 reposidedata = bool(b'exp-sidedata-flag' in op.repo.requirements)
1994 reposidedata = bool(b'exp-sidedata-flag' in op.repo.requirements)
1991 if reposidedata and not bundlesidedata:
1995 if reposidedata and not bundlesidedata:
1992 msg = b"repository is using sidedata but the bundle source do not"
1996 msg = b"repository is using sidedata but the bundle source do not"
1993 hint = b'this is currently unsupported'
1997 hint = b'this is currently unsupported'
1994 raise error.Abort(msg, hint=hint)
1998 raise error.Abort(msg, hint=hint)
1995
1999
1996 extrakwargs = {}
2000 extrakwargs = {}
1997 targetphase = inpart.params.get(b'targetphase')
2001 targetphase = inpart.params.get(b'targetphase')
1998 if targetphase is not None:
2002 if targetphase is not None:
1999 extrakwargs['targetphase'] = int(targetphase)
2003 extrakwargs['targetphase'] = int(targetphase)
2000 ret = _processchangegroup(
2004 ret = _processchangegroup(
2001 op,
2005 op,
2002 cg,
2006 cg,
2003 tr,
2007 tr,
2004 b'bundle2',
2008 b'bundle2',
2005 b'bundle2',
2009 b'bundle2',
2006 expectedtotal=nbchangesets,
2010 expectedtotal=nbchangesets,
2007 **extrakwargs
2011 **extrakwargs
2008 )
2012 )
2009 if op.reply is not None:
2013 if op.reply is not None:
2010 # This is definitely not the final form of this
2014 # This is definitely not the final form of this
2011 # return. But one need to start somewhere.
2015 # return. But one need to start somewhere.
2012 part = op.reply.newpart(b'reply:changegroup', mandatory=False)
2016 part = op.reply.newpart(b'reply:changegroup', mandatory=False)
2013 part.addparam(
2017 part.addparam(
2014 b'in-reply-to', pycompat.bytestr(inpart.id), mandatory=False
2018 b'in-reply-to', pycompat.bytestr(inpart.id), mandatory=False
2015 )
2019 )
2016 part.addparam(b'return', b'%i' % ret, mandatory=False)
2020 part.addparam(b'return', b'%i' % ret, mandatory=False)
2017 assert not inpart.read()
2021 assert not inpart.read()
2018
2022
2019
2023
2020 _remotechangegroupparams = tuple(
2024 _remotechangegroupparams = tuple(
2021 [b'url', b'size', b'digests']
2025 [b'url', b'size', b'digests']
2022 + [b'digest:%s' % k for k in util.DIGESTS.keys()]
2026 + [b'digest:%s' % k for k in util.DIGESTS.keys()]
2023 )
2027 )
2024
2028
2025
2029
2026 @parthandler(b'remote-changegroup', _remotechangegroupparams)
2030 @parthandler(b'remote-changegroup', _remotechangegroupparams)
2027 def handleremotechangegroup(op, inpart):
2031 def handleremotechangegroup(op, inpart):
2028 """apply a bundle10 on the repo, given an url and validation information
2032 """apply a bundle10 on the repo, given an url and validation information
2029
2033
2030 All the information about the remote bundle to import are given as
2034 All the information about the remote bundle to import are given as
2031 parameters. The parameters include:
2035 parameters. The parameters include:
2032 - url: the url to the bundle10.
2036 - url: the url to the bundle10.
2033 - size: the bundle10 file size. It is used to validate what was
2037 - size: the bundle10 file size. It is used to validate what was
2034 retrieved by the client matches the server knowledge about the bundle.
2038 retrieved by the client matches the server knowledge about the bundle.
2035 - digests: a space separated list of the digest types provided as
2039 - digests: a space separated list of the digest types provided as
2036 parameters.
2040 parameters.
2037 - digest:<digest-type>: the hexadecimal representation of the digest with
2041 - digest:<digest-type>: the hexadecimal representation of the digest with
2038 that name. Like the size, it is used to validate what was retrieved by
2042 that name. Like the size, it is used to validate what was retrieved by
2039 the client matches what the server knows about the bundle.
2043 the client matches what the server knows about the bundle.
2040
2044
2041 When multiple digest types are given, all of them are checked.
2045 When multiple digest types are given, all of them are checked.
2042 """
2046 """
2043 try:
2047 try:
2044 raw_url = inpart.params[b'url']
2048 raw_url = inpart.params[b'url']
2045 except KeyError:
2049 except KeyError:
2046 raise error.Abort(_(b'remote-changegroup: missing "%s" param') % b'url')
2050 raise error.Abort(_(b'remote-changegroup: missing "%s" param') % b'url')
2047 parsed_url = util.url(raw_url)
2051 parsed_url = util.url(raw_url)
2048 if parsed_url.scheme not in capabilities[b'remote-changegroup']:
2052 if parsed_url.scheme not in capabilities[b'remote-changegroup']:
2049 raise error.Abort(
2053 raise error.Abort(
2050 _(b'remote-changegroup does not support %s urls')
2054 _(b'remote-changegroup does not support %s urls')
2051 % parsed_url.scheme
2055 % parsed_url.scheme
2052 )
2056 )
2053
2057
2054 try:
2058 try:
2055 size = int(inpart.params[b'size'])
2059 size = int(inpart.params[b'size'])
2056 except ValueError:
2060 except ValueError:
2057 raise error.Abort(
2061 raise error.Abort(
2058 _(b'remote-changegroup: invalid value for param "%s"') % b'size'
2062 _(b'remote-changegroup: invalid value for param "%s"') % b'size'
2059 )
2063 )
2060 except KeyError:
2064 except KeyError:
2061 raise error.Abort(
2065 raise error.Abort(
2062 _(b'remote-changegroup: missing "%s" param') % b'size'
2066 _(b'remote-changegroup: missing "%s" param') % b'size'
2063 )
2067 )
2064
2068
2065 digests = {}
2069 digests = {}
2066 for typ in inpart.params.get(b'digests', b'').split():
2070 for typ in inpart.params.get(b'digests', b'').split():
2067 param = b'digest:%s' % typ
2071 param = b'digest:%s' % typ
2068 try:
2072 try:
2069 value = inpart.params[param]
2073 value = inpart.params[param]
2070 except KeyError:
2074 except KeyError:
2071 raise error.Abort(
2075 raise error.Abort(
2072 _(b'remote-changegroup: missing "%s" param') % param
2076 _(b'remote-changegroup: missing "%s" param') % param
2073 )
2077 )
2074 digests[typ] = value
2078 digests[typ] = value
2075
2079
2076 real_part = util.digestchecker(url.open(op.ui, raw_url), size, digests)
2080 real_part = util.digestchecker(url.open(op.ui, raw_url), size, digests)
2077
2081
2078 tr = op.gettransaction()
2082 tr = op.gettransaction()
2079 from . import exchange
2083 from . import exchange
2080
2084
2081 cg = exchange.readbundle(op.repo.ui, real_part, raw_url)
2085 cg = exchange.readbundle(op.repo.ui, real_part, raw_url)
2082 if not isinstance(cg, changegroup.cg1unpacker):
2086 if not isinstance(cg, changegroup.cg1unpacker):
2083 raise error.Abort(
2087 raise error.Abort(
2084 _(b'%s: not a bundle version 1.0') % util.hidepassword(raw_url)
2088 _(b'%s: not a bundle version 1.0') % util.hidepassword(raw_url)
2085 )
2089 )
2086 ret = _processchangegroup(op, cg, tr, b'bundle2', b'bundle2')
2090 ret = _processchangegroup(op, cg, tr, b'bundle2', b'bundle2')
2087 if op.reply is not None:
2091 if op.reply is not None:
2088 # This is definitely not the final form of this
2092 # This is definitely not the final form of this
2089 # return. But one need to start somewhere.
2093 # return. But one need to start somewhere.
2090 part = op.reply.newpart(b'reply:changegroup')
2094 part = op.reply.newpart(b'reply:changegroup')
2091 part.addparam(
2095 part.addparam(
2092 b'in-reply-to', pycompat.bytestr(inpart.id), mandatory=False
2096 b'in-reply-to', pycompat.bytestr(inpart.id), mandatory=False
2093 )
2097 )
2094 part.addparam(b'return', b'%i' % ret, mandatory=False)
2098 part.addparam(b'return', b'%i' % ret, mandatory=False)
2095 try:
2099 try:
2096 real_part.validate()
2100 real_part.validate()
2097 except error.Abort as e:
2101 except error.Abort as e:
2098 raise error.Abort(
2102 raise error.Abort(
2099 _(b'bundle at %s is corrupted:\n%s')
2103 _(b'bundle at %s is corrupted:\n%s')
2100 % (util.hidepassword(raw_url), e.message)
2104 % (util.hidepassword(raw_url), e.message)
2101 )
2105 )
2102 assert not inpart.read()
2106 assert not inpart.read()
2103
2107
2104
2108
2105 @parthandler(b'reply:changegroup', (b'return', b'in-reply-to'))
2109 @parthandler(b'reply:changegroup', (b'return', b'in-reply-to'))
2106 def handlereplychangegroup(op, inpart):
2110 def handlereplychangegroup(op, inpart):
2107 ret = int(inpart.params[b'return'])
2111 ret = int(inpart.params[b'return'])
2108 replyto = int(inpart.params[b'in-reply-to'])
2112 replyto = int(inpart.params[b'in-reply-to'])
2109 op.records.add(b'changegroup', {b'return': ret}, replyto)
2113 op.records.add(b'changegroup', {b'return': ret}, replyto)
2110
2114
2111
2115
2112 @parthandler(b'check:bookmarks')
2116 @parthandler(b'check:bookmarks')
2113 def handlecheckbookmarks(op, inpart):
2117 def handlecheckbookmarks(op, inpart):
2114 """check location of bookmarks
2118 """check location of bookmarks
2115
2119
2116 This part is to be used to detect push race regarding bookmark, it
2120 This part is to be used to detect push race regarding bookmark, it
2117 contains binary encoded (bookmark, node) tuple. If the local state does
2121 contains binary encoded (bookmark, node) tuple. If the local state does
2118 not marks the one in the part, a PushRaced exception is raised
2122 not marks the one in the part, a PushRaced exception is raised
2119 """
2123 """
2120 bookdata = bookmarks.binarydecode(inpart)
2124 bookdata = bookmarks.binarydecode(inpart)
2121
2125
2122 msgstandard = (
2126 msgstandard = (
2123 b'remote repository changed while pushing - please try again '
2127 b'remote repository changed while pushing - please try again '
2124 b'(bookmark "%s" move from %s to %s)'
2128 b'(bookmark "%s" move from %s to %s)'
2125 )
2129 )
2126 msgmissing = (
2130 msgmissing = (
2127 b'remote repository changed while pushing - please try again '
2131 b'remote repository changed while pushing - please try again '
2128 b'(bookmark "%s" is missing, expected %s)'
2132 b'(bookmark "%s" is missing, expected %s)'
2129 )
2133 )
2130 msgexist = (
2134 msgexist = (
2131 b'remote repository changed while pushing - please try again '
2135 b'remote repository changed while pushing - please try again '
2132 b'(bookmark "%s" set on %s, expected missing)'
2136 b'(bookmark "%s" set on %s, expected missing)'
2133 )
2137 )
2134 for book, node in bookdata:
2138 for book, node in bookdata:
2135 currentnode = op.repo._bookmarks.get(book)
2139 currentnode = op.repo._bookmarks.get(book)
2136 if currentnode != node:
2140 if currentnode != node:
2137 if node is None:
2141 if node is None:
2138 finalmsg = msgexist % (book, short(currentnode))
2142 finalmsg = msgexist % (book, short(currentnode))
2139 elif currentnode is None:
2143 elif currentnode is None:
2140 finalmsg = msgmissing % (book, short(node))
2144 finalmsg = msgmissing % (book, short(node))
2141 else:
2145 else:
2142 finalmsg = msgstandard % (
2146 finalmsg = msgstandard % (
2143 book,
2147 book,
2144 short(node),
2148 short(node),
2145 short(currentnode),
2149 short(currentnode),
2146 )
2150 )
2147 raise error.PushRaced(finalmsg)
2151 raise error.PushRaced(finalmsg)
2148
2152
2149
2153
2150 @parthandler(b'check:heads')
2154 @parthandler(b'check:heads')
2151 def handlecheckheads(op, inpart):
2155 def handlecheckheads(op, inpart):
2152 """check that head of the repo did not change
2156 """check that head of the repo did not change
2153
2157
2154 This is used to detect a push race when using unbundle.
2158 This is used to detect a push race when using unbundle.
2155 This replaces the "heads" argument of unbundle."""
2159 This replaces the "heads" argument of unbundle."""
2156 h = inpart.read(20)
2160 h = inpart.read(20)
2157 heads = []
2161 heads = []
2158 while len(h) == 20:
2162 while len(h) == 20:
2159 heads.append(h)
2163 heads.append(h)
2160 h = inpart.read(20)
2164 h = inpart.read(20)
2161 assert not h
2165 assert not h
2162 # Trigger a transaction so that we are guaranteed to have the lock now.
2166 # Trigger a transaction so that we are guaranteed to have the lock now.
2163 if op.ui.configbool(b'experimental', b'bundle2lazylocking'):
2167 if op.ui.configbool(b'experimental', b'bundle2lazylocking'):
2164 op.gettransaction()
2168 op.gettransaction()
2165 if sorted(heads) != sorted(op.repo.heads()):
2169 if sorted(heads) != sorted(op.repo.heads()):
2166 raise error.PushRaced(
2170 raise error.PushRaced(
2167 b'remote repository changed while pushing - please try again'
2171 b'remote repository changed while pushing - please try again'
2168 )
2172 )
2169
2173
2170
2174
2171 @parthandler(b'check:updated-heads')
2175 @parthandler(b'check:updated-heads')
2172 def handlecheckupdatedheads(op, inpart):
2176 def handlecheckupdatedheads(op, inpart):
2173 """check for race on the heads touched by a push
2177 """check for race on the heads touched by a push
2174
2178
2175 This is similar to 'check:heads' but focus on the heads actually updated
2179 This is similar to 'check:heads' but focus on the heads actually updated
2176 during the push. If other activities happen on unrelated heads, it is
2180 during the push. If other activities happen on unrelated heads, it is
2177 ignored.
2181 ignored.
2178
2182
2179 This allow server with high traffic to avoid push contention as long as
2183 This allow server with high traffic to avoid push contention as long as
2180 unrelated parts of the graph are involved."""
2184 unrelated parts of the graph are involved."""
2181 h = inpart.read(20)
2185 h = inpart.read(20)
2182 heads = []
2186 heads = []
2183 while len(h) == 20:
2187 while len(h) == 20:
2184 heads.append(h)
2188 heads.append(h)
2185 h = inpart.read(20)
2189 h = inpart.read(20)
2186 assert not h
2190 assert not h
2187 # trigger a transaction so that we are guaranteed to have the lock now.
2191 # trigger a transaction so that we are guaranteed to have the lock now.
2188 if op.ui.configbool(b'experimental', b'bundle2lazylocking'):
2192 if op.ui.configbool(b'experimental', b'bundle2lazylocking'):
2189 op.gettransaction()
2193 op.gettransaction()
2190
2194
2191 currentheads = set()
2195 currentheads = set()
2192 for ls in op.repo.branchmap().iterheads():
2196 for ls in op.repo.branchmap().iterheads():
2193 currentheads.update(ls)
2197 currentheads.update(ls)
2194
2198
2195 for h in heads:
2199 for h in heads:
2196 if h not in currentheads:
2200 if h not in currentheads:
2197 raise error.PushRaced(
2201 raise error.PushRaced(
2198 b'remote repository changed while pushing - '
2202 b'remote repository changed while pushing - '
2199 b'please try again'
2203 b'please try again'
2200 )
2204 )
2201
2205
2202
2206
2203 @parthandler(b'check:phases')
2207 @parthandler(b'check:phases')
2204 def handlecheckphases(op, inpart):
2208 def handlecheckphases(op, inpart):
2205 """check that phase boundaries of the repository did not change
2209 """check that phase boundaries of the repository did not change
2206
2210
2207 This is used to detect a push race.
2211 This is used to detect a push race.
2208 """
2212 """
2209 phasetonodes = phases.binarydecode(inpart)
2213 phasetonodes = phases.binarydecode(inpart)
2210 unfi = op.repo.unfiltered()
2214 unfi = op.repo.unfiltered()
2211 cl = unfi.changelog
2215 cl = unfi.changelog
2212 phasecache = unfi._phasecache
2216 phasecache = unfi._phasecache
2213 msg = (
2217 msg = (
2214 b'remote repository changed while pushing - please try again '
2218 b'remote repository changed while pushing - please try again '
2215 b'(%s is %s expected %s)'
2219 b'(%s is %s expected %s)'
2216 )
2220 )
2217 for expectedphase, nodes in pycompat.iteritems(phasetonodes):
2221 for expectedphase, nodes in pycompat.iteritems(phasetonodes):
2218 for n in nodes:
2222 for n in nodes:
2219 actualphase = phasecache.phase(unfi, cl.rev(n))
2223 actualphase = phasecache.phase(unfi, cl.rev(n))
2220 if actualphase != expectedphase:
2224 if actualphase != expectedphase:
2221 finalmsg = msg % (
2225 finalmsg = msg % (
2222 short(n),
2226 short(n),
2223 phases.phasenames[actualphase],
2227 phases.phasenames[actualphase],
2224 phases.phasenames[expectedphase],
2228 phases.phasenames[expectedphase],
2225 )
2229 )
2226 raise error.PushRaced(finalmsg)
2230 raise error.PushRaced(finalmsg)
2227
2231
2228
2232
2229 @parthandler(b'output')
2233 @parthandler(b'output')
2230 def handleoutput(op, inpart):
2234 def handleoutput(op, inpart):
2231 """forward output captured on the server to the client"""
2235 """forward output captured on the server to the client"""
2232 for line in inpart.read().splitlines():
2236 for line in inpart.read().splitlines():
2233 op.ui.status(_(b'remote: %s\n') % line)
2237 op.ui.status(_(b'remote: %s\n') % line)
2234
2238
2235
2239
2236 @parthandler(b'replycaps')
2240 @parthandler(b'replycaps')
2237 def handlereplycaps(op, inpart):
2241 def handlereplycaps(op, inpart):
2238 """Notify that a reply bundle should be created
2242 """Notify that a reply bundle should be created
2239
2243
2240 The payload contains the capabilities information for the reply"""
2244 The payload contains the capabilities information for the reply"""
2241 caps = decodecaps(inpart.read())
2245 caps = decodecaps(inpart.read())
2242 if op.reply is None:
2246 if op.reply is None:
2243 op.reply = bundle20(op.ui, caps)
2247 op.reply = bundle20(op.ui, caps)
2244
2248
2245
2249
2246 class AbortFromPart(error.Abort):
2250 class AbortFromPart(error.Abort):
2247 """Sub-class of Abort that denotes an error from a bundle2 part."""
2251 """Sub-class of Abort that denotes an error from a bundle2 part."""
2248
2252
2249
2253
2250 @parthandler(b'error:abort', (b'message', b'hint'))
2254 @parthandler(b'error:abort', (b'message', b'hint'))
2251 def handleerrorabort(op, inpart):
2255 def handleerrorabort(op, inpart):
2252 """Used to transmit abort error over the wire"""
2256 """Used to transmit abort error over the wire"""
2253 raise AbortFromPart(
2257 raise AbortFromPart(
2254 inpart.params[b'message'], hint=inpart.params.get(b'hint')
2258 inpart.params[b'message'], hint=inpart.params.get(b'hint')
2255 )
2259 )
2256
2260
2257
2261
2258 @parthandler(
2262 @parthandler(
2259 b'error:pushkey',
2263 b'error:pushkey',
2260 (b'namespace', b'key', b'new', b'old', b'ret', b'in-reply-to'),
2264 (b'namespace', b'key', b'new', b'old', b'ret', b'in-reply-to'),
2261 )
2265 )
2262 def handleerrorpushkey(op, inpart):
2266 def handleerrorpushkey(op, inpart):
2263 """Used to transmit failure of a mandatory pushkey over the wire"""
2267 """Used to transmit failure of a mandatory pushkey over the wire"""
2264 kwargs = {}
2268 kwargs = {}
2265 for name in (b'namespace', b'key', b'new', b'old', b'ret'):
2269 for name in (b'namespace', b'key', b'new', b'old', b'ret'):
2266 value = inpart.params.get(name)
2270 value = inpart.params.get(name)
2267 if value is not None:
2271 if value is not None:
2268 kwargs[name] = value
2272 kwargs[name] = value
2269 raise error.PushkeyFailed(
2273 raise error.PushkeyFailed(
2270 inpart.params[b'in-reply-to'], **pycompat.strkwargs(kwargs)
2274 inpart.params[b'in-reply-to'], **pycompat.strkwargs(kwargs)
2271 )
2275 )
2272
2276
2273
2277
2274 @parthandler(b'error:unsupportedcontent', (b'parttype', b'params'))
2278 @parthandler(b'error:unsupportedcontent', (b'parttype', b'params'))
2275 def handleerrorunsupportedcontent(op, inpart):
2279 def handleerrorunsupportedcontent(op, inpart):
2276 """Used to transmit unknown content error over the wire"""
2280 """Used to transmit unknown content error over the wire"""
2277 kwargs = {}
2281 kwargs = {}
2278 parttype = inpart.params.get(b'parttype')
2282 parttype = inpart.params.get(b'parttype')
2279 if parttype is not None:
2283 if parttype is not None:
2280 kwargs[b'parttype'] = parttype
2284 kwargs[b'parttype'] = parttype
2281 params = inpart.params.get(b'params')
2285 params = inpart.params.get(b'params')
2282 if params is not None:
2286 if params is not None:
2283 kwargs[b'params'] = params.split(b'\0')
2287 kwargs[b'params'] = params.split(b'\0')
2284
2288
2285 raise error.BundleUnknownFeatureError(**pycompat.strkwargs(kwargs))
2289 raise error.BundleUnknownFeatureError(**pycompat.strkwargs(kwargs))
2286
2290
2287
2291
2288 @parthandler(b'error:pushraced', (b'message',))
2292 @parthandler(b'error:pushraced', (b'message',))
2289 def handleerrorpushraced(op, inpart):
2293 def handleerrorpushraced(op, inpart):
2290 """Used to transmit push race error over the wire"""
2294 """Used to transmit push race error over the wire"""
2291 raise error.ResponseError(_(b'push failed:'), inpart.params[b'message'])
2295 raise error.ResponseError(_(b'push failed:'), inpart.params[b'message'])
2292
2296
2293
2297
2294 @parthandler(b'listkeys', (b'namespace',))
2298 @parthandler(b'listkeys', (b'namespace',))
2295 def handlelistkeys(op, inpart):
2299 def handlelistkeys(op, inpart):
2296 """retrieve pushkey namespace content stored in a bundle2"""
2300 """retrieve pushkey namespace content stored in a bundle2"""
2297 namespace = inpart.params[b'namespace']
2301 namespace = inpart.params[b'namespace']
2298 r = pushkey.decodekeys(inpart.read())
2302 r = pushkey.decodekeys(inpart.read())
2299 op.records.add(b'listkeys', (namespace, r))
2303 op.records.add(b'listkeys', (namespace, r))
2300
2304
2301
2305
2302 @parthandler(b'pushkey', (b'namespace', b'key', b'old', b'new'))
2306 @parthandler(b'pushkey', (b'namespace', b'key', b'old', b'new'))
2303 def handlepushkey(op, inpart):
2307 def handlepushkey(op, inpart):
2304 """process a pushkey request"""
2308 """process a pushkey request"""
2305 dec = pushkey.decode
2309 dec = pushkey.decode
2306 namespace = dec(inpart.params[b'namespace'])
2310 namespace = dec(inpart.params[b'namespace'])
2307 key = dec(inpart.params[b'key'])
2311 key = dec(inpart.params[b'key'])
2308 old = dec(inpart.params[b'old'])
2312 old = dec(inpart.params[b'old'])
2309 new = dec(inpart.params[b'new'])
2313 new = dec(inpart.params[b'new'])
2310 # Grab the transaction to ensure that we have the lock before performing the
2314 # Grab the transaction to ensure that we have the lock before performing the
2311 # pushkey.
2315 # pushkey.
2312 if op.ui.configbool(b'experimental', b'bundle2lazylocking'):
2316 if op.ui.configbool(b'experimental', b'bundle2lazylocking'):
2313 op.gettransaction()
2317 op.gettransaction()
2314 ret = op.repo.pushkey(namespace, key, old, new)
2318 ret = op.repo.pushkey(namespace, key, old, new)
2315 record = {b'namespace': namespace, b'key': key, b'old': old, b'new': new}
2319 record = {b'namespace': namespace, b'key': key, b'old': old, b'new': new}
2316 op.records.add(b'pushkey', record)
2320 op.records.add(b'pushkey', record)
2317 if op.reply is not None:
2321 if op.reply is not None:
2318 rpart = op.reply.newpart(b'reply:pushkey')
2322 rpart = op.reply.newpart(b'reply:pushkey')
2319 rpart.addparam(
2323 rpart.addparam(
2320 b'in-reply-to', pycompat.bytestr(inpart.id), mandatory=False
2324 b'in-reply-to', pycompat.bytestr(inpart.id), mandatory=False
2321 )
2325 )
2322 rpart.addparam(b'return', b'%i' % ret, mandatory=False)
2326 rpart.addparam(b'return', b'%i' % ret, mandatory=False)
2323 if inpart.mandatory and not ret:
2327 if inpart.mandatory and not ret:
2324 kwargs = {}
2328 kwargs = {}
2325 for key in (b'namespace', b'key', b'new', b'old', b'ret'):
2329 for key in (b'namespace', b'key', b'new', b'old', b'ret'):
2326 if key in inpart.params:
2330 if key in inpart.params:
2327 kwargs[key] = inpart.params[key]
2331 kwargs[key] = inpart.params[key]
2328 raise error.PushkeyFailed(
2332 raise error.PushkeyFailed(
2329 partid=b'%d' % inpart.id, **pycompat.strkwargs(kwargs)
2333 partid=b'%d' % inpart.id, **pycompat.strkwargs(kwargs)
2330 )
2334 )
2331
2335
2332
2336
2333 @parthandler(b'bookmarks')
2337 @parthandler(b'bookmarks')
2334 def handlebookmark(op, inpart):
2338 def handlebookmark(op, inpart):
2335 """transmit bookmark information
2339 """transmit bookmark information
2336
2340
2337 The part contains binary encoded bookmark information.
2341 The part contains binary encoded bookmark information.
2338
2342
2339 The exact behavior of this part can be controlled by the 'bookmarks' mode
2343 The exact behavior of this part can be controlled by the 'bookmarks' mode
2340 on the bundle operation.
2344 on the bundle operation.
2341
2345
2342 When mode is 'apply' (the default) the bookmark information is applied as
2346 When mode is 'apply' (the default) the bookmark information is applied as
2343 is to the unbundling repository. Make sure a 'check:bookmarks' part is
2347 is to the unbundling repository. Make sure a 'check:bookmarks' part is
2344 issued earlier to check for push races in such update. This behavior is
2348 issued earlier to check for push races in such update. This behavior is
2345 suitable for pushing.
2349 suitable for pushing.
2346
2350
2347 When mode is 'records', the information is recorded into the 'bookmarks'
2351 When mode is 'records', the information is recorded into the 'bookmarks'
2348 records of the bundle operation. This behavior is suitable for pulling.
2352 records of the bundle operation. This behavior is suitable for pulling.
2349 """
2353 """
2350 changes = bookmarks.binarydecode(inpart)
2354 changes = bookmarks.binarydecode(inpart)
2351
2355
2352 pushkeycompat = op.repo.ui.configbool(
2356 pushkeycompat = op.repo.ui.configbool(
2353 b'server', b'bookmarks-pushkey-compat'
2357 b'server', b'bookmarks-pushkey-compat'
2354 )
2358 )
2355 bookmarksmode = op.modes.get(b'bookmarks', b'apply')
2359 bookmarksmode = op.modes.get(b'bookmarks', b'apply')
2356
2360
2357 if bookmarksmode == b'apply':
2361 if bookmarksmode == b'apply':
2358 tr = op.gettransaction()
2362 tr = op.gettransaction()
2359 bookstore = op.repo._bookmarks
2363 bookstore = op.repo._bookmarks
2360 if pushkeycompat:
2364 if pushkeycompat:
2361 allhooks = []
2365 allhooks = []
2362 for book, node in changes:
2366 for book, node in changes:
2363 hookargs = tr.hookargs.copy()
2367 hookargs = tr.hookargs.copy()
2364 hookargs[b'pushkeycompat'] = b'1'
2368 hookargs[b'pushkeycompat'] = b'1'
2365 hookargs[b'namespace'] = b'bookmarks'
2369 hookargs[b'namespace'] = b'bookmarks'
2366 hookargs[b'key'] = book
2370 hookargs[b'key'] = book
2367 hookargs[b'old'] = hex(bookstore.get(book, b''))
2371 hookargs[b'old'] = hex(bookstore.get(book, b''))
2368 hookargs[b'new'] = hex(node if node is not None else b'')
2372 hookargs[b'new'] = hex(node if node is not None else b'')
2369 allhooks.append(hookargs)
2373 allhooks.append(hookargs)
2370
2374
2371 for hookargs in allhooks:
2375 for hookargs in allhooks:
2372 op.repo.hook(
2376 op.repo.hook(
2373 b'prepushkey', throw=True, **pycompat.strkwargs(hookargs)
2377 b'prepushkey', throw=True, **pycompat.strkwargs(hookargs)
2374 )
2378 )
2375
2379
2376 for book, node in changes:
2380 for book, node in changes:
2377 if bookmarks.isdivergent(book):
2381 if bookmarks.isdivergent(book):
2378 msg = _(b'cannot accept divergent bookmark %s!') % book
2382 msg = _(b'cannot accept divergent bookmark %s!') % book
2379 raise error.Abort(msg)
2383 raise error.Abort(msg)
2380
2384
2381 bookstore.applychanges(op.repo, op.gettransaction(), changes)
2385 bookstore.applychanges(op.repo, op.gettransaction(), changes)
2382
2386
2383 if pushkeycompat:
2387 if pushkeycompat:
2384
2388
2385 def runhook(unused_success):
2389 def runhook(unused_success):
2386 for hookargs in allhooks:
2390 for hookargs in allhooks:
2387 op.repo.hook(b'pushkey', **pycompat.strkwargs(hookargs))
2391 op.repo.hook(b'pushkey', **pycompat.strkwargs(hookargs))
2388
2392
2389 op.repo._afterlock(runhook)
2393 op.repo._afterlock(runhook)
2390
2394
2391 elif bookmarksmode == b'records':
2395 elif bookmarksmode == b'records':
2392 for book, node in changes:
2396 for book, node in changes:
2393 record = {b'bookmark': book, b'node': node}
2397 record = {b'bookmark': book, b'node': node}
2394 op.records.add(b'bookmarks', record)
2398 op.records.add(b'bookmarks', record)
2395 else:
2399 else:
2396 raise error.ProgrammingError(
2400 raise error.ProgrammingError(
2397 b'unkown bookmark mode: %s' % bookmarksmode
2401 b'unkown bookmark mode: %s' % bookmarksmode
2398 )
2402 )
2399
2403
2400
2404
2401 @parthandler(b'phase-heads')
2405 @parthandler(b'phase-heads')
2402 def handlephases(op, inpart):
2406 def handlephases(op, inpart):
2403 """apply phases from bundle part to repo"""
2407 """apply phases from bundle part to repo"""
2404 headsbyphase = phases.binarydecode(inpart)
2408 headsbyphase = phases.binarydecode(inpart)
2405 phases.updatephases(op.repo.unfiltered(), op.gettransaction, headsbyphase)
2409 phases.updatephases(op.repo.unfiltered(), op.gettransaction, headsbyphase)
2406
2410
2407
2411
2408 @parthandler(b'reply:pushkey', (b'return', b'in-reply-to'))
2412 @parthandler(b'reply:pushkey', (b'return', b'in-reply-to'))
2409 def handlepushkeyreply(op, inpart):
2413 def handlepushkeyreply(op, inpart):
2410 """retrieve the result of a pushkey request"""
2414 """retrieve the result of a pushkey request"""
2411 ret = int(inpart.params[b'return'])
2415 ret = int(inpart.params[b'return'])
2412 partid = int(inpart.params[b'in-reply-to'])
2416 partid = int(inpart.params[b'in-reply-to'])
2413 op.records.add(b'pushkey', {b'return': ret}, partid)
2417 op.records.add(b'pushkey', {b'return': ret}, partid)
2414
2418
2415
2419
2416 @parthandler(b'obsmarkers')
2420 @parthandler(b'obsmarkers')
2417 def handleobsmarker(op, inpart):
2421 def handleobsmarker(op, inpart):
2418 """add a stream of obsmarkers to the repo"""
2422 """add a stream of obsmarkers to the repo"""
2419 tr = op.gettransaction()
2423 tr = op.gettransaction()
2420 markerdata = inpart.read()
2424 markerdata = inpart.read()
2421 if op.ui.config(b'experimental', b'obsmarkers-exchange-debug'):
2425 if op.ui.config(b'experimental', b'obsmarkers-exchange-debug'):
2422 op.ui.writenoi18n(
2426 op.ui.writenoi18n(
2423 b'obsmarker-exchange: %i bytes received\n' % len(markerdata)
2427 b'obsmarker-exchange: %i bytes received\n' % len(markerdata)
2424 )
2428 )
2425 # The mergemarkers call will crash if marker creation is not enabled.
2429 # The mergemarkers call will crash if marker creation is not enabled.
2426 # we want to avoid this if the part is advisory.
2430 # we want to avoid this if the part is advisory.
2427 if not inpart.mandatory and op.repo.obsstore.readonly:
2431 if not inpart.mandatory and op.repo.obsstore.readonly:
2428 op.repo.ui.debug(
2432 op.repo.ui.debug(
2429 b'ignoring obsolescence markers, feature not enabled\n'
2433 b'ignoring obsolescence markers, feature not enabled\n'
2430 )
2434 )
2431 return
2435 return
2432 new = op.repo.obsstore.mergemarkers(tr, markerdata)
2436 new = op.repo.obsstore.mergemarkers(tr, markerdata)
2433 op.repo.invalidatevolatilesets()
2437 op.repo.invalidatevolatilesets()
2434 op.records.add(b'obsmarkers', {b'new': new})
2438 op.records.add(b'obsmarkers', {b'new': new})
2435 if op.reply is not None:
2439 if op.reply is not None:
2436 rpart = op.reply.newpart(b'reply:obsmarkers')
2440 rpart = op.reply.newpart(b'reply:obsmarkers')
2437 rpart.addparam(
2441 rpart.addparam(
2438 b'in-reply-to', pycompat.bytestr(inpart.id), mandatory=False
2442 b'in-reply-to', pycompat.bytestr(inpart.id), mandatory=False
2439 )
2443 )
2440 rpart.addparam(b'new', b'%i' % new, mandatory=False)
2444 rpart.addparam(b'new', b'%i' % new, mandatory=False)
2441
2445
2442
2446
2443 @parthandler(b'reply:obsmarkers', (b'new', b'in-reply-to'))
2447 @parthandler(b'reply:obsmarkers', (b'new', b'in-reply-to'))
2444 def handleobsmarkerreply(op, inpart):
2448 def handleobsmarkerreply(op, inpart):
2445 """retrieve the result of a pushkey request"""
2449 """retrieve the result of a pushkey request"""
2446 ret = int(inpart.params[b'new'])
2450 ret = int(inpart.params[b'new'])
2447 partid = int(inpart.params[b'in-reply-to'])
2451 partid = int(inpart.params[b'in-reply-to'])
2448 op.records.add(b'obsmarkers', {b'new': ret}, partid)
2452 op.records.add(b'obsmarkers', {b'new': ret}, partid)
2449
2453
2450
2454
2451 @parthandler(b'hgtagsfnodes')
2455 @parthandler(b'hgtagsfnodes')
2452 def handlehgtagsfnodes(op, inpart):
2456 def handlehgtagsfnodes(op, inpart):
2453 """Applies .hgtags fnodes cache entries to the local repo.
2457 """Applies .hgtags fnodes cache entries to the local repo.
2454
2458
2455 Payload is pairs of 20 byte changeset nodes and filenodes.
2459 Payload is pairs of 20 byte changeset nodes and filenodes.
2456 """
2460 """
2457 # Grab the transaction so we ensure that we have the lock at this point.
2461 # Grab the transaction so we ensure that we have the lock at this point.
2458 if op.ui.configbool(b'experimental', b'bundle2lazylocking'):
2462 if op.ui.configbool(b'experimental', b'bundle2lazylocking'):
2459 op.gettransaction()
2463 op.gettransaction()
2460 cache = tags.hgtagsfnodescache(op.repo.unfiltered())
2464 cache = tags.hgtagsfnodescache(op.repo.unfiltered())
2461
2465
2462 count = 0
2466 count = 0
2463 while True:
2467 while True:
2464 node = inpart.read(20)
2468 node = inpart.read(20)
2465 fnode = inpart.read(20)
2469 fnode = inpart.read(20)
2466 if len(node) < 20 or len(fnode) < 20:
2470 if len(node) < 20 or len(fnode) < 20:
2467 op.ui.debug(b'ignoring incomplete received .hgtags fnodes data\n')
2471 op.ui.debug(b'ignoring incomplete received .hgtags fnodes data\n')
2468 break
2472 break
2469 cache.setfnode(node, fnode)
2473 cache.setfnode(node, fnode)
2470 count += 1
2474 count += 1
2471
2475
2472 cache.write()
2476 cache.write()
2473 op.ui.debug(b'applied %i hgtags fnodes cache entries\n' % count)
2477 op.ui.debug(b'applied %i hgtags fnodes cache entries\n' % count)
2474
2478
2475
2479
2476 rbcstruct = struct.Struct(b'>III')
2480 rbcstruct = struct.Struct(b'>III')
2477
2481
2478
2482
2479 @parthandler(b'cache:rev-branch-cache')
2483 @parthandler(b'cache:rev-branch-cache')
2480 def handlerbc(op, inpart):
2484 def handlerbc(op, inpart):
2481 """receive a rev-branch-cache payload and update the local cache
2485 """receive a rev-branch-cache payload and update the local cache
2482
2486
2483 The payload is a series of data related to each branch
2487 The payload is a series of data related to each branch
2484
2488
2485 1) branch name length
2489 1) branch name length
2486 2) number of open heads
2490 2) number of open heads
2487 3) number of closed heads
2491 3) number of closed heads
2488 4) open heads nodes
2492 4) open heads nodes
2489 5) closed heads nodes
2493 5) closed heads nodes
2490 """
2494 """
2491 total = 0
2495 total = 0
2492 rawheader = inpart.read(rbcstruct.size)
2496 rawheader = inpart.read(rbcstruct.size)
2493 cache = op.repo.revbranchcache()
2497 cache = op.repo.revbranchcache()
2494 cl = op.repo.unfiltered().changelog
2498 cl = op.repo.unfiltered().changelog
2495 while rawheader:
2499 while rawheader:
2496 header = rbcstruct.unpack(rawheader)
2500 header = rbcstruct.unpack(rawheader)
2497 total += header[1] + header[2]
2501 total += header[1] + header[2]
2498 utf8branch = inpart.read(header[0])
2502 utf8branch = inpart.read(header[0])
2499 branch = encoding.tolocal(utf8branch)
2503 branch = encoding.tolocal(utf8branch)
2500 for x in pycompat.xrange(header[1]):
2504 for x in pycompat.xrange(header[1]):
2501 node = inpart.read(20)
2505 node = inpart.read(20)
2502 rev = cl.rev(node)
2506 rev = cl.rev(node)
2503 cache.setdata(branch, rev, node, False)
2507 cache.setdata(branch, rev, node, False)
2504 for x in pycompat.xrange(header[2]):
2508 for x in pycompat.xrange(header[2]):
2505 node = inpart.read(20)
2509 node = inpart.read(20)
2506 rev = cl.rev(node)
2510 rev = cl.rev(node)
2507 cache.setdata(branch, rev, node, True)
2511 cache.setdata(branch, rev, node, True)
2508 rawheader = inpart.read(rbcstruct.size)
2512 rawheader = inpart.read(rbcstruct.size)
2509 cache.write()
2513 cache.write()
2510
2514
2511
2515
2512 @parthandler(b'pushvars')
2516 @parthandler(b'pushvars')
2513 def bundle2getvars(op, part):
2517 def bundle2getvars(op, part):
2514 '''unbundle a bundle2 containing shellvars on the server'''
2518 '''unbundle a bundle2 containing shellvars on the server'''
2515 # An option to disable unbundling on server-side for security reasons
2519 # An option to disable unbundling on server-side for security reasons
2516 if op.ui.configbool(b'push', b'pushvars.server'):
2520 if op.ui.configbool(b'push', b'pushvars.server'):
2517 hookargs = {}
2521 hookargs = {}
2518 for key, value in part.advisoryparams:
2522 for key, value in part.advisoryparams:
2519 key = key.upper()
2523 key = key.upper()
2520 # We want pushed variables to have USERVAR_ prepended so we know
2524 # We want pushed variables to have USERVAR_ prepended so we know
2521 # they came from the --pushvar flag.
2525 # they came from the --pushvar flag.
2522 key = b"USERVAR_" + key
2526 key = b"USERVAR_" + key
2523 hookargs[key] = value
2527 hookargs[key] = value
2524 op.addhookargs(hookargs)
2528 op.addhookargs(hookargs)
2525
2529
2526
2530
2527 @parthandler(b'stream2', (b'requirements', b'filecount', b'bytecount'))
2531 @parthandler(b'stream2', (b'requirements', b'filecount', b'bytecount'))
2528 def handlestreamv2bundle(op, part):
2532 def handlestreamv2bundle(op, part):
2529
2533
2530 requirements = urlreq.unquote(part.params[b'requirements']).split(b',')
2534 requirements = urlreq.unquote(part.params[b'requirements']).split(b',')
2531 filecount = int(part.params[b'filecount'])
2535 filecount = int(part.params[b'filecount'])
2532 bytecount = int(part.params[b'bytecount'])
2536 bytecount = int(part.params[b'bytecount'])
2533
2537
2534 repo = op.repo
2538 repo = op.repo
2535 if len(repo):
2539 if len(repo):
2536 msg = _(b'cannot apply stream clone to non empty repository')
2540 msg = _(b'cannot apply stream clone to non empty repository')
2537 raise error.Abort(msg)
2541 raise error.Abort(msg)
2538
2542
2539 repo.ui.debug(b'applying stream bundle\n')
2543 repo.ui.debug(b'applying stream bundle\n')
2540 streamclone.applybundlev2(repo, part, filecount, bytecount, requirements)
2544 streamclone.applybundlev2(repo, part, filecount, bytecount, requirements)
2541
2545
2542
2546
2543 def widen_bundle(
2547 def widen_bundle(
2544 bundler, repo, oldmatcher, newmatcher, common, known, cgversion, ellipses
2548 bundler, repo, oldmatcher, newmatcher, common, known, cgversion, ellipses
2545 ):
2549 ):
2546 """generates bundle2 for widening a narrow clone
2550 """generates bundle2 for widening a narrow clone
2547
2551
2548 bundler is the bundle to which data should be added
2552 bundler is the bundle to which data should be added
2549 repo is the localrepository instance
2553 repo is the localrepository instance
2550 oldmatcher matches what the client already has
2554 oldmatcher matches what the client already has
2551 newmatcher matches what the client needs (including what it already has)
2555 newmatcher matches what the client needs (including what it already has)
2552 common is set of common heads between server and client
2556 common is set of common heads between server and client
2553 known is a set of revs known on the client side (used in ellipses)
2557 known is a set of revs known on the client side (used in ellipses)
2554 cgversion is the changegroup version to send
2558 cgversion is the changegroup version to send
2555 ellipses is boolean value telling whether to send ellipses data or not
2559 ellipses is boolean value telling whether to send ellipses data or not
2556
2560
2557 returns bundle2 of the data required for extending
2561 returns bundle2 of the data required for extending
2558 """
2562 """
2559 commonnodes = set()
2563 commonnodes = set()
2560 cl = repo.changelog
2564 cl = repo.changelog
2561 for r in repo.revs(b"::%ln", common):
2565 for r in repo.revs(b"::%ln", common):
2562 commonnodes.add(cl.node(r))
2566 commonnodes.add(cl.node(r))
2563 if commonnodes:
2567 if commonnodes:
2564 # XXX: we should only send the filelogs (and treemanifest). user
2568 # XXX: we should only send the filelogs (and treemanifest). user
2565 # already has the changelog and manifest
2569 # already has the changelog and manifest
2566 packer = changegroup.getbundler(
2570 packer = changegroup.getbundler(
2567 cgversion,
2571 cgversion,
2568 repo,
2572 repo,
2569 oldmatcher=oldmatcher,
2573 oldmatcher=oldmatcher,
2570 matcher=newmatcher,
2574 matcher=newmatcher,
2571 fullnodes=commonnodes,
2575 fullnodes=commonnodes,
2572 )
2576 )
2573 cgdata = packer.generate(
2577 cgdata = packer.generate(
2574 {nullid},
2578 {nullid},
2575 list(commonnodes),
2579 list(commonnodes),
2576 False,
2580 False,
2577 b'narrow_widen',
2581 b'narrow_widen',
2578 changelog=False,
2582 changelog=False,
2579 )
2583 )
2580
2584
2581 part = bundler.newpart(b'changegroup', data=cgdata)
2585 part = bundler.newpart(b'changegroup', data=cgdata)
2582 part.addparam(b'version', cgversion)
2586 part.addparam(b'version', cgversion)
2583 if scmutil.istreemanifest(repo):
2587 if scmutil.istreemanifest(repo):
2584 part.addparam(b'treemanifest', b'1')
2588 part.addparam(b'treemanifest', b'1')
2585 if b'exp-sidedata-flag' in repo.requirements:
2589 if b'exp-sidedata-flag' in repo.requirements:
2586 part.addparam(b'exp-sidedata', b'1')
2590 part.addparam(b'exp-sidedata', b'1')
2587
2591
2588 return bundler
2592 return bundler
@@ -1,7747 +1,7752
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 __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import errno
10 import errno
11 import os
11 import os
12 import re
12 import re
13 import sys
13 import sys
14
14
15 from .i18n import _
15 from .i18n import _
16 from .node import (
16 from .node import (
17 hex,
17 hex,
18 nullid,
18 nullid,
19 nullrev,
19 nullrev,
20 short,
20 short,
21 wdirhex,
21 wdirhex,
22 wdirrev,
22 wdirrev,
23 )
23 )
24 from .pycompat import open
24 from .pycompat import open
25 from . import (
25 from . import (
26 archival,
26 archival,
27 bookmarks,
27 bookmarks,
28 bundle2,
28 bundle2,
29 bundlecaches,
29 bundlecaches,
30 changegroup,
30 changegroup,
31 cmdutil,
31 cmdutil,
32 copies,
32 copies,
33 debugcommands as debugcommandsmod,
33 debugcommands as debugcommandsmod,
34 destutil,
34 destutil,
35 dirstateguard,
35 dirstateguard,
36 discovery,
36 discovery,
37 encoding,
37 encoding,
38 error,
38 error,
39 exchange,
39 exchange,
40 extensions,
40 extensions,
41 filemerge,
41 filemerge,
42 formatter,
42 formatter,
43 graphmod,
43 graphmod,
44 grep as grepmod,
44 grep as grepmod,
45 hbisect,
45 hbisect,
46 help,
46 help,
47 hg,
47 hg,
48 logcmdutil,
48 logcmdutil,
49 merge as mergemod,
49 merge as mergemod,
50 mergestate as mergestatemod,
50 mergestate as mergestatemod,
51 narrowspec,
51 narrowspec,
52 obsolete,
52 obsolete,
53 obsutil,
53 obsutil,
54 patch,
54 patch,
55 phases,
55 phases,
56 pycompat,
56 pycompat,
57 rcutil,
57 rcutil,
58 registrar,
58 registrar,
59 requirements,
59 requirements,
60 revsetlang,
60 revsetlang,
61 rewriteutil,
61 rewriteutil,
62 scmutil,
62 scmutil,
63 server,
63 server,
64 shelve as shelvemod,
64 shelve as shelvemod,
65 state as statemod,
65 state as statemod,
66 streamclone,
66 streamclone,
67 tags as tagsmod,
67 tags as tagsmod,
68 ui as uimod,
68 ui as uimod,
69 util,
69 util,
70 verify as verifymod,
70 verify as verifymod,
71 vfs as vfsmod,
71 vfs as vfsmod,
72 wireprotoserver,
72 wireprotoserver,
73 )
73 )
74 from .utils import (
74 from .utils import (
75 dateutil,
75 dateutil,
76 stringutil,
76 stringutil,
77 )
77 )
78
78
79 table = {}
79 table = {}
80 table.update(debugcommandsmod.command._table)
80 table.update(debugcommandsmod.command._table)
81
81
82 command = registrar.command(table)
82 command = registrar.command(table)
83 INTENT_READONLY = registrar.INTENT_READONLY
83 INTENT_READONLY = registrar.INTENT_READONLY
84
84
85 # common command options
85 # common command options
86
86
87 globalopts = [
87 globalopts = [
88 (
88 (
89 b'R',
89 b'R',
90 b'repository',
90 b'repository',
91 b'',
91 b'',
92 _(b'repository root directory or name of overlay bundle file'),
92 _(b'repository root directory or name of overlay bundle file'),
93 _(b'REPO'),
93 _(b'REPO'),
94 ),
94 ),
95 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
95 (b'', b'cwd', b'', _(b'change working directory'), _(b'DIR')),
96 (
96 (
97 b'y',
97 b'y',
98 b'noninteractive',
98 b'noninteractive',
99 None,
99 None,
100 _(
100 _(
101 b'do not prompt, automatically pick the first choice for all prompts'
101 b'do not prompt, automatically pick the first choice for all prompts'
102 ),
102 ),
103 ),
103 ),
104 (b'q', b'quiet', None, _(b'suppress output')),
104 (b'q', b'quiet', None, _(b'suppress output')),
105 (b'v', b'verbose', None, _(b'enable additional output')),
105 (b'v', b'verbose', None, _(b'enable additional output')),
106 (
106 (
107 b'',
107 b'',
108 b'color',
108 b'color',
109 b'',
109 b'',
110 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
110 # i18n: 'always', 'auto', 'never', and 'debug' are keywords
111 # and should not be translated
111 # and should not be translated
112 _(b"when to colorize (boolean, always, auto, never, or debug)"),
112 _(b"when to colorize (boolean, always, auto, never, or debug)"),
113 _(b'TYPE'),
113 _(b'TYPE'),
114 ),
114 ),
115 (
115 (
116 b'',
116 b'',
117 b'config',
117 b'config',
118 [],
118 [],
119 _(b'set/override config option (use \'section.name=value\')'),
119 _(b'set/override config option (use \'section.name=value\')'),
120 _(b'CONFIG'),
120 _(b'CONFIG'),
121 ),
121 ),
122 (b'', b'debug', None, _(b'enable debugging output')),
122 (b'', b'debug', None, _(b'enable debugging output')),
123 (b'', b'debugger', None, _(b'start debugger')),
123 (b'', b'debugger', None, _(b'start debugger')),
124 (
124 (
125 b'',
125 b'',
126 b'encoding',
126 b'encoding',
127 encoding.encoding,
127 encoding.encoding,
128 _(b'set the charset encoding'),
128 _(b'set the charset encoding'),
129 _(b'ENCODE'),
129 _(b'ENCODE'),
130 ),
130 ),
131 (
131 (
132 b'',
132 b'',
133 b'encodingmode',
133 b'encodingmode',
134 encoding.encodingmode,
134 encoding.encodingmode,
135 _(b'set the charset encoding mode'),
135 _(b'set the charset encoding mode'),
136 _(b'MODE'),
136 _(b'MODE'),
137 ),
137 ),
138 (b'', b'traceback', None, _(b'always print a traceback on exception')),
138 (b'', b'traceback', None, _(b'always print a traceback on exception')),
139 (b'', b'time', None, _(b'time how long the command takes')),
139 (b'', b'time', None, _(b'time how long the command takes')),
140 (b'', b'profile', None, _(b'print command execution profile')),
140 (b'', b'profile', None, _(b'print command execution profile')),
141 (b'', b'version', None, _(b'output version information and exit')),
141 (b'', b'version', None, _(b'output version information and exit')),
142 (b'h', b'help', None, _(b'display help and exit')),
142 (b'h', b'help', None, _(b'display help and exit')),
143 (b'', b'hidden', False, _(b'consider hidden changesets')),
143 (b'', b'hidden', False, _(b'consider hidden changesets')),
144 (
144 (
145 b'',
145 b'',
146 b'pager',
146 b'pager',
147 b'auto',
147 b'auto',
148 _(b"when to paginate (boolean, always, auto, or never)"),
148 _(b"when to paginate (boolean, always, auto, or never)"),
149 _(b'TYPE'),
149 _(b'TYPE'),
150 ),
150 ),
151 ]
151 ]
152
152
153 dryrunopts = cmdutil.dryrunopts
153 dryrunopts = cmdutil.dryrunopts
154 remoteopts = cmdutil.remoteopts
154 remoteopts = cmdutil.remoteopts
155 walkopts = cmdutil.walkopts
155 walkopts = cmdutil.walkopts
156 commitopts = cmdutil.commitopts
156 commitopts = cmdutil.commitopts
157 commitopts2 = cmdutil.commitopts2
157 commitopts2 = cmdutil.commitopts2
158 commitopts3 = cmdutil.commitopts3
158 commitopts3 = cmdutil.commitopts3
159 formatteropts = cmdutil.formatteropts
159 formatteropts = cmdutil.formatteropts
160 templateopts = cmdutil.templateopts
160 templateopts = cmdutil.templateopts
161 logopts = cmdutil.logopts
161 logopts = cmdutil.logopts
162 diffopts = cmdutil.diffopts
162 diffopts = cmdutil.diffopts
163 diffwsopts = cmdutil.diffwsopts
163 diffwsopts = cmdutil.diffwsopts
164 diffopts2 = cmdutil.diffopts2
164 diffopts2 = cmdutil.diffopts2
165 mergetoolopts = cmdutil.mergetoolopts
165 mergetoolopts = cmdutil.mergetoolopts
166 similarityopts = cmdutil.similarityopts
166 similarityopts = cmdutil.similarityopts
167 subrepoopts = cmdutil.subrepoopts
167 subrepoopts = cmdutil.subrepoopts
168 debugrevlogopts = cmdutil.debugrevlogopts
168 debugrevlogopts = cmdutil.debugrevlogopts
169
169
170 # Commands start here, listed alphabetically
170 # Commands start here, listed alphabetically
171
171
172
172
173 @command(
173 @command(
174 b'abort',
174 b'abort',
175 dryrunopts,
175 dryrunopts,
176 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
176 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
177 helpbasic=True,
177 helpbasic=True,
178 )
178 )
179 def abort(ui, repo, **opts):
179 def abort(ui, repo, **opts):
180 """abort an unfinished operation (EXPERIMENTAL)
180 """abort an unfinished operation (EXPERIMENTAL)
181
181
182 Aborts a multistep operation like graft, histedit, rebase, merge,
182 Aborts a multistep operation like graft, histedit, rebase, merge,
183 and unshelve if they are in an unfinished state.
183 and unshelve if they are in an unfinished state.
184
184
185 use --dry-run/-n to dry run the command.
185 use --dry-run/-n to dry run the command.
186 """
186 """
187 dryrun = opts.get('dry_run')
187 dryrun = opts.get('dry_run')
188 abortstate = cmdutil.getunfinishedstate(repo)
188 abortstate = cmdutil.getunfinishedstate(repo)
189 if not abortstate:
189 if not abortstate:
190 raise error.StateError(_(b'no operation in progress'))
190 raise error.StateError(_(b'no operation in progress'))
191 if not abortstate.abortfunc:
191 if not abortstate.abortfunc:
192 raise error.InputError(
192 raise error.InputError(
193 (
193 (
194 _(b"%s in progress but does not support 'hg abort'")
194 _(b"%s in progress but does not support 'hg abort'")
195 % (abortstate._opname)
195 % (abortstate._opname)
196 ),
196 ),
197 hint=abortstate.hint(),
197 hint=abortstate.hint(),
198 )
198 )
199 if dryrun:
199 if dryrun:
200 ui.status(
200 ui.status(
201 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
201 _(b'%s in progress, will be aborted\n') % (abortstate._opname)
202 )
202 )
203 return
203 return
204 return abortstate.abortfunc(ui, repo)
204 return abortstate.abortfunc(ui, repo)
205
205
206
206
207 @command(
207 @command(
208 b'add',
208 b'add',
209 walkopts + subrepoopts + dryrunopts,
209 walkopts + subrepoopts + dryrunopts,
210 _(b'[OPTION]... [FILE]...'),
210 _(b'[OPTION]... [FILE]...'),
211 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
211 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
212 helpbasic=True,
212 helpbasic=True,
213 inferrepo=True,
213 inferrepo=True,
214 )
214 )
215 def add(ui, repo, *pats, **opts):
215 def add(ui, repo, *pats, **opts):
216 """add the specified files on the next commit
216 """add the specified files on the next commit
217
217
218 Schedule files to be version controlled and added to the
218 Schedule files to be version controlled and added to the
219 repository.
219 repository.
220
220
221 The files will be added to the repository at the next commit. To
221 The files will be added to the repository at the next commit. To
222 undo an add before that, see :hg:`forget`.
222 undo an add before that, see :hg:`forget`.
223
223
224 If no names are given, add all files to the repository (except
224 If no names are given, add all files to the repository (except
225 files matching ``.hgignore``).
225 files matching ``.hgignore``).
226
226
227 .. container:: verbose
227 .. container:: verbose
228
228
229 Examples:
229 Examples:
230
230
231 - New (unknown) files are added
231 - New (unknown) files are added
232 automatically by :hg:`add`::
232 automatically by :hg:`add`::
233
233
234 $ ls
234 $ ls
235 foo.c
235 foo.c
236 $ hg status
236 $ hg status
237 ? foo.c
237 ? foo.c
238 $ hg add
238 $ hg add
239 adding foo.c
239 adding foo.c
240 $ hg status
240 $ hg status
241 A foo.c
241 A foo.c
242
242
243 - Specific files to be added can be specified::
243 - Specific files to be added can be specified::
244
244
245 $ ls
245 $ ls
246 bar.c foo.c
246 bar.c foo.c
247 $ hg status
247 $ hg status
248 ? bar.c
248 ? bar.c
249 ? foo.c
249 ? foo.c
250 $ hg add bar.c
250 $ hg add bar.c
251 $ hg status
251 $ hg status
252 A bar.c
252 A bar.c
253 ? foo.c
253 ? foo.c
254
254
255 Returns 0 if all files are successfully added.
255 Returns 0 if all files are successfully added.
256 """
256 """
257
257
258 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
258 m = scmutil.match(repo[None], pats, pycompat.byteskwargs(opts))
259 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
259 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
260 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
260 rejected = cmdutil.add(ui, repo, m, b"", uipathfn, False, **opts)
261 return rejected and 1 or 0
261 return rejected and 1 or 0
262
262
263
263
264 @command(
264 @command(
265 b'addremove',
265 b'addremove',
266 similarityopts + subrepoopts + walkopts + dryrunopts,
266 similarityopts + subrepoopts + walkopts + dryrunopts,
267 _(b'[OPTION]... [FILE]...'),
267 _(b'[OPTION]... [FILE]...'),
268 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
268 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
269 inferrepo=True,
269 inferrepo=True,
270 )
270 )
271 def addremove(ui, repo, *pats, **opts):
271 def addremove(ui, repo, *pats, **opts):
272 """add all new files, delete all missing files
272 """add all new files, delete all missing files
273
273
274 Add all new files and remove all missing files from the
274 Add all new files and remove all missing files from the
275 repository.
275 repository.
276
276
277 Unless names are given, new files are ignored if they match any of
277 Unless names are given, new files are ignored if they match any of
278 the patterns in ``.hgignore``. As with add, these changes take
278 the patterns in ``.hgignore``. As with add, these changes take
279 effect at the next commit.
279 effect at the next commit.
280
280
281 Use the -s/--similarity option to detect renamed files. This
281 Use the -s/--similarity option to detect renamed files. This
282 option takes a percentage between 0 (disabled) and 100 (files must
282 option takes a percentage between 0 (disabled) and 100 (files must
283 be identical) as its parameter. With a parameter greater than 0,
283 be identical) as its parameter. With a parameter greater than 0,
284 this compares every removed file with every added file and records
284 this compares every removed file with every added file and records
285 those similar enough as renames. Detecting renamed files this way
285 those similar enough as renames. Detecting renamed files this way
286 can be expensive. After using this option, :hg:`status -C` can be
286 can be expensive. After using this option, :hg:`status -C` can be
287 used to check which files were identified as moved or renamed. If
287 used to check which files were identified as moved or renamed. If
288 not specified, -s/--similarity defaults to 100 and only renames of
288 not specified, -s/--similarity defaults to 100 and only renames of
289 identical files are detected.
289 identical files are detected.
290
290
291 .. container:: verbose
291 .. container:: verbose
292
292
293 Examples:
293 Examples:
294
294
295 - A number of files (bar.c and foo.c) are new,
295 - A number of files (bar.c and foo.c) are new,
296 while foobar.c has been removed (without using :hg:`remove`)
296 while foobar.c has been removed (without using :hg:`remove`)
297 from the repository::
297 from the repository::
298
298
299 $ ls
299 $ ls
300 bar.c foo.c
300 bar.c foo.c
301 $ hg status
301 $ hg status
302 ! foobar.c
302 ! foobar.c
303 ? bar.c
303 ? bar.c
304 ? foo.c
304 ? foo.c
305 $ hg addremove
305 $ hg addremove
306 adding bar.c
306 adding bar.c
307 adding foo.c
307 adding foo.c
308 removing foobar.c
308 removing foobar.c
309 $ hg status
309 $ hg status
310 A bar.c
310 A bar.c
311 A foo.c
311 A foo.c
312 R foobar.c
312 R foobar.c
313
313
314 - A file foobar.c was moved to foo.c without using :hg:`rename`.
314 - A file foobar.c was moved to foo.c without using :hg:`rename`.
315 Afterwards, it was edited slightly::
315 Afterwards, it was edited slightly::
316
316
317 $ ls
317 $ ls
318 foo.c
318 foo.c
319 $ hg status
319 $ hg status
320 ! foobar.c
320 ! foobar.c
321 ? foo.c
321 ? foo.c
322 $ hg addremove --similarity 90
322 $ hg addremove --similarity 90
323 removing foobar.c
323 removing foobar.c
324 adding foo.c
324 adding foo.c
325 recording removal of foobar.c as rename to foo.c (94% similar)
325 recording removal of foobar.c as rename to foo.c (94% similar)
326 $ hg status -C
326 $ hg status -C
327 A foo.c
327 A foo.c
328 foobar.c
328 foobar.c
329 R foobar.c
329 R foobar.c
330
330
331 Returns 0 if all files are successfully added.
331 Returns 0 if all files are successfully added.
332 """
332 """
333 opts = pycompat.byteskwargs(opts)
333 opts = pycompat.byteskwargs(opts)
334 if not opts.get(b'similarity'):
334 if not opts.get(b'similarity'):
335 opts[b'similarity'] = b'100'
335 opts[b'similarity'] = b'100'
336 matcher = scmutil.match(repo[None], pats, opts)
336 matcher = scmutil.match(repo[None], pats, opts)
337 relative = scmutil.anypats(pats, opts)
337 relative = scmutil.anypats(pats, opts)
338 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
338 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=relative)
339 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
339 return scmutil.addremove(repo, matcher, b"", uipathfn, opts)
340
340
341
341
342 @command(
342 @command(
343 b'annotate|blame',
343 b'annotate|blame',
344 [
344 [
345 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
345 (b'r', b'rev', b'', _(b'annotate the specified revision'), _(b'REV')),
346 (
346 (
347 b'',
347 b'',
348 b'follow',
348 b'follow',
349 None,
349 None,
350 _(b'follow copies/renames and list the filename (DEPRECATED)'),
350 _(b'follow copies/renames and list the filename (DEPRECATED)'),
351 ),
351 ),
352 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
352 (b'', b'no-follow', None, _(b"don't follow copies and renames")),
353 (b'a', b'text', None, _(b'treat all files as text')),
353 (b'a', b'text', None, _(b'treat all files as text')),
354 (b'u', b'user', None, _(b'list the author (long with -v)')),
354 (b'u', b'user', None, _(b'list the author (long with -v)')),
355 (b'f', b'file', None, _(b'list the filename')),
355 (b'f', b'file', None, _(b'list the filename')),
356 (b'd', b'date', None, _(b'list the date (short with -q)')),
356 (b'd', b'date', None, _(b'list the date (short with -q)')),
357 (b'n', b'number', None, _(b'list the revision number (default)')),
357 (b'n', b'number', None, _(b'list the revision number (default)')),
358 (b'c', b'changeset', None, _(b'list the changeset')),
358 (b'c', b'changeset', None, _(b'list the changeset')),
359 (
359 (
360 b'l',
360 b'l',
361 b'line-number',
361 b'line-number',
362 None,
362 None,
363 _(b'show line number at the first appearance'),
363 _(b'show line number at the first appearance'),
364 ),
364 ),
365 (
365 (
366 b'',
366 b'',
367 b'skip',
367 b'skip',
368 [],
368 [],
369 _(b'revset to not display (EXPERIMENTAL)'),
369 _(b'revset to not display (EXPERIMENTAL)'),
370 _(b'REV'),
370 _(b'REV'),
371 ),
371 ),
372 ]
372 ]
373 + diffwsopts
373 + diffwsopts
374 + walkopts
374 + walkopts
375 + formatteropts,
375 + formatteropts,
376 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
376 _(b'[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
377 helpcategory=command.CATEGORY_FILE_CONTENTS,
377 helpcategory=command.CATEGORY_FILE_CONTENTS,
378 helpbasic=True,
378 helpbasic=True,
379 inferrepo=True,
379 inferrepo=True,
380 )
380 )
381 def annotate(ui, repo, *pats, **opts):
381 def annotate(ui, repo, *pats, **opts):
382 """show changeset information by line for each file
382 """show changeset information by line for each file
383
383
384 List changes in files, showing the revision id responsible for
384 List changes in files, showing the revision id responsible for
385 each line.
385 each line.
386
386
387 This command is useful for discovering when a change was made and
387 This command is useful for discovering when a change was made and
388 by whom.
388 by whom.
389
389
390 If you include --file, --user, or --date, the revision number is
390 If you include --file, --user, or --date, the revision number is
391 suppressed unless you also include --number.
391 suppressed unless you also include --number.
392
392
393 Without the -a/--text option, annotate will avoid processing files
393 Without the -a/--text option, annotate will avoid processing files
394 it detects as binary. With -a, annotate will annotate the file
394 it detects as binary. With -a, annotate will annotate the file
395 anyway, although the results will probably be neither useful
395 anyway, although the results will probably be neither useful
396 nor desirable.
396 nor desirable.
397
397
398 .. container:: verbose
398 .. container:: verbose
399
399
400 Template:
400 Template:
401
401
402 The following keywords are supported in addition to the common template
402 The following keywords are supported in addition to the common template
403 keywords and functions. See also :hg:`help templates`.
403 keywords and functions. See also :hg:`help templates`.
404
404
405 :lines: List of lines with annotation data.
405 :lines: List of lines with annotation data.
406 :path: String. Repository-absolute path of the specified file.
406 :path: String. Repository-absolute path of the specified file.
407
407
408 And each entry of ``{lines}`` provides the following sub-keywords in
408 And each entry of ``{lines}`` provides the following sub-keywords in
409 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
409 addition to ``{date}``, ``{node}``, ``{rev}``, ``{user}``, etc.
410
410
411 :line: String. Line content.
411 :line: String. Line content.
412 :lineno: Integer. Line number at that revision.
412 :lineno: Integer. Line number at that revision.
413 :path: String. Repository-absolute path of the file at that revision.
413 :path: String. Repository-absolute path of the file at that revision.
414
414
415 See :hg:`help templates.operators` for the list expansion syntax.
415 See :hg:`help templates.operators` for the list expansion syntax.
416
416
417 Returns 0 on success.
417 Returns 0 on success.
418 """
418 """
419 opts = pycompat.byteskwargs(opts)
419 opts = pycompat.byteskwargs(opts)
420 if not pats:
420 if not pats:
421 raise error.InputError(
421 raise error.InputError(
422 _(b'at least one filename or pattern is required')
422 _(b'at least one filename or pattern is required')
423 )
423 )
424
424
425 if opts.get(b'follow'):
425 if opts.get(b'follow'):
426 # --follow is deprecated and now just an alias for -f/--file
426 # --follow is deprecated and now just an alias for -f/--file
427 # to mimic the behavior of Mercurial before version 1.5
427 # to mimic the behavior of Mercurial before version 1.5
428 opts[b'file'] = True
428 opts[b'file'] = True
429
429
430 if (
430 if (
431 not opts.get(b'user')
431 not opts.get(b'user')
432 and not opts.get(b'changeset')
432 and not opts.get(b'changeset')
433 and not opts.get(b'date')
433 and not opts.get(b'date')
434 and not opts.get(b'file')
434 and not opts.get(b'file')
435 ):
435 ):
436 opts[b'number'] = True
436 opts[b'number'] = True
437
437
438 linenumber = opts.get(b'line_number') is not None
438 linenumber = opts.get(b'line_number') is not None
439 if (
439 if (
440 linenumber
440 linenumber
441 and (not opts.get(b'changeset'))
441 and (not opts.get(b'changeset'))
442 and (not opts.get(b'number'))
442 and (not opts.get(b'number'))
443 ):
443 ):
444 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
444 raise error.InputError(_(b'at least one of -n/-c is required for -l'))
445
445
446 rev = opts.get(b'rev')
446 rev = opts.get(b'rev')
447 if rev:
447 if rev:
448 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
448 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
449 ctx = scmutil.revsingle(repo, rev)
449 ctx = scmutil.revsingle(repo, rev)
450
450
451 ui.pager(b'annotate')
451 ui.pager(b'annotate')
452 rootfm = ui.formatter(b'annotate', opts)
452 rootfm = ui.formatter(b'annotate', opts)
453 if ui.debugflag:
453 if ui.debugflag:
454 shorthex = pycompat.identity
454 shorthex = pycompat.identity
455 else:
455 else:
456
456
457 def shorthex(h):
457 def shorthex(h):
458 return h[:12]
458 return h[:12]
459
459
460 if ui.quiet:
460 if ui.quiet:
461 datefunc = dateutil.shortdate
461 datefunc = dateutil.shortdate
462 else:
462 else:
463 datefunc = dateutil.datestr
463 datefunc = dateutil.datestr
464 if ctx.rev() is None:
464 if ctx.rev() is None:
465 if opts.get(b'changeset'):
465 if opts.get(b'changeset'):
466 # omit "+" suffix which is appended to node hex
466 # omit "+" suffix which is appended to node hex
467 def formatrev(rev):
467 def formatrev(rev):
468 if rev == wdirrev:
468 if rev == wdirrev:
469 return b'%d' % ctx.p1().rev()
469 return b'%d' % ctx.p1().rev()
470 else:
470 else:
471 return b'%d' % rev
471 return b'%d' % rev
472
472
473 else:
473 else:
474
474
475 def formatrev(rev):
475 def formatrev(rev):
476 if rev == wdirrev:
476 if rev == wdirrev:
477 return b'%d+' % ctx.p1().rev()
477 return b'%d+' % ctx.p1().rev()
478 else:
478 else:
479 return b'%d ' % rev
479 return b'%d ' % rev
480
480
481 def formathex(h):
481 def formathex(h):
482 if h == wdirhex:
482 if h == wdirhex:
483 return b'%s+' % shorthex(hex(ctx.p1().node()))
483 return b'%s+' % shorthex(hex(ctx.p1().node()))
484 else:
484 else:
485 return b'%s ' % shorthex(h)
485 return b'%s ' % shorthex(h)
486
486
487 else:
487 else:
488 formatrev = b'%d'.__mod__
488 formatrev = b'%d'.__mod__
489 formathex = shorthex
489 formathex = shorthex
490
490
491 opmap = [
491 opmap = [
492 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
492 (b'user', b' ', lambda x: x.fctx.user(), ui.shortuser),
493 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
493 (b'rev', b' ', lambda x: scmutil.intrev(x.fctx), formatrev),
494 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
494 (b'node', b' ', lambda x: hex(scmutil.binnode(x.fctx)), formathex),
495 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
495 (b'date', b' ', lambda x: x.fctx.date(), util.cachefunc(datefunc)),
496 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
496 (b'path', b' ', lambda x: x.fctx.path(), pycompat.bytestr),
497 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
497 (b'lineno', b':', lambda x: x.lineno, pycompat.bytestr),
498 ]
498 ]
499 opnamemap = {
499 opnamemap = {
500 b'rev': b'number',
500 b'rev': b'number',
501 b'node': b'changeset',
501 b'node': b'changeset',
502 b'path': b'file',
502 b'path': b'file',
503 b'lineno': b'line_number',
503 b'lineno': b'line_number',
504 }
504 }
505
505
506 if rootfm.isplain():
506 if rootfm.isplain():
507
507
508 def makefunc(get, fmt):
508 def makefunc(get, fmt):
509 return lambda x: fmt(get(x))
509 return lambda x: fmt(get(x))
510
510
511 else:
511 else:
512
512
513 def makefunc(get, fmt):
513 def makefunc(get, fmt):
514 return get
514 return get
515
515
516 datahint = rootfm.datahint()
516 datahint = rootfm.datahint()
517 funcmap = [
517 funcmap = [
518 (makefunc(get, fmt), sep)
518 (makefunc(get, fmt), sep)
519 for fn, sep, get, fmt in opmap
519 for fn, sep, get, fmt in opmap
520 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
520 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
521 ]
521 ]
522 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
522 funcmap[0] = (funcmap[0][0], b'') # no separator in front of first column
523 fields = b' '.join(
523 fields = b' '.join(
524 fn
524 fn
525 for fn, sep, get, fmt in opmap
525 for fn, sep, get, fmt in opmap
526 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
526 if opts.get(opnamemap.get(fn, fn)) or fn in datahint
527 )
527 )
528
528
529 def bad(x, y):
529 def bad(x, y):
530 raise error.Abort(b"%s: %s" % (x, y))
530 raise error.Abort(b"%s: %s" % (x, y))
531
531
532 m = scmutil.match(ctx, pats, opts, badfn=bad)
532 m = scmutil.match(ctx, pats, opts, badfn=bad)
533
533
534 follow = not opts.get(b'no_follow')
534 follow = not opts.get(b'no_follow')
535 diffopts = patch.difffeatureopts(
535 diffopts = patch.difffeatureopts(
536 ui, opts, section=b'annotate', whitespace=True
536 ui, opts, section=b'annotate', whitespace=True
537 )
537 )
538 skiprevs = opts.get(b'skip')
538 skiprevs = opts.get(b'skip')
539 if skiprevs:
539 if skiprevs:
540 skiprevs = scmutil.revrange(repo, skiprevs)
540 skiprevs = scmutil.revrange(repo, skiprevs)
541
541
542 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
542 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
543 for abs in ctx.walk(m):
543 for abs in ctx.walk(m):
544 fctx = ctx[abs]
544 fctx = ctx[abs]
545 rootfm.startitem()
545 rootfm.startitem()
546 rootfm.data(path=abs)
546 rootfm.data(path=abs)
547 if not opts.get(b'text') and fctx.isbinary():
547 if not opts.get(b'text') and fctx.isbinary():
548 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
548 rootfm.plain(_(b"%s: binary file\n") % uipathfn(abs))
549 continue
549 continue
550
550
551 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
551 fm = rootfm.nested(b'lines', tmpl=b'{rev}: {line}')
552 lines = fctx.annotate(
552 lines = fctx.annotate(
553 follow=follow, skiprevs=skiprevs, diffopts=diffopts
553 follow=follow, skiprevs=skiprevs, diffopts=diffopts
554 )
554 )
555 if not lines:
555 if not lines:
556 fm.end()
556 fm.end()
557 continue
557 continue
558 formats = []
558 formats = []
559 pieces = []
559 pieces = []
560
560
561 for f, sep in funcmap:
561 for f, sep in funcmap:
562 l = [f(n) for n in lines]
562 l = [f(n) for n in lines]
563 if fm.isplain():
563 if fm.isplain():
564 sizes = [encoding.colwidth(x) for x in l]
564 sizes = [encoding.colwidth(x) for x in l]
565 ml = max(sizes)
565 ml = max(sizes)
566 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
566 formats.append([sep + b' ' * (ml - w) + b'%s' for w in sizes])
567 else:
567 else:
568 formats.append([b'%s'] * len(l))
568 formats.append([b'%s'] * len(l))
569 pieces.append(l)
569 pieces.append(l)
570
570
571 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
571 for f, p, n in zip(zip(*formats), zip(*pieces), lines):
572 fm.startitem()
572 fm.startitem()
573 fm.context(fctx=n.fctx)
573 fm.context(fctx=n.fctx)
574 fm.write(fields, b"".join(f), *p)
574 fm.write(fields, b"".join(f), *p)
575 if n.skip:
575 if n.skip:
576 fmt = b"* %s"
576 fmt = b"* %s"
577 else:
577 else:
578 fmt = b": %s"
578 fmt = b": %s"
579 fm.write(b'line', fmt, n.text)
579 fm.write(b'line', fmt, n.text)
580
580
581 if not lines[-1].text.endswith(b'\n'):
581 if not lines[-1].text.endswith(b'\n'):
582 fm.plain(b'\n')
582 fm.plain(b'\n')
583 fm.end()
583 fm.end()
584
584
585 rootfm.end()
585 rootfm.end()
586
586
587
587
588 @command(
588 @command(
589 b'archive',
589 b'archive',
590 [
590 [
591 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
591 (b'', b'no-decode', None, _(b'do not pass files through decoders')),
592 (
592 (
593 b'p',
593 b'p',
594 b'prefix',
594 b'prefix',
595 b'',
595 b'',
596 _(b'directory prefix for files in archive'),
596 _(b'directory prefix for files in archive'),
597 _(b'PREFIX'),
597 _(b'PREFIX'),
598 ),
598 ),
599 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
599 (b'r', b'rev', b'', _(b'revision to distribute'), _(b'REV')),
600 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
600 (b't', b'type', b'', _(b'type of distribution to create'), _(b'TYPE')),
601 ]
601 ]
602 + subrepoopts
602 + subrepoopts
603 + walkopts,
603 + walkopts,
604 _(b'[OPTION]... DEST'),
604 _(b'[OPTION]... DEST'),
605 helpcategory=command.CATEGORY_IMPORT_EXPORT,
605 helpcategory=command.CATEGORY_IMPORT_EXPORT,
606 )
606 )
607 def archive(ui, repo, dest, **opts):
607 def archive(ui, repo, dest, **opts):
608 """create an unversioned archive of a repository revision
608 """create an unversioned archive of a repository revision
609
609
610 By default, the revision used is the parent of the working
610 By default, the revision used is the parent of the working
611 directory; use -r/--rev to specify a different revision.
611 directory; use -r/--rev to specify a different revision.
612
612
613 The archive type is automatically detected based on file
613 The archive type is automatically detected based on file
614 extension (to override, use -t/--type).
614 extension (to override, use -t/--type).
615
615
616 .. container:: verbose
616 .. container:: verbose
617
617
618 Examples:
618 Examples:
619
619
620 - create a zip file containing the 1.0 release::
620 - create a zip file containing the 1.0 release::
621
621
622 hg archive -r 1.0 project-1.0.zip
622 hg archive -r 1.0 project-1.0.zip
623
623
624 - create a tarball excluding .hg files::
624 - create a tarball excluding .hg files::
625
625
626 hg archive project.tar.gz -X ".hg*"
626 hg archive project.tar.gz -X ".hg*"
627
627
628 Valid types are:
628 Valid types are:
629
629
630 :``files``: a directory full of files (default)
630 :``files``: a directory full of files (default)
631 :``tar``: tar archive, uncompressed
631 :``tar``: tar archive, uncompressed
632 :``tbz2``: tar archive, compressed using bzip2
632 :``tbz2``: tar archive, compressed using bzip2
633 :``tgz``: tar archive, compressed using gzip
633 :``tgz``: tar archive, compressed using gzip
634 :``txz``: tar archive, compressed using lzma (only in Python 3)
634 :``txz``: tar archive, compressed using lzma (only in Python 3)
635 :``uzip``: zip archive, uncompressed
635 :``uzip``: zip archive, uncompressed
636 :``zip``: zip archive, compressed using deflate
636 :``zip``: zip archive, compressed using deflate
637
637
638 The exact name of the destination archive or directory is given
638 The exact name of the destination archive or directory is given
639 using a format string; see :hg:`help export` for details.
639 using a format string; see :hg:`help export` for details.
640
640
641 Each member added to an archive file has a directory prefix
641 Each member added to an archive file has a directory prefix
642 prepended. Use -p/--prefix to specify a format string for the
642 prepended. Use -p/--prefix to specify a format string for the
643 prefix. The default is the basename of the archive, with suffixes
643 prefix. The default is the basename of the archive, with suffixes
644 removed.
644 removed.
645
645
646 Returns 0 on success.
646 Returns 0 on success.
647 """
647 """
648
648
649 opts = pycompat.byteskwargs(opts)
649 opts = pycompat.byteskwargs(opts)
650 rev = opts.get(b'rev')
650 rev = opts.get(b'rev')
651 if rev:
651 if rev:
652 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
652 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
653 ctx = scmutil.revsingle(repo, rev)
653 ctx = scmutil.revsingle(repo, rev)
654 if not ctx:
654 if not ctx:
655 raise error.InputError(
655 raise error.InputError(
656 _(b'no working directory: please specify a revision')
656 _(b'no working directory: please specify a revision')
657 )
657 )
658 node = ctx.node()
658 node = ctx.node()
659 dest = cmdutil.makefilename(ctx, dest)
659 dest = cmdutil.makefilename(ctx, dest)
660 if os.path.realpath(dest) == repo.root:
660 if os.path.realpath(dest) == repo.root:
661 raise error.InputError(_(b'repository root cannot be destination'))
661 raise error.InputError(_(b'repository root cannot be destination'))
662
662
663 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
663 kind = opts.get(b'type') or archival.guesskind(dest) or b'files'
664 prefix = opts.get(b'prefix')
664 prefix = opts.get(b'prefix')
665
665
666 if dest == b'-':
666 if dest == b'-':
667 if kind == b'files':
667 if kind == b'files':
668 raise error.InputError(_(b'cannot archive plain files to stdout'))
668 raise error.InputError(_(b'cannot archive plain files to stdout'))
669 dest = cmdutil.makefileobj(ctx, dest)
669 dest = cmdutil.makefileobj(ctx, dest)
670 if not prefix:
670 if not prefix:
671 prefix = os.path.basename(repo.root) + b'-%h'
671 prefix = os.path.basename(repo.root) + b'-%h'
672
672
673 prefix = cmdutil.makefilename(ctx, prefix)
673 prefix = cmdutil.makefilename(ctx, prefix)
674 match = scmutil.match(ctx, [], opts)
674 match = scmutil.match(ctx, [], opts)
675 archival.archive(
675 archival.archive(
676 repo,
676 repo,
677 dest,
677 dest,
678 node,
678 node,
679 kind,
679 kind,
680 not opts.get(b'no_decode'),
680 not opts.get(b'no_decode'),
681 match,
681 match,
682 prefix,
682 prefix,
683 subrepos=opts.get(b'subrepos'),
683 subrepos=opts.get(b'subrepos'),
684 )
684 )
685
685
686
686
687 @command(
687 @command(
688 b'backout',
688 b'backout',
689 [
689 [
690 (
690 (
691 b'',
691 b'',
692 b'merge',
692 b'merge',
693 None,
693 None,
694 _(b'merge with old dirstate parent after backout'),
694 _(b'merge with old dirstate parent after backout'),
695 ),
695 ),
696 (
696 (
697 b'',
697 b'',
698 b'commit',
698 b'commit',
699 None,
699 None,
700 _(b'commit if no conflicts were encountered (DEPRECATED)'),
700 _(b'commit if no conflicts were encountered (DEPRECATED)'),
701 ),
701 ),
702 (b'', b'no-commit', None, _(b'do not commit')),
702 (b'', b'no-commit', None, _(b'do not commit')),
703 (
703 (
704 b'',
704 b'',
705 b'parent',
705 b'parent',
706 b'',
706 b'',
707 _(b'parent to choose when backing out merge (DEPRECATED)'),
707 _(b'parent to choose when backing out merge (DEPRECATED)'),
708 _(b'REV'),
708 _(b'REV'),
709 ),
709 ),
710 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
710 (b'r', b'rev', b'', _(b'revision to backout'), _(b'REV')),
711 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
711 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
712 ]
712 ]
713 + mergetoolopts
713 + mergetoolopts
714 + walkopts
714 + walkopts
715 + commitopts
715 + commitopts
716 + commitopts2,
716 + commitopts2,
717 _(b'[OPTION]... [-r] REV'),
717 _(b'[OPTION]... [-r] REV'),
718 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
718 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
719 )
719 )
720 def backout(ui, repo, node=None, rev=None, **opts):
720 def backout(ui, repo, node=None, rev=None, **opts):
721 """reverse effect of earlier changeset
721 """reverse effect of earlier changeset
722
722
723 Prepare a new changeset with the effect of REV undone in the
723 Prepare a new changeset with the effect of REV undone in the
724 current working directory. If no conflicts were encountered,
724 current working directory. If no conflicts were encountered,
725 it will be committed immediately.
725 it will be committed immediately.
726
726
727 If REV is the parent of the working directory, then this new changeset
727 If REV is the parent of the working directory, then this new changeset
728 is committed automatically (unless --no-commit is specified).
728 is committed automatically (unless --no-commit is specified).
729
729
730 .. note::
730 .. note::
731
731
732 :hg:`backout` cannot be used to fix either an unwanted or
732 :hg:`backout` cannot be used to fix either an unwanted or
733 incorrect merge.
733 incorrect merge.
734
734
735 .. container:: verbose
735 .. container:: verbose
736
736
737 Examples:
737 Examples:
738
738
739 - Reverse the effect of the parent of the working directory.
739 - Reverse the effect of the parent of the working directory.
740 This backout will be committed immediately::
740 This backout will be committed immediately::
741
741
742 hg backout -r .
742 hg backout -r .
743
743
744 - Reverse the effect of previous bad revision 23::
744 - Reverse the effect of previous bad revision 23::
745
745
746 hg backout -r 23
746 hg backout -r 23
747
747
748 - Reverse the effect of previous bad revision 23 and
748 - Reverse the effect of previous bad revision 23 and
749 leave changes uncommitted::
749 leave changes uncommitted::
750
750
751 hg backout -r 23 --no-commit
751 hg backout -r 23 --no-commit
752 hg commit -m "Backout revision 23"
752 hg commit -m "Backout revision 23"
753
753
754 By default, the pending changeset will have one parent,
754 By default, the pending changeset will have one parent,
755 maintaining a linear history. With --merge, the pending
755 maintaining a linear history. With --merge, the pending
756 changeset will instead have two parents: the old parent of the
756 changeset will instead have two parents: the old parent of the
757 working directory and a new child of REV that simply undoes REV.
757 working directory and a new child of REV that simply undoes REV.
758
758
759 Before version 1.7, the behavior without --merge was equivalent
759 Before version 1.7, the behavior without --merge was equivalent
760 to specifying --merge followed by :hg:`update --clean .` to
760 to specifying --merge followed by :hg:`update --clean .` to
761 cancel the merge and leave the child of REV as a head to be
761 cancel the merge and leave the child of REV as a head to be
762 merged separately.
762 merged separately.
763
763
764 See :hg:`help dates` for a list of formats valid for -d/--date.
764 See :hg:`help dates` for a list of formats valid for -d/--date.
765
765
766 See :hg:`help revert` for a way to restore files to the state
766 See :hg:`help revert` for a way to restore files to the state
767 of another revision.
767 of another revision.
768
768
769 Returns 0 on success, 1 if nothing to backout or there are unresolved
769 Returns 0 on success, 1 if nothing to backout or there are unresolved
770 files.
770 files.
771 """
771 """
772 with repo.wlock(), repo.lock():
772 with repo.wlock(), repo.lock():
773 return _dobackout(ui, repo, node, rev, **opts)
773 return _dobackout(ui, repo, node, rev, **opts)
774
774
775
775
776 def _dobackout(ui, repo, node=None, rev=None, **opts):
776 def _dobackout(ui, repo, node=None, rev=None, **opts):
777 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
777 cmdutil.check_incompatible_arguments(opts, 'no_commit', ['commit', 'merge'])
778 opts = pycompat.byteskwargs(opts)
778 opts = pycompat.byteskwargs(opts)
779
779
780 if rev and node:
780 if rev and node:
781 raise error.InputError(_(b"please specify just one revision"))
781 raise error.InputError(_(b"please specify just one revision"))
782
782
783 if not rev:
783 if not rev:
784 rev = node
784 rev = node
785
785
786 if not rev:
786 if not rev:
787 raise error.InputError(_(b"please specify a revision to backout"))
787 raise error.InputError(_(b"please specify a revision to backout"))
788
788
789 date = opts.get(b'date')
789 date = opts.get(b'date')
790 if date:
790 if date:
791 opts[b'date'] = dateutil.parsedate(date)
791 opts[b'date'] = dateutil.parsedate(date)
792
792
793 cmdutil.checkunfinished(repo)
793 cmdutil.checkunfinished(repo)
794 cmdutil.bailifchanged(repo)
794 cmdutil.bailifchanged(repo)
795 ctx = scmutil.revsingle(repo, rev)
795 ctx = scmutil.revsingle(repo, rev)
796 node = ctx.node()
796 node = ctx.node()
797
797
798 op1, op2 = repo.dirstate.parents()
798 op1, op2 = repo.dirstate.parents()
799 if not repo.changelog.isancestor(node, op1):
799 if not repo.changelog.isancestor(node, op1):
800 raise error.InputError(
800 raise error.InputError(
801 _(b'cannot backout change that is not an ancestor')
801 _(b'cannot backout change that is not an ancestor')
802 )
802 )
803
803
804 p1, p2 = repo.changelog.parents(node)
804 p1, p2 = repo.changelog.parents(node)
805 if p1 == nullid:
805 if p1 == nullid:
806 raise error.InputError(_(b'cannot backout a change with no parents'))
806 raise error.InputError(_(b'cannot backout a change with no parents'))
807 if p2 != nullid:
807 if p2 != nullid:
808 if not opts.get(b'parent'):
808 if not opts.get(b'parent'):
809 raise error.InputError(_(b'cannot backout a merge changeset'))
809 raise error.InputError(_(b'cannot backout a merge changeset'))
810 p = repo.lookup(opts[b'parent'])
810 p = repo.lookup(opts[b'parent'])
811 if p not in (p1, p2):
811 if p not in (p1, p2):
812 raise error.InputError(
812 raise error.InputError(
813 _(b'%s is not a parent of %s') % (short(p), short(node))
813 _(b'%s is not a parent of %s') % (short(p), short(node))
814 )
814 )
815 parent = p
815 parent = p
816 else:
816 else:
817 if opts.get(b'parent'):
817 if opts.get(b'parent'):
818 raise error.InputError(
818 raise error.InputError(
819 _(b'cannot use --parent on non-merge changeset')
819 _(b'cannot use --parent on non-merge changeset')
820 )
820 )
821 parent = p1
821 parent = p1
822
822
823 # the backout should appear on the same branch
823 # the backout should appear on the same branch
824 branch = repo.dirstate.branch()
824 branch = repo.dirstate.branch()
825 bheads = repo.branchheads(branch)
825 bheads = repo.branchheads(branch)
826 rctx = scmutil.revsingle(repo, hex(parent))
826 rctx = scmutil.revsingle(repo, hex(parent))
827 if not opts.get(b'merge') and op1 != node:
827 if not opts.get(b'merge') and op1 != node:
828 with dirstateguard.dirstateguard(repo, b'backout'):
828 with dirstateguard.dirstateguard(repo, b'backout'):
829 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
829 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
830 with ui.configoverride(overrides, b'backout'):
830 with ui.configoverride(overrides, b'backout'):
831 stats = mergemod.back_out(ctx, parent=repo[parent])
831 stats = mergemod.back_out(ctx, parent=repo[parent])
832 repo.setparents(op1, op2)
832 repo.setparents(op1, op2)
833 hg._showstats(repo, stats)
833 hg._showstats(repo, stats)
834 if stats.unresolvedcount:
834 if stats.unresolvedcount:
835 repo.ui.status(
835 repo.ui.status(
836 _(b"use 'hg resolve' to retry unresolved file merges\n")
836 _(b"use 'hg resolve' to retry unresolved file merges\n")
837 )
837 )
838 return 1
838 return 1
839 else:
839 else:
840 hg.clean(repo, node, show_stats=False)
840 hg.clean(repo, node, show_stats=False)
841 repo.dirstate.setbranch(branch)
841 repo.dirstate.setbranch(branch)
842 cmdutil.revert(ui, repo, rctx)
842 cmdutil.revert(ui, repo, rctx)
843
843
844 if opts.get(b'no_commit'):
844 if opts.get(b'no_commit'):
845 msg = _(b"changeset %s backed out, don't forget to commit.\n")
845 msg = _(b"changeset %s backed out, don't forget to commit.\n")
846 ui.status(msg % short(node))
846 ui.status(msg % short(node))
847 return 0
847 return 0
848
848
849 def commitfunc(ui, repo, message, match, opts):
849 def commitfunc(ui, repo, message, match, opts):
850 editform = b'backout'
850 editform = b'backout'
851 e = cmdutil.getcommiteditor(
851 e = cmdutil.getcommiteditor(
852 editform=editform, **pycompat.strkwargs(opts)
852 editform=editform, **pycompat.strkwargs(opts)
853 )
853 )
854 if not message:
854 if not message:
855 # we don't translate commit messages
855 # we don't translate commit messages
856 message = b"Backed out changeset %s" % short(node)
856 message = b"Backed out changeset %s" % short(node)
857 e = cmdutil.getcommiteditor(edit=True, editform=editform)
857 e = cmdutil.getcommiteditor(edit=True, editform=editform)
858 return repo.commit(
858 return repo.commit(
859 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
859 message, opts.get(b'user'), opts.get(b'date'), match, editor=e
860 )
860 )
861
861
862 # save to detect changes
862 # save to detect changes
863 tip = repo.changelog.tip()
863 tip = repo.changelog.tip()
864
864
865 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
865 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
866 if not newnode:
866 if not newnode:
867 ui.status(_(b"nothing changed\n"))
867 ui.status(_(b"nothing changed\n"))
868 return 1
868 return 1
869 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
869 cmdutil.commitstatus(repo, newnode, branch, bheads, tip)
870
870
871 def nice(node):
871 def nice(node):
872 return b'%d:%s' % (repo.changelog.rev(node), short(node))
872 return b'%d:%s' % (repo.changelog.rev(node), short(node))
873
873
874 ui.status(
874 ui.status(
875 _(b'changeset %s backs out changeset %s\n')
875 _(b'changeset %s backs out changeset %s\n')
876 % (nice(newnode), nice(node))
876 % (nice(newnode), nice(node))
877 )
877 )
878 if opts.get(b'merge') and op1 != node:
878 if opts.get(b'merge') and op1 != node:
879 hg.clean(repo, op1, show_stats=False)
879 hg.clean(repo, op1, show_stats=False)
880 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
880 ui.status(_(b'merging with changeset %s\n') % nice(newnode))
881 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
881 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
882 with ui.configoverride(overrides, b'backout'):
882 with ui.configoverride(overrides, b'backout'):
883 return hg.merge(repo[b'tip'])
883 return hg.merge(repo[b'tip'])
884 return 0
884 return 0
885
885
886
886
887 @command(
887 @command(
888 b'bisect',
888 b'bisect',
889 [
889 [
890 (b'r', b'reset', False, _(b'reset bisect state')),
890 (b'r', b'reset', False, _(b'reset bisect state')),
891 (b'g', b'good', False, _(b'mark changeset good')),
891 (b'g', b'good', False, _(b'mark changeset good')),
892 (b'b', b'bad', False, _(b'mark changeset bad')),
892 (b'b', b'bad', False, _(b'mark changeset bad')),
893 (b's', b'skip', False, _(b'skip testing changeset')),
893 (b's', b'skip', False, _(b'skip testing changeset')),
894 (b'e', b'extend', False, _(b'extend the bisect range')),
894 (b'e', b'extend', False, _(b'extend the bisect range')),
895 (
895 (
896 b'c',
896 b'c',
897 b'command',
897 b'command',
898 b'',
898 b'',
899 _(b'use command to check changeset state'),
899 _(b'use command to check changeset state'),
900 _(b'CMD'),
900 _(b'CMD'),
901 ),
901 ),
902 (b'U', b'noupdate', False, _(b'do not update to target')),
902 (b'U', b'noupdate', False, _(b'do not update to target')),
903 ],
903 ],
904 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
904 _(b"[-gbsr] [-U] [-c CMD] [REV]"),
905 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
905 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
906 )
906 )
907 def bisect(
907 def bisect(
908 ui,
908 ui,
909 repo,
909 repo,
910 positional_1=None,
910 positional_1=None,
911 positional_2=None,
911 positional_2=None,
912 command=None,
912 command=None,
913 reset=None,
913 reset=None,
914 good=None,
914 good=None,
915 bad=None,
915 bad=None,
916 skip=None,
916 skip=None,
917 extend=None,
917 extend=None,
918 noupdate=None,
918 noupdate=None,
919 ):
919 ):
920 """subdivision search of changesets
920 """subdivision search of changesets
921
921
922 This command helps to find changesets which introduce problems. To
922 This command helps to find changesets which introduce problems. To
923 use, mark the earliest changeset you know exhibits the problem as
923 use, mark the earliest changeset you know exhibits the problem as
924 bad, then mark the latest changeset which is free from the problem
924 bad, then mark the latest changeset which is free from the problem
925 as good. Bisect will update your working directory to a revision
925 as good. Bisect will update your working directory to a revision
926 for testing (unless the -U/--noupdate option is specified). Once
926 for testing (unless the -U/--noupdate option is specified). Once
927 you have performed tests, mark the working directory as good or
927 you have performed tests, mark the working directory as good or
928 bad, and bisect will either update to another candidate changeset
928 bad, and bisect will either update to another candidate changeset
929 or announce that it has found the bad revision.
929 or announce that it has found the bad revision.
930
930
931 As a shortcut, you can also use the revision argument to mark a
931 As a shortcut, you can also use the revision argument to mark a
932 revision as good or bad without checking it out first.
932 revision as good or bad without checking it out first.
933
933
934 If you supply a command, it will be used for automatic bisection.
934 If you supply a command, it will be used for automatic bisection.
935 The environment variable HG_NODE will contain the ID of the
935 The environment variable HG_NODE will contain the ID of the
936 changeset being tested. The exit status of the command will be
936 changeset being tested. The exit status of the command will be
937 used to mark revisions as good or bad: status 0 means good, 125
937 used to mark revisions as good or bad: status 0 means good, 125
938 means to skip the revision, 127 (command not found) will abort the
938 means to skip the revision, 127 (command not found) will abort the
939 bisection, and any other non-zero exit status means the revision
939 bisection, and any other non-zero exit status means the revision
940 is bad.
940 is bad.
941
941
942 .. container:: verbose
942 .. container:: verbose
943
943
944 Some examples:
944 Some examples:
945
945
946 - start a bisection with known bad revision 34, and good revision 12::
946 - start a bisection with known bad revision 34, and good revision 12::
947
947
948 hg bisect --bad 34
948 hg bisect --bad 34
949 hg bisect --good 12
949 hg bisect --good 12
950
950
951 - advance the current bisection by marking current revision as good or
951 - advance the current bisection by marking current revision as good or
952 bad::
952 bad::
953
953
954 hg bisect --good
954 hg bisect --good
955 hg bisect --bad
955 hg bisect --bad
956
956
957 - mark the current revision, or a known revision, to be skipped (e.g. if
957 - mark the current revision, or a known revision, to be skipped (e.g. if
958 that revision is not usable because of another issue)::
958 that revision is not usable because of another issue)::
959
959
960 hg bisect --skip
960 hg bisect --skip
961 hg bisect --skip 23
961 hg bisect --skip 23
962
962
963 - skip all revisions that do not touch directories ``foo`` or ``bar``::
963 - skip all revisions that do not touch directories ``foo`` or ``bar``::
964
964
965 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
965 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
966
966
967 - forget the current bisection::
967 - forget the current bisection::
968
968
969 hg bisect --reset
969 hg bisect --reset
970
970
971 - use 'make && make tests' to automatically find the first broken
971 - use 'make && make tests' to automatically find the first broken
972 revision::
972 revision::
973
973
974 hg bisect --reset
974 hg bisect --reset
975 hg bisect --bad 34
975 hg bisect --bad 34
976 hg bisect --good 12
976 hg bisect --good 12
977 hg bisect --command "make && make tests"
977 hg bisect --command "make && make tests"
978
978
979 - see all changesets whose states are already known in the current
979 - see all changesets whose states are already known in the current
980 bisection::
980 bisection::
981
981
982 hg log -r "bisect(pruned)"
982 hg log -r "bisect(pruned)"
983
983
984 - see the changeset currently being bisected (especially useful
984 - see the changeset currently being bisected (especially useful
985 if running with -U/--noupdate)::
985 if running with -U/--noupdate)::
986
986
987 hg log -r "bisect(current)"
987 hg log -r "bisect(current)"
988
988
989 - see all changesets that took part in the current bisection::
989 - see all changesets that took part in the current bisection::
990
990
991 hg log -r "bisect(range)"
991 hg log -r "bisect(range)"
992
992
993 - you can even get a nice graph::
993 - you can even get a nice graph::
994
994
995 hg log --graph -r "bisect(range)"
995 hg log --graph -r "bisect(range)"
996
996
997 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
997 See :hg:`help revisions.bisect` for more about the `bisect()` predicate.
998
998
999 Returns 0 on success.
999 Returns 0 on success.
1000 """
1000 """
1001 rev = []
1001 rev = []
1002 # backward compatibility
1002 # backward compatibility
1003 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1003 if positional_1 in (b"good", b"bad", b"reset", b"init"):
1004 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1004 ui.warn(_(b"(use of 'hg bisect <cmd>' is deprecated)\n"))
1005 cmd = positional_1
1005 cmd = positional_1
1006 rev.append(positional_2)
1006 rev.append(positional_2)
1007 if cmd == b"good":
1007 if cmd == b"good":
1008 good = True
1008 good = True
1009 elif cmd == b"bad":
1009 elif cmd == b"bad":
1010 bad = True
1010 bad = True
1011 else:
1011 else:
1012 reset = True
1012 reset = True
1013 elif positional_2:
1013 elif positional_2:
1014 raise error.InputError(_(b'incompatible arguments'))
1014 raise error.InputError(_(b'incompatible arguments'))
1015 elif positional_1 is not None:
1015 elif positional_1 is not None:
1016 rev.append(positional_1)
1016 rev.append(positional_1)
1017
1017
1018 incompatibles = {
1018 incompatibles = {
1019 b'--bad': bad,
1019 b'--bad': bad,
1020 b'--command': bool(command),
1020 b'--command': bool(command),
1021 b'--extend': extend,
1021 b'--extend': extend,
1022 b'--good': good,
1022 b'--good': good,
1023 b'--reset': reset,
1023 b'--reset': reset,
1024 b'--skip': skip,
1024 b'--skip': skip,
1025 }
1025 }
1026
1026
1027 enabled = [x for x in incompatibles if incompatibles[x]]
1027 enabled = [x for x in incompatibles if incompatibles[x]]
1028
1028
1029 if len(enabled) > 1:
1029 if len(enabled) > 1:
1030 raise error.InputError(
1030 raise error.InputError(
1031 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1031 _(b'%s and %s are incompatible') % tuple(sorted(enabled)[0:2])
1032 )
1032 )
1033
1033
1034 if reset:
1034 if reset:
1035 hbisect.resetstate(repo)
1035 hbisect.resetstate(repo)
1036 return
1036 return
1037
1037
1038 state = hbisect.load_state(repo)
1038 state = hbisect.load_state(repo)
1039
1039
1040 if rev:
1040 if rev:
1041 nodes = [repo[i].node() for i in scmutil.revrange(repo, rev)]
1041 nodes = [repo[i].node() for i in scmutil.revrange(repo, rev)]
1042 else:
1042 else:
1043 nodes = [repo.lookup(b'.')]
1043 nodes = [repo.lookup(b'.')]
1044
1044
1045 # update state
1045 # update state
1046 if good or bad or skip:
1046 if good or bad or skip:
1047 if good:
1047 if good:
1048 state[b'good'] += nodes
1048 state[b'good'] += nodes
1049 elif bad:
1049 elif bad:
1050 state[b'bad'] += nodes
1050 state[b'bad'] += nodes
1051 elif skip:
1051 elif skip:
1052 state[b'skip'] += nodes
1052 state[b'skip'] += nodes
1053 hbisect.save_state(repo, state)
1053 hbisect.save_state(repo, state)
1054 if not (state[b'good'] and state[b'bad']):
1054 if not (state[b'good'] and state[b'bad']):
1055 return
1055 return
1056
1056
1057 def mayupdate(repo, node, show_stats=True):
1057 def mayupdate(repo, node, show_stats=True):
1058 """common used update sequence"""
1058 """common used update sequence"""
1059 if noupdate:
1059 if noupdate:
1060 return
1060 return
1061 cmdutil.checkunfinished(repo)
1061 cmdutil.checkunfinished(repo)
1062 cmdutil.bailifchanged(repo)
1062 cmdutil.bailifchanged(repo)
1063 return hg.clean(repo, node, show_stats=show_stats)
1063 return hg.clean(repo, node, show_stats=show_stats)
1064
1064
1065 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1065 displayer = logcmdutil.changesetdisplayer(ui, repo, {})
1066
1066
1067 if command:
1067 if command:
1068 changesets = 1
1068 changesets = 1
1069 if noupdate:
1069 if noupdate:
1070 try:
1070 try:
1071 node = state[b'current'][0]
1071 node = state[b'current'][0]
1072 except LookupError:
1072 except LookupError:
1073 raise error.StateError(
1073 raise error.StateError(
1074 _(
1074 _(
1075 b'current bisect revision is unknown - '
1075 b'current bisect revision is unknown - '
1076 b'start a new bisect to fix'
1076 b'start a new bisect to fix'
1077 )
1077 )
1078 )
1078 )
1079 else:
1079 else:
1080 node, p2 = repo.dirstate.parents()
1080 node, p2 = repo.dirstate.parents()
1081 if p2 != nullid:
1081 if p2 != nullid:
1082 raise error.StateError(_(b'current bisect revision is a merge'))
1082 raise error.StateError(_(b'current bisect revision is a merge'))
1083 if rev:
1083 if rev:
1084 if not nodes:
1084 if not nodes:
1085 raise error.Abort(_(b'empty revision set'))
1085 raise error.Abort(_(b'empty revision set'))
1086 node = repo[nodes.last()].node()
1086 node = repo[nodes.last()].node()
1087 with hbisect.restore_state(repo, state, node):
1087 with hbisect.restore_state(repo, state, node):
1088 while changesets:
1088 while changesets:
1089 # update state
1089 # update state
1090 state[b'current'] = [node]
1090 state[b'current'] = [node]
1091 hbisect.save_state(repo, state)
1091 hbisect.save_state(repo, state)
1092 status = ui.system(
1092 status = ui.system(
1093 command,
1093 command,
1094 environ={b'HG_NODE': hex(node)},
1094 environ={b'HG_NODE': hex(node)},
1095 blockedtag=b'bisect_check',
1095 blockedtag=b'bisect_check',
1096 )
1096 )
1097 if status == 125:
1097 if status == 125:
1098 transition = b"skip"
1098 transition = b"skip"
1099 elif status == 0:
1099 elif status == 0:
1100 transition = b"good"
1100 transition = b"good"
1101 # status < 0 means process was killed
1101 # status < 0 means process was killed
1102 elif status == 127:
1102 elif status == 127:
1103 raise error.Abort(_(b"failed to execute %s") % command)
1103 raise error.Abort(_(b"failed to execute %s") % command)
1104 elif status < 0:
1104 elif status < 0:
1105 raise error.Abort(_(b"%s killed") % command)
1105 raise error.Abort(_(b"%s killed") % command)
1106 else:
1106 else:
1107 transition = b"bad"
1107 transition = b"bad"
1108 state[transition].append(node)
1108 state[transition].append(node)
1109 ctx = repo[node]
1109 ctx = repo[node]
1110 ui.status(
1110 ui.status(
1111 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1111 _(b'changeset %d:%s: %s\n') % (ctx.rev(), ctx, transition)
1112 )
1112 )
1113 hbisect.checkstate(state)
1113 hbisect.checkstate(state)
1114 # bisect
1114 # bisect
1115 nodes, changesets, bgood = hbisect.bisect(repo, state)
1115 nodes, changesets, bgood = hbisect.bisect(repo, state)
1116 # update to next check
1116 # update to next check
1117 node = nodes[0]
1117 node = nodes[0]
1118 mayupdate(repo, node, show_stats=False)
1118 mayupdate(repo, node, show_stats=False)
1119 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1119 hbisect.printresult(ui, repo, state, displayer, nodes, bgood)
1120 return
1120 return
1121
1121
1122 hbisect.checkstate(state)
1122 hbisect.checkstate(state)
1123
1123
1124 # actually bisect
1124 # actually bisect
1125 nodes, changesets, good = hbisect.bisect(repo, state)
1125 nodes, changesets, good = hbisect.bisect(repo, state)
1126 if extend:
1126 if extend:
1127 if not changesets:
1127 if not changesets:
1128 extendnode = hbisect.extendrange(repo, state, nodes, good)
1128 extendnode = hbisect.extendrange(repo, state, nodes, good)
1129 if extendnode is not None:
1129 if extendnode is not None:
1130 ui.write(
1130 ui.write(
1131 _(b"Extending search to changeset %d:%s\n")
1131 _(b"Extending search to changeset %d:%s\n")
1132 % (extendnode.rev(), extendnode)
1132 % (extendnode.rev(), extendnode)
1133 )
1133 )
1134 state[b'current'] = [extendnode.node()]
1134 state[b'current'] = [extendnode.node()]
1135 hbisect.save_state(repo, state)
1135 hbisect.save_state(repo, state)
1136 return mayupdate(repo, extendnode.node())
1136 return mayupdate(repo, extendnode.node())
1137 raise error.StateError(_(b"nothing to extend"))
1137 raise error.StateError(_(b"nothing to extend"))
1138
1138
1139 if changesets == 0:
1139 if changesets == 0:
1140 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1140 hbisect.printresult(ui, repo, state, displayer, nodes, good)
1141 else:
1141 else:
1142 assert len(nodes) == 1 # only a single node can be tested next
1142 assert len(nodes) == 1 # only a single node can be tested next
1143 node = nodes[0]
1143 node = nodes[0]
1144 # compute the approximate number of remaining tests
1144 # compute the approximate number of remaining tests
1145 tests, size = 0, 2
1145 tests, size = 0, 2
1146 while size <= changesets:
1146 while size <= changesets:
1147 tests, size = tests + 1, size * 2
1147 tests, size = tests + 1, size * 2
1148 rev = repo.changelog.rev(node)
1148 rev = repo.changelog.rev(node)
1149 ui.write(
1149 ui.write(
1150 _(
1150 _(
1151 b"Testing changeset %d:%s "
1151 b"Testing changeset %d:%s "
1152 b"(%d changesets remaining, ~%d tests)\n"
1152 b"(%d changesets remaining, ~%d tests)\n"
1153 )
1153 )
1154 % (rev, short(node), changesets, tests)
1154 % (rev, short(node), changesets, tests)
1155 )
1155 )
1156 state[b'current'] = [node]
1156 state[b'current'] = [node]
1157 hbisect.save_state(repo, state)
1157 hbisect.save_state(repo, state)
1158 return mayupdate(repo, node)
1158 return mayupdate(repo, node)
1159
1159
1160
1160
1161 @command(
1161 @command(
1162 b'bookmarks|bookmark',
1162 b'bookmarks|bookmark',
1163 [
1163 [
1164 (b'f', b'force', False, _(b'force')),
1164 (b'f', b'force', False, _(b'force')),
1165 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1165 (b'r', b'rev', b'', _(b'revision for bookmark action'), _(b'REV')),
1166 (b'd', b'delete', False, _(b'delete a given bookmark')),
1166 (b'd', b'delete', False, _(b'delete a given bookmark')),
1167 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1167 (b'm', b'rename', b'', _(b'rename a given bookmark'), _(b'OLD')),
1168 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1168 (b'i', b'inactive', False, _(b'mark a bookmark inactive')),
1169 (b'l', b'list', False, _(b'list existing bookmarks')),
1169 (b'l', b'list', False, _(b'list existing bookmarks')),
1170 ]
1170 ]
1171 + formatteropts,
1171 + formatteropts,
1172 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1172 _(b'hg bookmarks [OPTIONS]... [NAME]...'),
1173 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1173 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1174 )
1174 )
1175 def bookmark(ui, repo, *names, **opts):
1175 def bookmark(ui, repo, *names, **opts):
1176 """create a new bookmark or list existing bookmarks
1176 """create a new bookmark or list existing bookmarks
1177
1177
1178 Bookmarks are labels on changesets to help track lines of development.
1178 Bookmarks are labels on changesets to help track lines of development.
1179 Bookmarks are unversioned and can be moved, renamed and deleted.
1179 Bookmarks are unversioned and can be moved, renamed and deleted.
1180 Deleting or moving a bookmark has no effect on the associated changesets.
1180 Deleting or moving a bookmark has no effect on the associated changesets.
1181
1181
1182 Creating or updating to a bookmark causes it to be marked as 'active'.
1182 Creating or updating to a bookmark causes it to be marked as 'active'.
1183 The active bookmark is indicated with a '*'.
1183 The active bookmark is indicated with a '*'.
1184 When a commit is made, the active bookmark will advance to the new commit.
1184 When a commit is made, the active bookmark will advance to the new commit.
1185 A plain :hg:`update` will also advance an active bookmark, if possible.
1185 A plain :hg:`update` will also advance an active bookmark, if possible.
1186 Updating away from a bookmark will cause it to be deactivated.
1186 Updating away from a bookmark will cause it to be deactivated.
1187
1187
1188 Bookmarks can be pushed and pulled between repositories (see
1188 Bookmarks can be pushed and pulled between repositories (see
1189 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1189 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
1190 diverged, a new 'divergent bookmark' of the form 'name@path' will
1190 diverged, a new 'divergent bookmark' of the form 'name@path' will
1191 be created. Using :hg:`merge` will resolve the divergence.
1191 be created. Using :hg:`merge` will resolve the divergence.
1192
1192
1193 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1193 Specifying bookmark as '.' to -m/-d/-l options is equivalent to specifying
1194 the active bookmark's name.
1194 the active bookmark's name.
1195
1195
1196 A bookmark named '@' has the special property that :hg:`clone` will
1196 A bookmark named '@' has the special property that :hg:`clone` will
1197 check it out by default if it exists.
1197 check it out by default if it exists.
1198
1198
1199 .. container:: verbose
1199 .. container:: verbose
1200
1200
1201 Template:
1201 Template:
1202
1202
1203 The following keywords are supported in addition to the common template
1203 The following keywords are supported in addition to the common template
1204 keywords and functions such as ``{bookmark}``. See also
1204 keywords and functions such as ``{bookmark}``. See also
1205 :hg:`help templates`.
1205 :hg:`help templates`.
1206
1206
1207 :active: Boolean. True if the bookmark is active.
1207 :active: Boolean. True if the bookmark is active.
1208
1208
1209 Examples:
1209 Examples:
1210
1210
1211 - create an active bookmark for a new line of development::
1211 - create an active bookmark for a new line of development::
1212
1212
1213 hg book new-feature
1213 hg book new-feature
1214
1214
1215 - create an inactive bookmark as a place marker::
1215 - create an inactive bookmark as a place marker::
1216
1216
1217 hg book -i reviewed
1217 hg book -i reviewed
1218
1218
1219 - create an inactive bookmark on another changeset::
1219 - create an inactive bookmark on another changeset::
1220
1220
1221 hg book -r .^ tested
1221 hg book -r .^ tested
1222
1222
1223 - rename bookmark turkey to dinner::
1223 - rename bookmark turkey to dinner::
1224
1224
1225 hg book -m turkey dinner
1225 hg book -m turkey dinner
1226
1226
1227 - move the '@' bookmark from another branch::
1227 - move the '@' bookmark from another branch::
1228
1228
1229 hg book -f @
1229 hg book -f @
1230
1230
1231 - print only the active bookmark name::
1231 - print only the active bookmark name::
1232
1232
1233 hg book -ql .
1233 hg book -ql .
1234 """
1234 """
1235 opts = pycompat.byteskwargs(opts)
1235 opts = pycompat.byteskwargs(opts)
1236 force = opts.get(b'force')
1236 force = opts.get(b'force')
1237 rev = opts.get(b'rev')
1237 rev = opts.get(b'rev')
1238 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1238 inactive = opts.get(b'inactive') # meaning add/rename to inactive bookmark
1239
1239
1240 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1240 action = cmdutil.check_at_most_one_arg(opts, b'delete', b'rename', b'list')
1241 if action:
1241 if action:
1242 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1242 cmdutil.check_incompatible_arguments(opts, action, [b'rev'])
1243 elif names or rev:
1243 elif names or rev:
1244 action = b'add'
1244 action = b'add'
1245 elif inactive:
1245 elif inactive:
1246 action = b'inactive' # meaning deactivate
1246 action = b'inactive' # meaning deactivate
1247 else:
1247 else:
1248 action = b'list'
1248 action = b'list'
1249
1249
1250 cmdutil.check_incompatible_arguments(
1250 cmdutil.check_incompatible_arguments(
1251 opts, b'inactive', [b'delete', b'list']
1251 opts, b'inactive', [b'delete', b'list']
1252 )
1252 )
1253 if not names and action in {b'add', b'delete'}:
1253 if not names and action in {b'add', b'delete'}:
1254 raise error.InputError(_(b"bookmark name required"))
1254 raise error.InputError(_(b"bookmark name required"))
1255
1255
1256 if action in {b'add', b'delete', b'rename', b'inactive'}:
1256 if action in {b'add', b'delete', b'rename', b'inactive'}:
1257 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1257 with repo.wlock(), repo.lock(), repo.transaction(b'bookmark') as tr:
1258 if action == b'delete':
1258 if action == b'delete':
1259 names = pycompat.maplist(repo._bookmarks.expandname, names)
1259 names = pycompat.maplist(repo._bookmarks.expandname, names)
1260 bookmarks.delete(repo, tr, names)
1260 bookmarks.delete(repo, tr, names)
1261 elif action == b'rename':
1261 elif action == b'rename':
1262 if not names:
1262 if not names:
1263 raise error.InputError(_(b"new bookmark name required"))
1263 raise error.InputError(_(b"new bookmark name required"))
1264 elif len(names) > 1:
1264 elif len(names) > 1:
1265 raise error.InputError(
1265 raise error.InputError(
1266 _(b"only one new bookmark name allowed")
1266 _(b"only one new bookmark name allowed")
1267 )
1267 )
1268 oldname = repo._bookmarks.expandname(opts[b'rename'])
1268 oldname = repo._bookmarks.expandname(opts[b'rename'])
1269 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1269 bookmarks.rename(repo, tr, oldname, names[0], force, inactive)
1270 elif action == b'add':
1270 elif action == b'add':
1271 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1271 bookmarks.addbookmarks(repo, tr, names, rev, force, inactive)
1272 elif action == b'inactive':
1272 elif action == b'inactive':
1273 if len(repo._bookmarks) == 0:
1273 if len(repo._bookmarks) == 0:
1274 ui.status(_(b"no bookmarks set\n"))
1274 ui.status(_(b"no bookmarks set\n"))
1275 elif not repo._activebookmark:
1275 elif not repo._activebookmark:
1276 ui.status(_(b"no active bookmark\n"))
1276 ui.status(_(b"no active bookmark\n"))
1277 else:
1277 else:
1278 bookmarks.deactivate(repo)
1278 bookmarks.deactivate(repo)
1279 elif action == b'list':
1279 elif action == b'list':
1280 names = pycompat.maplist(repo._bookmarks.expandname, names)
1280 names = pycompat.maplist(repo._bookmarks.expandname, names)
1281 with ui.formatter(b'bookmarks', opts) as fm:
1281 with ui.formatter(b'bookmarks', opts) as fm:
1282 bookmarks.printbookmarks(ui, repo, fm, names)
1282 bookmarks.printbookmarks(ui, repo, fm, names)
1283 else:
1283 else:
1284 raise error.ProgrammingError(b'invalid action: %s' % action)
1284 raise error.ProgrammingError(b'invalid action: %s' % action)
1285
1285
1286
1286
1287 @command(
1287 @command(
1288 b'branch',
1288 b'branch',
1289 [
1289 [
1290 (
1290 (
1291 b'f',
1291 b'f',
1292 b'force',
1292 b'force',
1293 None,
1293 None,
1294 _(b'set branch name even if it shadows an existing branch'),
1294 _(b'set branch name even if it shadows an existing branch'),
1295 ),
1295 ),
1296 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1296 (b'C', b'clean', None, _(b'reset branch name to parent branch name')),
1297 (
1297 (
1298 b'r',
1298 b'r',
1299 b'rev',
1299 b'rev',
1300 [],
1300 [],
1301 _(b'change branches of the given revs (EXPERIMENTAL)'),
1301 _(b'change branches of the given revs (EXPERIMENTAL)'),
1302 ),
1302 ),
1303 ],
1303 ],
1304 _(b'[-fC] [NAME]'),
1304 _(b'[-fC] [NAME]'),
1305 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1305 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1306 )
1306 )
1307 def branch(ui, repo, label=None, **opts):
1307 def branch(ui, repo, label=None, **opts):
1308 """set or show the current branch name
1308 """set or show the current branch name
1309
1309
1310 .. note::
1310 .. note::
1311
1311
1312 Branch names are permanent and global. Use :hg:`bookmark` to create a
1312 Branch names are permanent and global. Use :hg:`bookmark` to create a
1313 light-weight bookmark instead. See :hg:`help glossary` for more
1313 light-weight bookmark instead. See :hg:`help glossary` for more
1314 information about named branches and bookmarks.
1314 information about named branches and bookmarks.
1315
1315
1316 With no argument, show the current branch name. With one argument,
1316 With no argument, show the current branch name. With one argument,
1317 set the working directory branch name (the branch will not exist
1317 set the working directory branch name (the branch will not exist
1318 in the repository until the next commit). Standard practice
1318 in the repository until the next commit). Standard practice
1319 recommends that primary development take place on the 'default'
1319 recommends that primary development take place on the 'default'
1320 branch.
1320 branch.
1321
1321
1322 Unless -f/--force is specified, branch will not let you set a
1322 Unless -f/--force is specified, branch will not let you set a
1323 branch name that already exists.
1323 branch name that already exists.
1324
1324
1325 Use -C/--clean to reset the working directory branch to that of
1325 Use -C/--clean to reset the working directory branch to that of
1326 the parent of the working directory, negating a previous branch
1326 the parent of the working directory, negating a previous branch
1327 change.
1327 change.
1328
1328
1329 Use the command :hg:`update` to switch to an existing branch. Use
1329 Use the command :hg:`update` to switch to an existing branch. Use
1330 :hg:`commit --close-branch` to mark this branch head as closed.
1330 :hg:`commit --close-branch` to mark this branch head as closed.
1331 When all heads of a branch are closed, the branch will be
1331 When all heads of a branch are closed, the branch will be
1332 considered closed.
1332 considered closed.
1333
1333
1334 Returns 0 on success.
1334 Returns 0 on success.
1335 """
1335 """
1336 opts = pycompat.byteskwargs(opts)
1336 opts = pycompat.byteskwargs(opts)
1337 revs = opts.get(b'rev')
1337 revs = opts.get(b'rev')
1338 if label:
1338 if label:
1339 label = label.strip()
1339 label = label.strip()
1340
1340
1341 if not opts.get(b'clean') and not label:
1341 if not opts.get(b'clean') and not label:
1342 if revs:
1342 if revs:
1343 raise error.InputError(
1343 raise error.InputError(
1344 _(b"no branch name specified for the revisions")
1344 _(b"no branch name specified for the revisions")
1345 )
1345 )
1346 ui.write(b"%s\n" % repo.dirstate.branch())
1346 ui.write(b"%s\n" % repo.dirstate.branch())
1347 return
1347 return
1348
1348
1349 with repo.wlock():
1349 with repo.wlock():
1350 if opts.get(b'clean'):
1350 if opts.get(b'clean'):
1351 label = repo[b'.'].branch()
1351 label = repo[b'.'].branch()
1352 repo.dirstate.setbranch(label)
1352 repo.dirstate.setbranch(label)
1353 ui.status(_(b'reset working directory to branch %s\n') % label)
1353 ui.status(_(b'reset working directory to branch %s\n') % label)
1354 elif label:
1354 elif label:
1355
1355
1356 scmutil.checknewlabel(repo, label, b'branch')
1356 scmutil.checknewlabel(repo, label, b'branch')
1357 if revs:
1357 if revs:
1358 return cmdutil.changebranch(ui, repo, revs, label, opts)
1358 return cmdutil.changebranch(ui, repo, revs, label, opts)
1359
1359
1360 if not opts.get(b'force') and label in repo.branchmap():
1360 if not opts.get(b'force') and label in repo.branchmap():
1361 if label not in [p.branch() for p in repo[None].parents()]:
1361 if label not in [p.branch() for p in repo[None].parents()]:
1362 raise error.InputError(
1362 raise error.InputError(
1363 _(b'a branch of the same name already exists'),
1363 _(b'a branch of the same name already exists'),
1364 # i18n: "it" refers to an existing branch
1364 # i18n: "it" refers to an existing branch
1365 hint=_(b"use 'hg update' to switch to it"),
1365 hint=_(b"use 'hg update' to switch to it"),
1366 )
1366 )
1367
1367
1368 repo.dirstate.setbranch(label)
1368 repo.dirstate.setbranch(label)
1369 ui.status(_(b'marked working directory as branch %s\n') % label)
1369 ui.status(_(b'marked working directory as branch %s\n') % label)
1370
1370
1371 # find any open named branches aside from default
1371 # find any open named branches aside from default
1372 for n, h, t, c in repo.branchmap().iterbranches():
1372 for n, h, t, c in repo.branchmap().iterbranches():
1373 if n != b"default" and not c:
1373 if n != b"default" and not c:
1374 return 0
1374 return 0
1375 ui.status(
1375 ui.status(
1376 _(
1376 _(
1377 b'(branches are permanent and global, '
1377 b'(branches are permanent and global, '
1378 b'did you want a bookmark?)\n'
1378 b'did you want a bookmark?)\n'
1379 )
1379 )
1380 )
1380 )
1381
1381
1382
1382
1383 @command(
1383 @command(
1384 b'branches',
1384 b'branches',
1385 [
1385 [
1386 (
1386 (
1387 b'a',
1387 b'a',
1388 b'active',
1388 b'active',
1389 False,
1389 False,
1390 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1390 _(b'show only branches that have unmerged heads (DEPRECATED)'),
1391 ),
1391 ),
1392 (b'c', b'closed', False, _(b'show normal and closed branches')),
1392 (b'c', b'closed', False, _(b'show normal and closed branches')),
1393 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1393 (b'r', b'rev', [], _(b'show branch name(s) of the given rev')),
1394 ]
1394 ]
1395 + formatteropts,
1395 + formatteropts,
1396 _(b'[-c]'),
1396 _(b'[-c]'),
1397 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1397 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
1398 intents={INTENT_READONLY},
1398 intents={INTENT_READONLY},
1399 )
1399 )
1400 def branches(ui, repo, active=False, closed=False, **opts):
1400 def branches(ui, repo, active=False, closed=False, **opts):
1401 """list repository named branches
1401 """list repository named branches
1402
1402
1403 List the repository's named branches, indicating which ones are
1403 List the repository's named branches, indicating which ones are
1404 inactive. If -c/--closed is specified, also list branches which have
1404 inactive. If -c/--closed is specified, also list branches which have
1405 been marked closed (see :hg:`commit --close-branch`).
1405 been marked closed (see :hg:`commit --close-branch`).
1406
1406
1407 Use the command :hg:`update` to switch to an existing branch.
1407 Use the command :hg:`update` to switch to an existing branch.
1408
1408
1409 .. container:: verbose
1409 .. container:: verbose
1410
1410
1411 Template:
1411 Template:
1412
1412
1413 The following keywords are supported in addition to the common template
1413 The following keywords are supported in addition to the common template
1414 keywords and functions such as ``{branch}``. See also
1414 keywords and functions such as ``{branch}``. See also
1415 :hg:`help templates`.
1415 :hg:`help templates`.
1416
1416
1417 :active: Boolean. True if the branch is active.
1417 :active: Boolean. True if the branch is active.
1418 :closed: Boolean. True if the branch is closed.
1418 :closed: Boolean. True if the branch is closed.
1419 :current: Boolean. True if it is the current branch.
1419 :current: Boolean. True if it is the current branch.
1420
1420
1421 Returns 0.
1421 Returns 0.
1422 """
1422 """
1423
1423
1424 opts = pycompat.byteskwargs(opts)
1424 opts = pycompat.byteskwargs(opts)
1425 revs = opts.get(b'rev')
1425 revs = opts.get(b'rev')
1426 selectedbranches = None
1426 selectedbranches = None
1427 if revs:
1427 if revs:
1428 revs = scmutil.revrange(repo, revs)
1428 revs = scmutil.revrange(repo, revs)
1429 getbi = repo.revbranchcache().branchinfo
1429 getbi = repo.revbranchcache().branchinfo
1430 selectedbranches = {getbi(r)[0] for r in revs}
1430 selectedbranches = {getbi(r)[0] for r in revs}
1431
1431
1432 ui.pager(b'branches')
1432 ui.pager(b'branches')
1433 fm = ui.formatter(b'branches', opts)
1433 fm = ui.formatter(b'branches', opts)
1434 hexfunc = fm.hexfunc
1434 hexfunc = fm.hexfunc
1435
1435
1436 allheads = set(repo.heads())
1436 allheads = set(repo.heads())
1437 branches = []
1437 branches = []
1438 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1438 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1439 if selectedbranches is not None and tag not in selectedbranches:
1439 if selectedbranches is not None and tag not in selectedbranches:
1440 continue
1440 continue
1441 isactive = False
1441 isactive = False
1442 if not isclosed:
1442 if not isclosed:
1443 openheads = set(repo.branchmap().iteropen(heads))
1443 openheads = set(repo.branchmap().iteropen(heads))
1444 isactive = bool(openheads & allheads)
1444 isactive = bool(openheads & allheads)
1445 branches.append((tag, repo[tip], isactive, not isclosed))
1445 branches.append((tag, repo[tip], isactive, not isclosed))
1446 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1446 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]), reverse=True)
1447
1447
1448 for tag, ctx, isactive, isopen in branches:
1448 for tag, ctx, isactive, isopen in branches:
1449 if active and not isactive:
1449 if active and not isactive:
1450 continue
1450 continue
1451 if isactive:
1451 if isactive:
1452 label = b'branches.active'
1452 label = b'branches.active'
1453 notice = b''
1453 notice = b''
1454 elif not isopen:
1454 elif not isopen:
1455 if not closed:
1455 if not closed:
1456 continue
1456 continue
1457 label = b'branches.closed'
1457 label = b'branches.closed'
1458 notice = _(b' (closed)')
1458 notice = _(b' (closed)')
1459 else:
1459 else:
1460 label = b'branches.inactive'
1460 label = b'branches.inactive'
1461 notice = _(b' (inactive)')
1461 notice = _(b' (inactive)')
1462 current = tag == repo.dirstate.branch()
1462 current = tag == repo.dirstate.branch()
1463 if current:
1463 if current:
1464 label = b'branches.current'
1464 label = b'branches.current'
1465
1465
1466 fm.startitem()
1466 fm.startitem()
1467 fm.write(b'branch', b'%s', tag, label=label)
1467 fm.write(b'branch', b'%s', tag, label=label)
1468 rev = ctx.rev()
1468 rev = ctx.rev()
1469 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1469 padsize = max(31 - len(b"%d" % rev) - encoding.colwidth(tag), 0)
1470 fmt = b' ' * padsize + b' %d:%s'
1470 fmt = b' ' * padsize + b' %d:%s'
1471 fm.condwrite(
1471 fm.condwrite(
1472 not ui.quiet,
1472 not ui.quiet,
1473 b'rev node',
1473 b'rev node',
1474 fmt,
1474 fmt,
1475 rev,
1475 rev,
1476 hexfunc(ctx.node()),
1476 hexfunc(ctx.node()),
1477 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1477 label=b'log.changeset changeset.%s' % ctx.phasestr(),
1478 )
1478 )
1479 fm.context(ctx=ctx)
1479 fm.context(ctx=ctx)
1480 fm.data(active=isactive, closed=not isopen, current=current)
1480 fm.data(active=isactive, closed=not isopen, current=current)
1481 if not ui.quiet:
1481 if not ui.quiet:
1482 fm.plain(notice)
1482 fm.plain(notice)
1483 fm.plain(b'\n')
1483 fm.plain(b'\n')
1484 fm.end()
1484 fm.end()
1485
1485
1486
1486
1487 @command(
1487 @command(
1488 b'bundle',
1488 b'bundle',
1489 [
1489 [
1490 (
1490 (
1491 b'f',
1491 b'f',
1492 b'force',
1492 b'force',
1493 None,
1493 None,
1494 _(b'run even when the destination is unrelated'),
1494 _(b'run even when the destination is unrelated'),
1495 ),
1495 ),
1496 (
1496 (
1497 b'r',
1497 b'r',
1498 b'rev',
1498 b'rev',
1499 [],
1499 [],
1500 _(b'a changeset intended to be added to the destination'),
1500 _(b'a changeset intended to be added to the destination'),
1501 _(b'REV'),
1501 _(b'REV'),
1502 ),
1502 ),
1503 (
1503 (
1504 b'b',
1504 b'b',
1505 b'branch',
1505 b'branch',
1506 [],
1506 [],
1507 _(b'a specific branch you would like to bundle'),
1507 _(b'a specific branch you would like to bundle'),
1508 _(b'BRANCH'),
1508 _(b'BRANCH'),
1509 ),
1509 ),
1510 (
1510 (
1511 b'',
1511 b'',
1512 b'base',
1512 b'base',
1513 [],
1513 [],
1514 _(b'a base changeset assumed to be available at the destination'),
1514 _(b'a base changeset assumed to be available at the destination'),
1515 _(b'REV'),
1515 _(b'REV'),
1516 ),
1516 ),
1517 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1517 (b'a', b'all', None, _(b'bundle all changesets in the repository')),
1518 (
1518 (
1519 b't',
1519 b't',
1520 b'type',
1520 b'type',
1521 b'bzip2',
1521 b'bzip2',
1522 _(b'bundle compression type to use'),
1522 _(b'bundle compression type to use'),
1523 _(b'TYPE'),
1523 _(b'TYPE'),
1524 ),
1524 ),
1525 ]
1525 ]
1526 + remoteopts,
1526 + remoteopts,
1527 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1527 _(b'[-f] [-t BUNDLESPEC] [-a] [-r REV]... [--base REV]... FILE [DEST]'),
1528 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1528 helpcategory=command.CATEGORY_IMPORT_EXPORT,
1529 )
1529 )
1530 def bundle(ui, repo, fname, dest=None, **opts):
1530 def bundle(ui, repo, fname, dest=None, **opts):
1531 """create a bundle file
1531 """create a bundle file
1532
1532
1533 Generate a bundle file containing data to be transferred to another
1533 Generate a bundle file containing data to be transferred to another
1534 repository.
1534 repository.
1535
1535
1536 To create a bundle containing all changesets, use -a/--all
1536 To create a bundle containing all changesets, use -a/--all
1537 (or --base null). Otherwise, hg assumes the destination will have
1537 (or --base null). Otherwise, hg assumes the destination will have
1538 all the nodes you specify with --base parameters. Otherwise, hg
1538 all the nodes you specify with --base parameters. Otherwise, hg
1539 will assume the repository has all the nodes in destination, or
1539 will assume the repository has all the nodes in destination, or
1540 default-push/default if no destination is specified, where destination
1540 default-push/default if no destination is specified, where destination
1541 is the repository you provide through DEST option.
1541 is the repository you provide through DEST option.
1542
1542
1543 You can change bundle format with the -t/--type option. See
1543 You can change bundle format with the -t/--type option. See
1544 :hg:`help bundlespec` for documentation on this format. By default,
1544 :hg:`help bundlespec` for documentation on this format. By default,
1545 the most appropriate format is used and compression defaults to
1545 the most appropriate format is used and compression defaults to
1546 bzip2.
1546 bzip2.
1547
1547
1548 The bundle file can then be transferred using conventional means
1548 The bundle file can then be transferred using conventional means
1549 and applied to another repository with the unbundle or pull
1549 and applied to another repository with the unbundle or pull
1550 command. This is useful when direct push and pull are not
1550 command. This is useful when direct push and pull are not
1551 available or when exporting an entire repository is undesirable.
1551 available or when exporting an entire repository is undesirable.
1552
1552
1553 Applying bundles preserves all changeset contents including
1553 Applying bundles preserves all changeset contents including
1554 permissions, copy/rename information, and revision history.
1554 permissions, copy/rename information, and revision history.
1555
1555
1556 Returns 0 on success, 1 if no changes found.
1556 Returns 0 on success, 1 if no changes found.
1557 """
1557 """
1558 opts = pycompat.byteskwargs(opts)
1558 opts = pycompat.byteskwargs(opts)
1559 revs = None
1559 revs = None
1560 if b'rev' in opts:
1560 if b'rev' in opts:
1561 revstrings = opts[b'rev']
1561 revstrings = opts[b'rev']
1562 revs = scmutil.revrange(repo, revstrings)
1562 revs = scmutil.revrange(repo, revstrings)
1563 if revstrings and not revs:
1563 if revstrings and not revs:
1564 raise error.InputError(_(b'no commits to bundle'))
1564 raise error.InputError(_(b'no commits to bundle'))
1565
1565
1566 bundletype = opts.get(b'type', b'bzip2').lower()
1566 bundletype = opts.get(b'type', b'bzip2').lower()
1567 try:
1567 try:
1568 bundlespec = bundlecaches.parsebundlespec(
1568 bundlespec = bundlecaches.parsebundlespec(
1569 repo, bundletype, strict=False
1569 repo, bundletype, strict=False
1570 )
1570 )
1571 except error.UnsupportedBundleSpecification as e:
1571 except error.UnsupportedBundleSpecification as e:
1572 raise error.InputError(
1572 raise error.InputError(
1573 pycompat.bytestr(e),
1573 pycompat.bytestr(e),
1574 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1574 hint=_(b"see 'hg help bundlespec' for supported values for --type"),
1575 )
1575 )
1576 cgversion = bundlespec.contentopts[b"cg.version"]
1576 cgversion = bundlespec.contentopts[b"cg.version"]
1577
1577
1578 # Packed bundles are a pseudo bundle format for now.
1578 # Packed bundles are a pseudo bundle format for now.
1579 if cgversion == b's1':
1579 if cgversion == b's1':
1580 raise error.InputError(
1580 raise error.InputError(
1581 _(b'packed bundles cannot be produced by "hg bundle"'),
1581 _(b'packed bundles cannot be produced by "hg bundle"'),
1582 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1582 hint=_(b"use 'hg debugcreatestreamclonebundle'"),
1583 )
1583 )
1584
1584
1585 if opts.get(b'all'):
1585 if opts.get(b'all'):
1586 if dest:
1586 if dest:
1587 raise error.InputError(
1587 raise error.InputError(
1588 _(b"--all is incompatible with specifying a destination")
1588 _(b"--all is incompatible with specifying a destination")
1589 )
1589 )
1590 if opts.get(b'base'):
1590 if opts.get(b'base'):
1591 ui.warn(_(b"ignoring --base because --all was specified\n"))
1591 ui.warn(_(b"ignoring --base because --all was specified\n"))
1592 base = [nullrev]
1592 base = [nullrev]
1593 else:
1593 else:
1594 base = scmutil.revrange(repo, opts.get(b'base'))
1594 base = scmutil.revrange(repo, opts.get(b'base'))
1595 if cgversion not in changegroup.supportedoutgoingversions(repo):
1595 if cgversion not in changegroup.supportedoutgoingversions(repo):
1596 raise error.Abort(
1596 raise error.Abort(
1597 _(b"repository does not support bundle version %s") % cgversion
1597 _(b"repository does not support bundle version %s") % cgversion
1598 )
1598 )
1599
1599
1600 if base:
1600 if base:
1601 if dest:
1601 if dest:
1602 raise error.InputError(
1602 raise error.InputError(
1603 _(b"--base is incompatible with specifying a destination")
1603 _(b"--base is incompatible with specifying a destination")
1604 )
1604 )
1605 common = [repo[rev].node() for rev in base]
1605 common = [repo[rev].node() for rev in base]
1606 heads = [repo[r].node() for r in revs] if revs else None
1606 heads = [repo[r].node() for r in revs] if revs else None
1607 outgoing = discovery.outgoing(repo, common, heads)
1607 outgoing = discovery.outgoing(repo, common, heads)
1608 else:
1608 else:
1609 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1609 dest = ui.expandpath(dest or b'default-push', dest or b'default')
1610 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1610 dest, branches = hg.parseurl(dest, opts.get(b'branch'))
1611 other = hg.peer(repo, opts, dest)
1611 other = hg.peer(repo, opts, dest)
1612 revs = [repo[r].hex() for r in revs]
1612 revs = [repo[r].hex() for r in revs]
1613 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1613 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1614 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1614 heads = revs and pycompat.maplist(repo.lookup, revs) or revs
1615 outgoing = discovery.findcommonoutgoing(
1615 outgoing = discovery.findcommonoutgoing(
1616 repo,
1616 repo,
1617 other,
1617 other,
1618 onlyheads=heads,
1618 onlyheads=heads,
1619 force=opts.get(b'force'),
1619 force=opts.get(b'force'),
1620 portable=True,
1620 portable=True,
1621 )
1621 )
1622
1622
1623 if not outgoing.missing:
1623 if not outgoing.missing:
1624 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1624 scmutil.nochangesfound(ui, repo, not base and outgoing.excluded)
1625 return 1
1625 return 1
1626
1626
1627 if cgversion == b'01': # bundle1
1627 if cgversion == b'01': # bundle1
1628 bversion = b'HG10' + bundlespec.wirecompression
1628 bversion = b'HG10' + bundlespec.wirecompression
1629 bcompression = None
1629 bcompression = None
1630 elif cgversion in (b'02', b'03'):
1630 elif cgversion in (b'02', b'03'):
1631 bversion = b'HG20'
1631 bversion = b'HG20'
1632 bcompression = bundlespec.wirecompression
1632 bcompression = bundlespec.wirecompression
1633 else:
1633 else:
1634 raise error.ProgrammingError(
1634 raise error.ProgrammingError(
1635 b'bundle: unexpected changegroup version %s' % cgversion
1635 b'bundle: unexpected changegroup version %s' % cgversion
1636 )
1636 )
1637
1637
1638 # TODO compression options should be derived from bundlespec parsing.
1638 # TODO compression options should be derived from bundlespec parsing.
1639 # This is a temporary hack to allow adjusting bundle compression
1639 # This is a temporary hack to allow adjusting bundle compression
1640 # level without a) formalizing the bundlespec changes to declare it
1640 # level without a) formalizing the bundlespec changes to declare it
1641 # b) introducing a command flag.
1641 # b) introducing a command flag.
1642 compopts = {}
1642 compopts = {}
1643 complevel = ui.configint(
1643 complevel = ui.configint(
1644 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1644 b'experimental', b'bundlecomplevel.' + bundlespec.compression
1645 )
1645 )
1646 if complevel is None:
1646 if complevel is None:
1647 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1647 complevel = ui.configint(b'experimental', b'bundlecomplevel')
1648 if complevel is not None:
1648 if complevel is not None:
1649 compopts[b'level'] = complevel
1649 compopts[b'level'] = complevel
1650
1650
1651 # Allow overriding the bundling of obsmarker in phases through
1651 # Bundling of obsmarker and phases is optional as not all clients
1652 # configuration while we don't have a bundle version that include them
1652 # support the necessary features.
1653 if repo.ui.configbool(b'experimental', b'evolution.bundle-obsmarker'):
1653 cfg = ui.configbool
1654 bundlespec.contentopts[b'obsolescence'] = True
1654 contentopts = {
1655 if repo.ui.configbool(b'experimental', b'bundle-phases'):
1655 b'obsolescence': cfg(b'experimental', b'evolution.bundle-obsmarker'),
1656 bundlespec.contentopts[b'phases'] = True
1656 b'obsolescence-mandatory': cfg(
1657 b'experimental', b'evolution.bundle-obsmarker:mandatory'
1658 ),
1659 b'phases': cfg(b'experimental', b'bundle-phases'),
1660 }
1661 bundlespec.contentopts.update(contentopts)
1657
1662
1658 bundle2.writenewbundle(
1663 bundle2.writenewbundle(
1659 ui,
1664 ui,
1660 repo,
1665 repo,
1661 b'bundle',
1666 b'bundle',
1662 fname,
1667 fname,
1663 bversion,
1668 bversion,
1664 outgoing,
1669 outgoing,
1665 bundlespec.contentopts,
1670 bundlespec.contentopts,
1666 compression=bcompression,
1671 compression=bcompression,
1667 compopts=compopts,
1672 compopts=compopts,
1668 )
1673 )
1669
1674
1670
1675
1671 @command(
1676 @command(
1672 b'cat',
1677 b'cat',
1673 [
1678 [
1674 (
1679 (
1675 b'o',
1680 b'o',
1676 b'output',
1681 b'output',
1677 b'',
1682 b'',
1678 _(b'print output to file with formatted name'),
1683 _(b'print output to file with formatted name'),
1679 _(b'FORMAT'),
1684 _(b'FORMAT'),
1680 ),
1685 ),
1681 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1686 (b'r', b'rev', b'', _(b'print the given revision'), _(b'REV')),
1682 (b'', b'decode', None, _(b'apply any matching decode filter')),
1687 (b'', b'decode', None, _(b'apply any matching decode filter')),
1683 ]
1688 ]
1684 + walkopts
1689 + walkopts
1685 + formatteropts,
1690 + formatteropts,
1686 _(b'[OPTION]... FILE...'),
1691 _(b'[OPTION]... FILE...'),
1687 helpcategory=command.CATEGORY_FILE_CONTENTS,
1692 helpcategory=command.CATEGORY_FILE_CONTENTS,
1688 inferrepo=True,
1693 inferrepo=True,
1689 intents={INTENT_READONLY},
1694 intents={INTENT_READONLY},
1690 )
1695 )
1691 def cat(ui, repo, file1, *pats, **opts):
1696 def cat(ui, repo, file1, *pats, **opts):
1692 """output the current or given revision of files
1697 """output the current or given revision of files
1693
1698
1694 Print the specified files as they were at the given revision. If
1699 Print the specified files as they were at the given revision. If
1695 no revision is given, the parent of the working directory is used.
1700 no revision is given, the parent of the working directory is used.
1696
1701
1697 Output may be to a file, in which case the name of the file is
1702 Output may be to a file, in which case the name of the file is
1698 given using a template string. See :hg:`help templates`. In addition
1703 given using a template string. See :hg:`help templates`. In addition
1699 to the common template keywords, the following formatting rules are
1704 to the common template keywords, the following formatting rules are
1700 supported:
1705 supported:
1701
1706
1702 :``%%``: literal "%" character
1707 :``%%``: literal "%" character
1703 :``%s``: basename of file being printed
1708 :``%s``: basename of file being printed
1704 :``%d``: dirname of file being printed, or '.' if in repository root
1709 :``%d``: dirname of file being printed, or '.' if in repository root
1705 :``%p``: root-relative path name of file being printed
1710 :``%p``: root-relative path name of file being printed
1706 :``%H``: changeset hash (40 hexadecimal digits)
1711 :``%H``: changeset hash (40 hexadecimal digits)
1707 :``%R``: changeset revision number
1712 :``%R``: changeset revision number
1708 :``%h``: short-form changeset hash (12 hexadecimal digits)
1713 :``%h``: short-form changeset hash (12 hexadecimal digits)
1709 :``%r``: zero-padded changeset revision number
1714 :``%r``: zero-padded changeset revision number
1710 :``%b``: basename of the exporting repository
1715 :``%b``: basename of the exporting repository
1711 :``\\``: literal "\\" character
1716 :``\\``: literal "\\" character
1712
1717
1713 .. container:: verbose
1718 .. container:: verbose
1714
1719
1715 Template:
1720 Template:
1716
1721
1717 The following keywords are supported in addition to the common template
1722 The following keywords are supported in addition to the common template
1718 keywords and functions. See also :hg:`help templates`.
1723 keywords and functions. See also :hg:`help templates`.
1719
1724
1720 :data: String. File content.
1725 :data: String. File content.
1721 :path: String. Repository-absolute path of the file.
1726 :path: String. Repository-absolute path of the file.
1722
1727
1723 Returns 0 on success.
1728 Returns 0 on success.
1724 """
1729 """
1725 opts = pycompat.byteskwargs(opts)
1730 opts = pycompat.byteskwargs(opts)
1726 rev = opts.get(b'rev')
1731 rev = opts.get(b'rev')
1727 if rev:
1732 if rev:
1728 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1733 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
1729 ctx = scmutil.revsingle(repo, rev)
1734 ctx = scmutil.revsingle(repo, rev)
1730 m = scmutil.match(ctx, (file1,) + pats, opts)
1735 m = scmutil.match(ctx, (file1,) + pats, opts)
1731 fntemplate = opts.pop(b'output', b'')
1736 fntemplate = opts.pop(b'output', b'')
1732 if cmdutil.isstdiofilename(fntemplate):
1737 if cmdutil.isstdiofilename(fntemplate):
1733 fntemplate = b''
1738 fntemplate = b''
1734
1739
1735 if fntemplate:
1740 if fntemplate:
1736 fm = formatter.nullformatter(ui, b'cat', opts)
1741 fm = formatter.nullformatter(ui, b'cat', opts)
1737 else:
1742 else:
1738 ui.pager(b'cat')
1743 ui.pager(b'cat')
1739 fm = ui.formatter(b'cat', opts)
1744 fm = ui.formatter(b'cat', opts)
1740 with fm:
1745 with fm:
1741 return cmdutil.cat(
1746 return cmdutil.cat(
1742 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1747 ui, repo, ctx, m, fm, fntemplate, b'', **pycompat.strkwargs(opts)
1743 )
1748 )
1744
1749
1745
1750
1746 @command(
1751 @command(
1747 b'clone',
1752 b'clone',
1748 [
1753 [
1749 (
1754 (
1750 b'U',
1755 b'U',
1751 b'noupdate',
1756 b'noupdate',
1752 None,
1757 None,
1753 _(
1758 _(
1754 b'the clone will include an empty working '
1759 b'the clone will include an empty working '
1755 b'directory (only a repository)'
1760 b'directory (only a repository)'
1756 ),
1761 ),
1757 ),
1762 ),
1758 (
1763 (
1759 b'u',
1764 b'u',
1760 b'updaterev',
1765 b'updaterev',
1761 b'',
1766 b'',
1762 _(b'revision, tag, or branch to check out'),
1767 _(b'revision, tag, or branch to check out'),
1763 _(b'REV'),
1768 _(b'REV'),
1764 ),
1769 ),
1765 (
1770 (
1766 b'r',
1771 b'r',
1767 b'rev',
1772 b'rev',
1768 [],
1773 [],
1769 _(
1774 _(
1770 b'do not clone everything, but include this changeset'
1775 b'do not clone everything, but include this changeset'
1771 b' and its ancestors'
1776 b' and its ancestors'
1772 ),
1777 ),
1773 _(b'REV'),
1778 _(b'REV'),
1774 ),
1779 ),
1775 (
1780 (
1776 b'b',
1781 b'b',
1777 b'branch',
1782 b'branch',
1778 [],
1783 [],
1779 _(
1784 _(
1780 b'do not clone everything, but include this branch\'s'
1785 b'do not clone everything, but include this branch\'s'
1781 b' changesets and their ancestors'
1786 b' changesets and their ancestors'
1782 ),
1787 ),
1783 _(b'BRANCH'),
1788 _(b'BRANCH'),
1784 ),
1789 ),
1785 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1790 (b'', b'pull', None, _(b'use pull protocol to copy metadata')),
1786 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1791 (b'', b'uncompressed', None, _(b'an alias to --stream (DEPRECATED)')),
1787 (b'', b'stream', None, _(b'clone with minimal data processing')),
1792 (b'', b'stream', None, _(b'clone with minimal data processing')),
1788 ]
1793 ]
1789 + remoteopts,
1794 + remoteopts,
1790 _(b'[OPTION]... SOURCE [DEST]'),
1795 _(b'[OPTION]... SOURCE [DEST]'),
1791 helpcategory=command.CATEGORY_REPO_CREATION,
1796 helpcategory=command.CATEGORY_REPO_CREATION,
1792 helpbasic=True,
1797 helpbasic=True,
1793 norepo=True,
1798 norepo=True,
1794 )
1799 )
1795 def clone(ui, source, dest=None, **opts):
1800 def clone(ui, source, dest=None, **opts):
1796 """make a copy of an existing repository
1801 """make a copy of an existing repository
1797
1802
1798 Create a copy of an existing repository in a new directory.
1803 Create a copy of an existing repository in a new directory.
1799
1804
1800 If no destination directory name is specified, it defaults to the
1805 If no destination directory name is specified, it defaults to the
1801 basename of the source.
1806 basename of the source.
1802
1807
1803 The location of the source is added to the new repository's
1808 The location of the source is added to the new repository's
1804 ``.hg/hgrc`` file, as the default to be used for future pulls.
1809 ``.hg/hgrc`` file, as the default to be used for future pulls.
1805
1810
1806 Only local paths and ``ssh://`` URLs are supported as
1811 Only local paths and ``ssh://`` URLs are supported as
1807 destinations. For ``ssh://`` destinations, no working directory or
1812 destinations. For ``ssh://`` destinations, no working directory or
1808 ``.hg/hgrc`` will be created on the remote side.
1813 ``.hg/hgrc`` will be created on the remote side.
1809
1814
1810 If the source repository has a bookmark called '@' set, that
1815 If the source repository has a bookmark called '@' set, that
1811 revision will be checked out in the new repository by default.
1816 revision will be checked out in the new repository by default.
1812
1817
1813 To check out a particular version, use -u/--update, or
1818 To check out a particular version, use -u/--update, or
1814 -U/--noupdate to create a clone with no working directory.
1819 -U/--noupdate to create a clone with no working directory.
1815
1820
1816 To pull only a subset of changesets, specify one or more revisions
1821 To pull only a subset of changesets, specify one or more revisions
1817 identifiers with -r/--rev or branches with -b/--branch. The
1822 identifiers with -r/--rev or branches with -b/--branch. The
1818 resulting clone will contain only the specified changesets and
1823 resulting clone will contain only the specified changesets and
1819 their ancestors. These options (or 'clone src#rev dest') imply
1824 their ancestors. These options (or 'clone src#rev dest') imply
1820 --pull, even for local source repositories.
1825 --pull, even for local source repositories.
1821
1826
1822 In normal clone mode, the remote normalizes repository data into a common
1827 In normal clone mode, the remote normalizes repository data into a common
1823 exchange format and the receiving end translates this data into its local
1828 exchange format and the receiving end translates this data into its local
1824 storage format. --stream activates a different clone mode that essentially
1829 storage format. --stream activates a different clone mode that essentially
1825 copies repository files from the remote with minimal data processing. This
1830 copies repository files from the remote with minimal data processing. This
1826 significantly reduces the CPU cost of a clone both remotely and locally.
1831 significantly reduces the CPU cost of a clone both remotely and locally.
1827 However, it often increases the transferred data size by 30-40%. This can
1832 However, it often increases the transferred data size by 30-40%. This can
1828 result in substantially faster clones where I/O throughput is plentiful,
1833 result in substantially faster clones where I/O throughput is plentiful,
1829 especially for larger repositories. A side-effect of --stream clones is
1834 especially for larger repositories. A side-effect of --stream clones is
1830 that storage settings and requirements on the remote are applied locally:
1835 that storage settings and requirements on the remote are applied locally:
1831 a modern client may inherit legacy or inefficient storage used by the
1836 a modern client may inherit legacy or inefficient storage used by the
1832 remote or a legacy Mercurial client may not be able to clone from a
1837 remote or a legacy Mercurial client may not be able to clone from a
1833 modern Mercurial remote.
1838 modern Mercurial remote.
1834
1839
1835 .. note::
1840 .. note::
1836
1841
1837 Specifying a tag will include the tagged changeset but not the
1842 Specifying a tag will include the tagged changeset but not the
1838 changeset containing the tag.
1843 changeset containing the tag.
1839
1844
1840 .. container:: verbose
1845 .. container:: verbose
1841
1846
1842 For efficiency, hardlinks are used for cloning whenever the
1847 For efficiency, hardlinks are used for cloning whenever the
1843 source and destination are on the same filesystem (note this
1848 source and destination are on the same filesystem (note this
1844 applies only to the repository data, not to the working
1849 applies only to the repository data, not to the working
1845 directory). Some filesystems, such as AFS, implement hardlinking
1850 directory). Some filesystems, such as AFS, implement hardlinking
1846 incorrectly, but do not report errors. In these cases, use the
1851 incorrectly, but do not report errors. In these cases, use the
1847 --pull option to avoid hardlinking.
1852 --pull option to avoid hardlinking.
1848
1853
1849 Mercurial will update the working directory to the first applicable
1854 Mercurial will update the working directory to the first applicable
1850 revision from this list:
1855 revision from this list:
1851
1856
1852 a) null if -U or the source repository has no changesets
1857 a) null if -U or the source repository has no changesets
1853 b) if -u . and the source repository is local, the first parent of
1858 b) if -u . and the source repository is local, the first parent of
1854 the source repository's working directory
1859 the source repository's working directory
1855 c) the changeset specified with -u (if a branch name, this means the
1860 c) the changeset specified with -u (if a branch name, this means the
1856 latest head of that branch)
1861 latest head of that branch)
1857 d) the changeset specified with -r
1862 d) the changeset specified with -r
1858 e) the tipmost head specified with -b
1863 e) the tipmost head specified with -b
1859 f) the tipmost head specified with the url#branch source syntax
1864 f) the tipmost head specified with the url#branch source syntax
1860 g) the revision marked with the '@' bookmark, if present
1865 g) the revision marked with the '@' bookmark, if present
1861 h) the tipmost head of the default branch
1866 h) the tipmost head of the default branch
1862 i) tip
1867 i) tip
1863
1868
1864 When cloning from servers that support it, Mercurial may fetch
1869 When cloning from servers that support it, Mercurial may fetch
1865 pre-generated data from a server-advertised URL or inline from the
1870 pre-generated data from a server-advertised URL or inline from the
1866 same stream. When this is done, hooks operating on incoming changesets
1871 same stream. When this is done, hooks operating on incoming changesets
1867 and changegroups may fire more than once, once for each pre-generated
1872 and changegroups may fire more than once, once for each pre-generated
1868 bundle and as well as for any additional remaining data. In addition,
1873 bundle and as well as for any additional remaining data. In addition,
1869 if an error occurs, the repository may be rolled back to a partial
1874 if an error occurs, the repository may be rolled back to a partial
1870 clone. This behavior may change in future releases.
1875 clone. This behavior may change in future releases.
1871 See :hg:`help -e clonebundles` for more.
1876 See :hg:`help -e clonebundles` for more.
1872
1877
1873 Examples:
1878 Examples:
1874
1879
1875 - clone a remote repository to a new directory named hg/::
1880 - clone a remote repository to a new directory named hg/::
1876
1881
1877 hg clone https://www.mercurial-scm.org/repo/hg/
1882 hg clone https://www.mercurial-scm.org/repo/hg/
1878
1883
1879 - create a lightweight local clone::
1884 - create a lightweight local clone::
1880
1885
1881 hg clone project/ project-feature/
1886 hg clone project/ project-feature/
1882
1887
1883 - clone from an absolute path on an ssh server (note double-slash)::
1888 - clone from an absolute path on an ssh server (note double-slash)::
1884
1889
1885 hg clone ssh://user@server//home/projects/alpha/
1890 hg clone ssh://user@server//home/projects/alpha/
1886
1891
1887 - do a streaming clone while checking out a specified version::
1892 - do a streaming clone while checking out a specified version::
1888
1893
1889 hg clone --stream http://server/repo -u 1.5
1894 hg clone --stream http://server/repo -u 1.5
1890
1895
1891 - create a repository without changesets after a particular revision::
1896 - create a repository without changesets after a particular revision::
1892
1897
1893 hg clone -r 04e544 experimental/ good/
1898 hg clone -r 04e544 experimental/ good/
1894
1899
1895 - clone (and track) a particular named branch::
1900 - clone (and track) a particular named branch::
1896
1901
1897 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1902 hg clone https://www.mercurial-scm.org/repo/hg/#stable
1898
1903
1899 See :hg:`help urls` for details on specifying URLs.
1904 See :hg:`help urls` for details on specifying URLs.
1900
1905
1901 Returns 0 on success.
1906 Returns 0 on success.
1902 """
1907 """
1903 opts = pycompat.byteskwargs(opts)
1908 opts = pycompat.byteskwargs(opts)
1904 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1909 cmdutil.check_at_most_one_arg(opts, b'noupdate', b'updaterev')
1905
1910
1906 # --include/--exclude can come from narrow or sparse.
1911 # --include/--exclude can come from narrow or sparse.
1907 includepats, excludepats = None, None
1912 includepats, excludepats = None, None
1908
1913
1909 # hg.clone() differentiates between None and an empty set. So make sure
1914 # hg.clone() differentiates between None and an empty set. So make sure
1910 # patterns are sets if narrow is requested without patterns.
1915 # patterns are sets if narrow is requested without patterns.
1911 if opts.get(b'narrow'):
1916 if opts.get(b'narrow'):
1912 includepats = set()
1917 includepats = set()
1913 excludepats = set()
1918 excludepats = set()
1914
1919
1915 if opts.get(b'include'):
1920 if opts.get(b'include'):
1916 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1921 includepats = narrowspec.parsepatterns(opts.get(b'include'))
1917 if opts.get(b'exclude'):
1922 if opts.get(b'exclude'):
1918 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1923 excludepats = narrowspec.parsepatterns(opts.get(b'exclude'))
1919
1924
1920 r = hg.clone(
1925 r = hg.clone(
1921 ui,
1926 ui,
1922 opts,
1927 opts,
1923 source,
1928 source,
1924 dest,
1929 dest,
1925 pull=opts.get(b'pull'),
1930 pull=opts.get(b'pull'),
1926 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1931 stream=opts.get(b'stream') or opts.get(b'uncompressed'),
1927 revs=opts.get(b'rev'),
1932 revs=opts.get(b'rev'),
1928 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1933 update=opts.get(b'updaterev') or not opts.get(b'noupdate'),
1929 branch=opts.get(b'branch'),
1934 branch=opts.get(b'branch'),
1930 shareopts=opts.get(b'shareopts'),
1935 shareopts=opts.get(b'shareopts'),
1931 storeincludepats=includepats,
1936 storeincludepats=includepats,
1932 storeexcludepats=excludepats,
1937 storeexcludepats=excludepats,
1933 depth=opts.get(b'depth') or None,
1938 depth=opts.get(b'depth') or None,
1934 )
1939 )
1935
1940
1936 return r is None
1941 return r is None
1937
1942
1938
1943
1939 @command(
1944 @command(
1940 b'commit|ci',
1945 b'commit|ci',
1941 [
1946 [
1942 (
1947 (
1943 b'A',
1948 b'A',
1944 b'addremove',
1949 b'addremove',
1945 None,
1950 None,
1946 _(b'mark new/missing files as added/removed before committing'),
1951 _(b'mark new/missing files as added/removed before committing'),
1947 ),
1952 ),
1948 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1953 (b'', b'close-branch', None, _(b'mark a branch head as closed')),
1949 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1954 (b'', b'amend', None, _(b'amend the parent of the working directory')),
1950 (b's', b'secret', None, _(b'use the secret phase for committing')),
1955 (b's', b'secret', None, _(b'use the secret phase for committing')),
1951 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1956 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
1952 (
1957 (
1953 b'',
1958 b'',
1954 b'force-close-branch',
1959 b'force-close-branch',
1955 None,
1960 None,
1956 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1961 _(b'forcibly close branch from a non-head changeset (ADVANCED)'),
1957 ),
1962 ),
1958 (b'i', b'interactive', None, _(b'use interactive mode')),
1963 (b'i', b'interactive', None, _(b'use interactive mode')),
1959 ]
1964 ]
1960 + walkopts
1965 + walkopts
1961 + commitopts
1966 + commitopts
1962 + commitopts2
1967 + commitopts2
1963 + subrepoopts,
1968 + subrepoopts,
1964 _(b'[OPTION]... [FILE]...'),
1969 _(b'[OPTION]... [FILE]...'),
1965 helpcategory=command.CATEGORY_COMMITTING,
1970 helpcategory=command.CATEGORY_COMMITTING,
1966 helpbasic=True,
1971 helpbasic=True,
1967 inferrepo=True,
1972 inferrepo=True,
1968 )
1973 )
1969 def commit(ui, repo, *pats, **opts):
1974 def commit(ui, repo, *pats, **opts):
1970 """commit the specified files or all outstanding changes
1975 """commit the specified files or all outstanding changes
1971
1976
1972 Commit changes to the given files into the repository. Unlike a
1977 Commit changes to the given files into the repository. Unlike a
1973 centralized SCM, this operation is a local operation. See
1978 centralized SCM, this operation is a local operation. See
1974 :hg:`push` for a way to actively distribute your changes.
1979 :hg:`push` for a way to actively distribute your changes.
1975
1980
1976 If a list of files is omitted, all changes reported by :hg:`status`
1981 If a list of files is omitted, all changes reported by :hg:`status`
1977 will be committed.
1982 will be committed.
1978
1983
1979 If you are committing the result of a merge, do not provide any
1984 If you are committing the result of a merge, do not provide any
1980 filenames or -I/-X filters.
1985 filenames or -I/-X filters.
1981
1986
1982 If no commit message is specified, Mercurial starts your
1987 If no commit message is specified, Mercurial starts your
1983 configured editor where you can enter a message. In case your
1988 configured editor where you can enter a message. In case your
1984 commit fails, you will find a backup of your message in
1989 commit fails, you will find a backup of your message in
1985 ``.hg/last-message.txt``.
1990 ``.hg/last-message.txt``.
1986
1991
1987 The --close-branch flag can be used to mark the current branch
1992 The --close-branch flag can be used to mark the current branch
1988 head closed. When all heads of a branch are closed, the branch
1993 head closed. When all heads of a branch are closed, the branch
1989 will be considered closed and no longer listed.
1994 will be considered closed and no longer listed.
1990
1995
1991 The --amend flag can be used to amend the parent of the
1996 The --amend flag can be used to amend the parent of the
1992 working directory with a new commit that contains the changes
1997 working directory with a new commit that contains the changes
1993 in the parent in addition to those currently reported by :hg:`status`,
1998 in the parent in addition to those currently reported by :hg:`status`,
1994 if there are any. The old commit is stored in a backup bundle in
1999 if there are any. The old commit is stored in a backup bundle in
1995 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
2000 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1996 on how to restore it).
2001 on how to restore it).
1997
2002
1998 Message, user and date are taken from the amended commit unless
2003 Message, user and date are taken from the amended commit unless
1999 specified. When a message isn't specified on the command line,
2004 specified. When a message isn't specified on the command line,
2000 the editor will open with the message of the amended commit.
2005 the editor will open with the message of the amended commit.
2001
2006
2002 It is not possible to amend public changesets (see :hg:`help phases`)
2007 It is not possible to amend public changesets (see :hg:`help phases`)
2003 or changesets that have children.
2008 or changesets that have children.
2004
2009
2005 See :hg:`help dates` for a list of formats valid for -d/--date.
2010 See :hg:`help dates` for a list of formats valid for -d/--date.
2006
2011
2007 Returns 0 on success, 1 if nothing changed.
2012 Returns 0 on success, 1 if nothing changed.
2008
2013
2009 .. container:: verbose
2014 .. container:: verbose
2010
2015
2011 Examples:
2016 Examples:
2012
2017
2013 - commit all files ending in .py::
2018 - commit all files ending in .py::
2014
2019
2015 hg commit --include "set:**.py"
2020 hg commit --include "set:**.py"
2016
2021
2017 - commit all non-binary files::
2022 - commit all non-binary files::
2018
2023
2019 hg commit --exclude "set:binary()"
2024 hg commit --exclude "set:binary()"
2020
2025
2021 - amend the current commit and set the date to now::
2026 - amend the current commit and set the date to now::
2022
2027
2023 hg commit --amend --date now
2028 hg commit --amend --date now
2024 """
2029 """
2025 with repo.wlock(), repo.lock():
2030 with repo.wlock(), repo.lock():
2026 return _docommit(ui, repo, *pats, **opts)
2031 return _docommit(ui, repo, *pats, **opts)
2027
2032
2028
2033
2029 def _docommit(ui, repo, *pats, **opts):
2034 def _docommit(ui, repo, *pats, **opts):
2030 if opts.get('interactive'):
2035 if opts.get('interactive'):
2031 opts.pop('interactive')
2036 opts.pop('interactive')
2032 ret = cmdutil.dorecord(
2037 ret = cmdutil.dorecord(
2033 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2038 ui, repo, commit, None, False, cmdutil.recordfilter, *pats, **opts
2034 )
2039 )
2035 # ret can be 0 (no changes to record) or the value returned by
2040 # ret can be 0 (no changes to record) or the value returned by
2036 # commit(), 1 if nothing changed or None on success.
2041 # commit(), 1 if nothing changed or None on success.
2037 return 1 if ret == 0 else ret
2042 return 1 if ret == 0 else ret
2038
2043
2039 opts = pycompat.byteskwargs(opts)
2044 opts = pycompat.byteskwargs(opts)
2040 if opts.get(b'subrepos'):
2045 if opts.get(b'subrepos'):
2041 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'amend'])
2046 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'amend'])
2042 # Let --subrepos on the command line override config setting.
2047 # Let --subrepos on the command line override config setting.
2043 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2048 ui.setconfig(b'ui', b'commitsubrepos', True, b'commit')
2044
2049
2045 cmdutil.checkunfinished(repo, commit=True)
2050 cmdutil.checkunfinished(repo, commit=True)
2046
2051
2047 branch = repo[None].branch()
2052 branch = repo[None].branch()
2048 bheads = repo.branchheads(branch)
2053 bheads = repo.branchheads(branch)
2049 tip = repo.changelog.tip()
2054 tip = repo.changelog.tip()
2050
2055
2051 extra = {}
2056 extra = {}
2052 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2057 if opts.get(b'close_branch') or opts.get(b'force_close_branch'):
2053 extra[b'close'] = b'1'
2058 extra[b'close'] = b'1'
2054
2059
2055 if repo[b'.'].closesbranch():
2060 if repo[b'.'].closesbranch():
2056 raise error.InputError(
2061 raise error.InputError(
2057 _(b'current revision is already a branch closing head')
2062 _(b'current revision is already a branch closing head')
2058 )
2063 )
2059 elif not bheads:
2064 elif not bheads:
2060 raise error.InputError(
2065 raise error.InputError(
2061 _(b'branch "%s" has no heads to close') % branch
2066 _(b'branch "%s" has no heads to close') % branch
2062 )
2067 )
2063 elif (
2068 elif (
2064 branch == repo[b'.'].branch()
2069 branch == repo[b'.'].branch()
2065 and repo[b'.'].node() not in bheads
2070 and repo[b'.'].node() not in bheads
2066 and not opts.get(b'force_close_branch')
2071 and not opts.get(b'force_close_branch')
2067 ):
2072 ):
2068 hint = _(
2073 hint = _(
2069 b'use --force-close-branch to close branch from a non-head'
2074 b'use --force-close-branch to close branch from a non-head'
2070 b' changeset'
2075 b' changeset'
2071 )
2076 )
2072 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2077 raise error.InputError(_(b'can only close branch heads'), hint=hint)
2073 elif opts.get(b'amend'):
2078 elif opts.get(b'amend'):
2074 if (
2079 if (
2075 repo[b'.'].p1().branch() != branch
2080 repo[b'.'].p1().branch() != branch
2076 and repo[b'.'].p2().branch() != branch
2081 and repo[b'.'].p2().branch() != branch
2077 ):
2082 ):
2078 raise error.InputError(_(b'can only close branch heads'))
2083 raise error.InputError(_(b'can only close branch heads'))
2079
2084
2080 if opts.get(b'amend'):
2085 if opts.get(b'amend'):
2081 if ui.configbool(b'ui', b'commitsubrepos'):
2086 if ui.configbool(b'ui', b'commitsubrepos'):
2082 raise error.InputError(
2087 raise error.InputError(
2083 _(b'cannot amend with ui.commitsubrepos enabled')
2088 _(b'cannot amend with ui.commitsubrepos enabled')
2084 )
2089 )
2085
2090
2086 old = repo[b'.']
2091 old = repo[b'.']
2087 rewriteutil.precheck(repo, [old.rev()], b'amend')
2092 rewriteutil.precheck(repo, [old.rev()], b'amend')
2088
2093
2089 # Currently histedit gets confused if an amend happens while histedit
2094 # Currently histedit gets confused if an amend happens while histedit
2090 # is in progress. Since we have a checkunfinished command, we are
2095 # is in progress. Since we have a checkunfinished command, we are
2091 # temporarily honoring it.
2096 # temporarily honoring it.
2092 #
2097 #
2093 # Note: eventually this guard will be removed. Please do not expect
2098 # Note: eventually this guard will be removed. Please do not expect
2094 # this behavior to remain.
2099 # this behavior to remain.
2095 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2100 if not obsolete.isenabled(repo, obsolete.createmarkersopt):
2096 cmdutil.checkunfinished(repo)
2101 cmdutil.checkunfinished(repo)
2097
2102
2098 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2103 node = cmdutil.amend(ui, repo, old, extra, pats, opts)
2099 if node == old.node():
2104 if node == old.node():
2100 ui.status(_(b"nothing changed\n"))
2105 ui.status(_(b"nothing changed\n"))
2101 return 1
2106 return 1
2102 else:
2107 else:
2103
2108
2104 def commitfunc(ui, repo, message, match, opts):
2109 def commitfunc(ui, repo, message, match, opts):
2105 overrides = {}
2110 overrides = {}
2106 if opts.get(b'secret'):
2111 if opts.get(b'secret'):
2107 overrides[(b'phases', b'new-commit')] = b'secret'
2112 overrides[(b'phases', b'new-commit')] = b'secret'
2108
2113
2109 baseui = repo.baseui
2114 baseui = repo.baseui
2110 with baseui.configoverride(overrides, b'commit'):
2115 with baseui.configoverride(overrides, b'commit'):
2111 with ui.configoverride(overrides, b'commit'):
2116 with ui.configoverride(overrides, b'commit'):
2112 editform = cmdutil.mergeeditform(
2117 editform = cmdutil.mergeeditform(
2113 repo[None], b'commit.normal'
2118 repo[None], b'commit.normal'
2114 )
2119 )
2115 editor = cmdutil.getcommiteditor(
2120 editor = cmdutil.getcommiteditor(
2116 editform=editform, **pycompat.strkwargs(opts)
2121 editform=editform, **pycompat.strkwargs(opts)
2117 )
2122 )
2118 return repo.commit(
2123 return repo.commit(
2119 message,
2124 message,
2120 opts.get(b'user'),
2125 opts.get(b'user'),
2121 opts.get(b'date'),
2126 opts.get(b'date'),
2122 match,
2127 match,
2123 editor=editor,
2128 editor=editor,
2124 extra=extra,
2129 extra=extra,
2125 )
2130 )
2126
2131
2127 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2132 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
2128
2133
2129 if not node:
2134 if not node:
2130 stat = cmdutil.postcommitstatus(repo, pats, opts)
2135 stat = cmdutil.postcommitstatus(repo, pats, opts)
2131 if stat.deleted:
2136 if stat.deleted:
2132 ui.status(
2137 ui.status(
2133 _(
2138 _(
2134 b"nothing changed (%d missing files, see "
2139 b"nothing changed (%d missing files, see "
2135 b"'hg status')\n"
2140 b"'hg status')\n"
2136 )
2141 )
2137 % len(stat.deleted)
2142 % len(stat.deleted)
2138 )
2143 )
2139 else:
2144 else:
2140 ui.status(_(b"nothing changed\n"))
2145 ui.status(_(b"nothing changed\n"))
2141 return 1
2146 return 1
2142
2147
2143 cmdutil.commitstatus(repo, node, branch, bheads, tip, opts)
2148 cmdutil.commitstatus(repo, node, branch, bheads, tip, opts)
2144
2149
2145 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2150 if not ui.quiet and ui.configbool(b'commands', b'commit.post-status'):
2146 status(
2151 status(
2147 ui,
2152 ui,
2148 repo,
2153 repo,
2149 modified=True,
2154 modified=True,
2150 added=True,
2155 added=True,
2151 removed=True,
2156 removed=True,
2152 deleted=True,
2157 deleted=True,
2153 unknown=True,
2158 unknown=True,
2154 subrepos=opts.get(b'subrepos'),
2159 subrepos=opts.get(b'subrepos'),
2155 )
2160 )
2156
2161
2157
2162
2158 @command(
2163 @command(
2159 b'config|showconfig|debugconfig',
2164 b'config|showconfig|debugconfig',
2160 [
2165 [
2161 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2166 (b'u', b'untrusted', None, _(b'show untrusted configuration options')),
2162 (b'e', b'edit', None, _(b'edit user config')),
2167 (b'e', b'edit', None, _(b'edit user config')),
2163 (b'l', b'local', None, _(b'edit repository config')),
2168 (b'l', b'local', None, _(b'edit repository config')),
2164 (
2169 (
2165 b'',
2170 b'',
2166 b'shared',
2171 b'shared',
2167 None,
2172 None,
2168 _(b'edit shared source repository config (EXPERIMENTAL)'),
2173 _(b'edit shared source repository config (EXPERIMENTAL)'),
2169 ),
2174 ),
2170 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2175 (b'', b'non-shared', None, _(b'edit non shared config (EXPERIMENTAL)')),
2171 (b'g', b'global', None, _(b'edit global config')),
2176 (b'g', b'global', None, _(b'edit global config')),
2172 ]
2177 ]
2173 + formatteropts,
2178 + formatteropts,
2174 _(b'[-u] [NAME]...'),
2179 _(b'[-u] [NAME]...'),
2175 helpcategory=command.CATEGORY_HELP,
2180 helpcategory=command.CATEGORY_HELP,
2176 optionalrepo=True,
2181 optionalrepo=True,
2177 intents={INTENT_READONLY},
2182 intents={INTENT_READONLY},
2178 )
2183 )
2179 def config(ui, repo, *values, **opts):
2184 def config(ui, repo, *values, **opts):
2180 """show combined config settings from all hgrc files
2185 """show combined config settings from all hgrc files
2181
2186
2182 With no arguments, print names and values of all config items.
2187 With no arguments, print names and values of all config items.
2183
2188
2184 With one argument of the form section.name, print just the value
2189 With one argument of the form section.name, print just the value
2185 of that config item.
2190 of that config item.
2186
2191
2187 With multiple arguments, print names and values of all config
2192 With multiple arguments, print names and values of all config
2188 items with matching section names or section.names.
2193 items with matching section names or section.names.
2189
2194
2190 With --edit, start an editor on the user-level config file. With
2195 With --edit, start an editor on the user-level config file. With
2191 --global, edit the system-wide config file. With --local, edit the
2196 --global, edit the system-wide config file. With --local, edit the
2192 repository-level config file.
2197 repository-level config file.
2193
2198
2194 With --debug, the source (filename and line number) is printed
2199 With --debug, the source (filename and line number) is printed
2195 for each config item.
2200 for each config item.
2196
2201
2197 See :hg:`help config` for more information about config files.
2202 See :hg:`help config` for more information about config files.
2198
2203
2199 .. container:: verbose
2204 .. container:: verbose
2200
2205
2201 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2206 --non-shared flag is used to edit `.hg/hgrc-not-shared` config file.
2202 This file is not shared across shares when in share-safe mode.
2207 This file is not shared across shares when in share-safe mode.
2203
2208
2204 Template:
2209 Template:
2205
2210
2206 The following keywords are supported. See also :hg:`help templates`.
2211 The following keywords are supported. See also :hg:`help templates`.
2207
2212
2208 :name: String. Config name.
2213 :name: String. Config name.
2209 :source: String. Filename and line number where the item is defined.
2214 :source: String. Filename and line number where the item is defined.
2210 :value: String. Config value.
2215 :value: String. Config value.
2211
2216
2212 The --shared flag can be used to edit the config file of shared source
2217 The --shared flag can be used to edit the config file of shared source
2213 repository. It only works when you have shared using the experimental
2218 repository. It only works when you have shared using the experimental
2214 share safe feature.
2219 share safe feature.
2215
2220
2216 Returns 0 on success, 1 if NAME does not exist.
2221 Returns 0 on success, 1 if NAME does not exist.
2217
2222
2218 """
2223 """
2219
2224
2220 opts = pycompat.byteskwargs(opts)
2225 opts = pycompat.byteskwargs(opts)
2221 editopts = (b'edit', b'local', b'global', b'shared', b'non_shared')
2226 editopts = (b'edit', b'local', b'global', b'shared', b'non_shared')
2222 if any(opts.get(o) for o in editopts):
2227 if any(opts.get(o) for o in editopts):
2223 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2228 cmdutil.check_at_most_one_arg(opts, *editopts[1:])
2224 if opts.get(b'local'):
2229 if opts.get(b'local'):
2225 if not repo:
2230 if not repo:
2226 raise error.InputError(
2231 raise error.InputError(
2227 _(b"can't use --local outside a repository")
2232 _(b"can't use --local outside a repository")
2228 )
2233 )
2229 paths = [repo.vfs.join(b'hgrc')]
2234 paths = [repo.vfs.join(b'hgrc')]
2230 elif opts.get(b'global'):
2235 elif opts.get(b'global'):
2231 paths = rcutil.systemrcpath()
2236 paths = rcutil.systemrcpath()
2232 elif opts.get(b'shared'):
2237 elif opts.get(b'shared'):
2233 if not repo.shared():
2238 if not repo.shared():
2234 raise error.InputError(
2239 raise error.InputError(
2235 _(b"repository is not shared; can't use --shared")
2240 _(b"repository is not shared; can't use --shared")
2236 )
2241 )
2237 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2242 if requirements.SHARESAFE_REQUIREMENT not in repo.requirements:
2238 raise error.InputError(
2243 raise error.InputError(
2239 _(
2244 _(
2240 b"share safe feature not enabled; "
2245 b"share safe feature not enabled; "
2241 b"unable to edit shared source repository config"
2246 b"unable to edit shared source repository config"
2242 )
2247 )
2243 )
2248 )
2244 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2249 paths = [vfsmod.vfs(repo.sharedpath).join(b'hgrc')]
2245 elif opts.get(b'non_shared'):
2250 elif opts.get(b'non_shared'):
2246 paths = [repo.vfs.join(b'hgrc-not-shared')]
2251 paths = [repo.vfs.join(b'hgrc-not-shared')]
2247 else:
2252 else:
2248 paths = rcutil.userrcpath()
2253 paths = rcutil.userrcpath()
2249
2254
2250 for f in paths:
2255 for f in paths:
2251 if os.path.exists(f):
2256 if os.path.exists(f):
2252 break
2257 break
2253 else:
2258 else:
2254 if opts.get(b'global'):
2259 if opts.get(b'global'):
2255 samplehgrc = uimod.samplehgrcs[b'global']
2260 samplehgrc = uimod.samplehgrcs[b'global']
2256 elif opts.get(b'local'):
2261 elif opts.get(b'local'):
2257 samplehgrc = uimod.samplehgrcs[b'local']
2262 samplehgrc = uimod.samplehgrcs[b'local']
2258 else:
2263 else:
2259 samplehgrc = uimod.samplehgrcs[b'user']
2264 samplehgrc = uimod.samplehgrcs[b'user']
2260
2265
2261 f = paths[0]
2266 f = paths[0]
2262 fp = open(f, b"wb")
2267 fp = open(f, b"wb")
2263 fp.write(util.tonativeeol(samplehgrc))
2268 fp.write(util.tonativeeol(samplehgrc))
2264 fp.close()
2269 fp.close()
2265
2270
2266 editor = ui.geteditor()
2271 editor = ui.geteditor()
2267 ui.system(
2272 ui.system(
2268 b"%s \"%s\"" % (editor, f),
2273 b"%s \"%s\"" % (editor, f),
2269 onerr=error.InputError,
2274 onerr=error.InputError,
2270 errprefix=_(b"edit failed"),
2275 errprefix=_(b"edit failed"),
2271 blockedtag=b'config_edit',
2276 blockedtag=b'config_edit',
2272 )
2277 )
2273 return
2278 return
2274 ui.pager(b'config')
2279 ui.pager(b'config')
2275 fm = ui.formatter(b'config', opts)
2280 fm = ui.formatter(b'config', opts)
2276 for t, f in rcutil.rccomponents():
2281 for t, f in rcutil.rccomponents():
2277 if t == b'path':
2282 if t == b'path':
2278 ui.debug(b'read config from: %s\n' % f)
2283 ui.debug(b'read config from: %s\n' % f)
2279 elif t == b'resource':
2284 elif t == b'resource':
2280 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2285 ui.debug(b'read config from: resource:%s.%s\n' % (f[0], f[1]))
2281 elif t == b'items':
2286 elif t == b'items':
2282 # Don't print anything for 'items'.
2287 # Don't print anything for 'items'.
2283 pass
2288 pass
2284 else:
2289 else:
2285 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2290 raise error.ProgrammingError(b'unknown rctype: %s' % t)
2286 untrusted = bool(opts.get(b'untrusted'))
2291 untrusted = bool(opts.get(b'untrusted'))
2287
2292
2288 selsections = selentries = []
2293 selsections = selentries = []
2289 if values:
2294 if values:
2290 selsections = [v for v in values if b'.' not in v]
2295 selsections = [v for v in values if b'.' not in v]
2291 selentries = [v for v in values if b'.' in v]
2296 selentries = [v for v in values if b'.' in v]
2292 uniquesel = len(selentries) == 1 and not selsections
2297 uniquesel = len(selentries) == 1 and not selsections
2293 selsections = set(selsections)
2298 selsections = set(selsections)
2294 selentries = set(selentries)
2299 selentries = set(selentries)
2295
2300
2296 matched = False
2301 matched = False
2297 for section, name, value in ui.walkconfig(untrusted=untrusted):
2302 for section, name, value in ui.walkconfig(untrusted=untrusted):
2298 source = ui.configsource(section, name, untrusted)
2303 source = ui.configsource(section, name, untrusted)
2299 value = pycompat.bytestr(value)
2304 value = pycompat.bytestr(value)
2300 defaultvalue = ui.configdefault(section, name)
2305 defaultvalue = ui.configdefault(section, name)
2301 if fm.isplain():
2306 if fm.isplain():
2302 source = source or b'none'
2307 source = source or b'none'
2303 value = value.replace(b'\n', b'\\n')
2308 value = value.replace(b'\n', b'\\n')
2304 entryname = section + b'.' + name
2309 entryname = section + b'.' + name
2305 if values and not (section in selsections or entryname in selentries):
2310 if values and not (section in selsections or entryname in selentries):
2306 continue
2311 continue
2307 fm.startitem()
2312 fm.startitem()
2308 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2313 fm.condwrite(ui.debugflag, b'source', b'%s: ', source)
2309 if uniquesel:
2314 if uniquesel:
2310 fm.data(name=entryname)
2315 fm.data(name=entryname)
2311 fm.write(b'value', b'%s\n', value)
2316 fm.write(b'value', b'%s\n', value)
2312 else:
2317 else:
2313 fm.write(b'name value', b'%s=%s\n', entryname, value)
2318 fm.write(b'name value', b'%s=%s\n', entryname, value)
2314 if formatter.isprintable(defaultvalue):
2319 if formatter.isprintable(defaultvalue):
2315 fm.data(defaultvalue=defaultvalue)
2320 fm.data(defaultvalue=defaultvalue)
2316 elif isinstance(defaultvalue, list) and all(
2321 elif isinstance(defaultvalue, list) and all(
2317 formatter.isprintable(e) for e in defaultvalue
2322 formatter.isprintable(e) for e in defaultvalue
2318 ):
2323 ):
2319 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2324 fm.data(defaultvalue=fm.formatlist(defaultvalue, name=b'value'))
2320 # TODO: no idea how to process unsupported defaultvalue types
2325 # TODO: no idea how to process unsupported defaultvalue types
2321 matched = True
2326 matched = True
2322 fm.end()
2327 fm.end()
2323 if matched:
2328 if matched:
2324 return 0
2329 return 0
2325 return 1
2330 return 1
2326
2331
2327
2332
2328 @command(
2333 @command(
2329 b'continue',
2334 b'continue',
2330 dryrunopts,
2335 dryrunopts,
2331 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2336 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2332 helpbasic=True,
2337 helpbasic=True,
2333 )
2338 )
2334 def continuecmd(ui, repo, **opts):
2339 def continuecmd(ui, repo, **opts):
2335 """resumes an interrupted operation (EXPERIMENTAL)
2340 """resumes an interrupted operation (EXPERIMENTAL)
2336
2341
2337 Finishes a multistep operation like graft, histedit, rebase, merge,
2342 Finishes a multistep operation like graft, histedit, rebase, merge,
2338 and unshelve if they are in an interrupted state.
2343 and unshelve if they are in an interrupted state.
2339
2344
2340 use --dry-run/-n to dry run the command.
2345 use --dry-run/-n to dry run the command.
2341 """
2346 """
2342 dryrun = opts.get('dry_run')
2347 dryrun = opts.get('dry_run')
2343 contstate = cmdutil.getunfinishedstate(repo)
2348 contstate = cmdutil.getunfinishedstate(repo)
2344 if not contstate:
2349 if not contstate:
2345 raise error.StateError(_(b'no operation in progress'))
2350 raise error.StateError(_(b'no operation in progress'))
2346 if not contstate.continuefunc:
2351 if not contstate.continuefunc:
2347 raise error.StateError(
2352 raise error.StateError(
2348 (
2353 (
2349 _(b"%s in progress but does not support 'hg continue'")
2354 _(b"%s in progress but does not support 'hg continue'")
2350 % (contstate._opname)
2355 % (contstate._opname)
2351 ),
2356 ),
2352 hint=contstate.continuemsg(),
2357 hint=contstate.continuemsg(),
2353 )
2358 )
2354 if dryrun:
2359 if dryrun:
2355 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2360 ui.status(_(b'%s in progress, will be resumed\n') % (contstate._opname))
2356 return
2361 return
2357 return contstate.continuefunc(ui, repo)
2362 return contstate.continuefunc(ui, repo)
2358
2363
2359
2364
2360 @command(
2365 @command(
2361 b'copy|cp',
2366 b'copy|cp',
2362 [
2367 [
2363 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2368 (b'', b'forget', None, _(b'unmark a destination file as copied')),
2364 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2369 (b'A', b'after', None, _(b'record a copy that has already occurred')),
2365 (
2370 (
2366 b'',
2371 b'',
2367 b'at-rev',
2372 b'at-rev',
2368 b'',
2373 b'',
2369 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2374 _(b'(un)mark copies in the given revision (EXPERIMENTAL)'),
2370 _(b'REV'),
2375 _(b'REV'),
2371 ),
2376 ),
2372 (
2377 (
2373 b'f',
2378 b'f',
2374 b'force',
2379 b'force',
2375 None,
2380 None,
2376 _(b'forcibly copy over an existing managed file'),
2381 _(b'forcibly copy over an existing managed file'),
2377 ),
2382 ),
2378 ]
2383 ]
2379 + walkopts
2384 + walkopts
2380 + dryrunopts,
2385 + dryrunopts,
2381 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2386 _(b'[OPTION]... (SOURCE... DEST | --forget DEST...)'),
2382 helpcategory=command.CATEGORY_FILE_CONTENTS,
2387 helpcategory=command.CATEGORY_FILE_CONTENTS,
2383 )
2388 )
2384 def copy(ui, repo, *pats, **opts):
2389 def copy(ui, repo, *pats, **opts):
2385 """mark files as copied for the next commit
2390 """mark files as copied for the next commit
2386
2391
2387 Mark dest as having copies of source files. If dest is a
2392 Mark dest as having copies of source files. If dest is a
2388 directory, copies are put in that directory. If dest is a file,
2393 directory, copies are put in that directory. If dest is a file,
2389 the source must be a single file.
2394 the source must be a single file.
2390
2395
2391 By default, this command copies the contents of files as they
2396 By default, this command copies the contents of files as they
2392 exist in the working directory. If invoked with -A/--after, the
2397 exist in the working directory. If invoked with -A/--after, the
2393 operation is recorded, but no copying is performed.
2398 operation is recorded, but no copying is performed.
2394
2399
2395 To undo marking a destination file as copied, use --forget. With that
2400 To undo marking a destination file as copied, use --forget. With that
2396 option, all given (positional) arguments are unmarked as copies. The
2401 option, all given (positional) arguments are unmarked as copies. The
2397 destination file(s) will be left in place (still tracked).
2402 destination file(s) will be left in place (still tracked).
2398
2403
2399 This command takes effect with the next commit by default.
2404 This command takes effect with the next commit by default.
2400
2405
2401 Returns 0 on success, 1 if errors are encountered.
2406 Returns 0 on success, 1 if errors are encountered.
2402 """
2407 """
2403 opts = pycompat.byteskwargs(opts)
2408 opts = pycompat.byteskwargs(opts)
2404 with repo.wlock():
2409 with repo.wlock():
2405 return cmdutil.copy(ui, repo, pats, opts)
2410 return cmdutil.copy(ui, repo, pats, opts)
2406
2411
2407
2412
2408 @command(
2413 @command(
2409 b'debugcommands',
2414 b'debugcommands',
2410 [],
2415 [],
2411 _(b'[COMMAND]'),
2416 _(b'[COMMAND]'),
2412 helpcategory=command.CATEGORY_HELP,
2417 helpcategory=command.CATEGORY_HELP,
2413 norepo=True,
2418 norepo=True,
2414 )
2419 )
2415 def debugcommands(ui, cmd=b'', *args):
2420 def debugcommands(ui, cmd=b'', *args):
2416 """list all available commands and options"""
2421 """list all available commands and options"""
2417 for cmd, vals in sorted(pycompat.iteritems(table)):
2422 for cmd, vals in sorted(pycompat.iteritems(table)):
2418 cmd = cmd.split(b'|')[0]
2423 cmd = cmd.split(b'|')[0]
2419 opts = b', '.join([i[1] for i in vals[1]])
2424 opts = b', '.join([i[1] for i in vals[1]])
2420 ui.write(b'%s: %s\n' % (cmd, opts))
2425 ui.write(b'%s: %s\n' % (cmd, opts))
2421
2426
2422
2427
2423 @command(
2428 @command(
2424 b'debugcomplete',
2429 b'debugcomplete',
2425 [(b'o', b'options', None, _(b'show the command options'))],
2430 [(b'o', b'options', None, _(b'show the command options'))],
2426 _(b'[-o] CMD'),
2431 _(b'[-o] CMD'),
2427 helpcategory=command.CATEGORY_HELP,
2432 helpcategory=command.CATEGORY_HELP,
2428 norepo=True,
2433 norepo=True,
2429 )
2434 )
2430 def debugcomplete(ui, cmd=b'', **opts):
2435 def debugcomplete(ui, cmd=b'', **opts):
2431 """returns the completion list associated with the given command"""
2436 """returns the completion list associated with the given command"""
2432
2437
2433 if opts.get('options'):
2438 if opts.get('options'):
2434 options = []
2439 options = []
2435 otables = [globalopts]
2440 otables = [globalopts]
2436 if cmd:
2441 if cmd:
2437 aliases, entry = cmdutil.findcmd(cmd, table, False)
2442 aliases, entry = cmdutil.findcmd(cmd, table, False)
2438 otables.append(entry[1])
2443 otables.append(entry[1])
2439 for t in otables:
2444 for t in otables:
2440 for o in t:
2445 for o in t:
2441 if b"(DEPRECATED)" in o[3]:
2446 if b"(DEPRECATED)" in o[3]:
2442 continue
2447 continue
2443 if o[0]:
2448 if o[0]:
2444 options.append(b'-%s' % o[0])
2449 options.append(b'-%s' % o[0])
2445 options.append(b'--%s' % o[1])
2450 options.append(b'--%s' % o[1])
2446 ui.write(b"%s\n" % b"\n".join(options))
2451 ui.write(b"%s\n" % b"\n".join(options))
2447 return
2452 return
2448
2453
2449 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2454 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
2450 if ui.verbose:
2455 if ui.verbose:
2451 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2456 cmdlist = [b' '.join(c[0]) for c in cmdlist.values()]
2452 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2457 ui.write(b"%s\n" % b"\n".join(sorted(cmdlist)))
2453
2458
2454
2459
2455 @command(
2460 @command(
2456 b'diff',
2461 b'diff',
2457 [
2462 [
2458 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2463 (b'r', b'rev', [], _(b'revision (DEPRECATED)'), _(b'REV')),
2459 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2464 (b'', b'from', b'', _(b'revision to diff from'), _(b'REV1')),
2460 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2465 (b'', b'to', b'', _(b'revision to diff to'), _(b'REV2')),
2461 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2466 (b'c', b'change', b'', _(b'change made by revision'), _(b'REV')),
2462 ]
2467 ]
2463 + diffopts
2468 + diffopts
2464 + diffopts2
2469 + diffopts2
2465 + walkopts
2470 + walkopts
2466 + subrepoopts,
2471 + subrepoopts,
2467 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2472 _(b'[OPTION]... ([-c REV] | [--from REV1] [--to REV2]) [FILE]...'),
2468 helpcategory=command.CATEGORY_FILE_CONTENTS,
2473 helpcategory=command.CATEGORY_FILE_CONTENTS,
2469 helpbasic=True,
2474 helpbasic=True,
2470 inferrepo=True,
2475 inferrepo=True,
2471 intents={INTENT_READONLY},
2476 intents={INTENT_READONLY},
2472 )
2477 )
2473 def diff(ui, repo, *pats, **opts):
2478 def diff(ui, repo, *pats, **opts):
2474 """diff repository (or selected files)
2479 """diff repository (or selected files)
2475
2480
2476 Show differences between revisions for the specified files.
2481 Show differences between revisions for the specified files.
2477
2482
2478 Differences between files are shown using the unified diff format.
2483 Differences between files are shown using the unified diff format.
2479
2484
2480 .. note::
2485 .. note::
2481
2486
2482 :hg:`diff` may generate unexpected results for merges, as it will
2487 :hg:`diff` may generate unexpected results for merges, as it will
2483 default to comparing against the working directory's first
2488 default to comparing against the working directory's first
2484 parent changeset if no revisions are specified.
2489 parent changeset if no revisions are specified.
2485
2490
2486 By default, the working directory files are compared to its first parent. To
2491 By default, the working directory files are compared to its first parent. To
2487 see the differences from another revision, use --from. To see the difference
2492 see the differences from another revision, use --from. To see the difference
2488 to another revision, use --to. For example, :hg:`diff --from .^` will show
2493 to another revision, use --to. For example, :hg:`diff --from .^` will show
2489 the differences from the working copy's grandparent to the working copy,
2494 the differences from the working copy's grandparent to the working copy,
2490 :hg:`diff --to .` will show the diff from the working copy to its parent
2495 :hg:`diff --to .` will show the diff from the working copy to its parent
2491 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2496 (i.e. the reverse of the default), and :hg:`diff --from 1.0 --to 1.2` will
2492 show the diff between those two revisions.
2497 show the diff between those two revisions.
2493
2498
2494 Alternatively you can specify -c/--change with a revision to see the changes
2499 Alternatively you can specify -c/--change with a revision to see the changes
2495 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2500 in that changeset relative to its first parent (i.e. :hg:`diff -c 42` is
2496 equivalent to :hg:`diff --from 42^ --to 42`)
2501 equivalent to :hg:`diff --from 42^ --to 42`)
2497
2502
2498 Without the -a/--text option, diff will avoid generating diffs of
2503 Without the -a/--text option, diff will avoid generating diffs of
2499 files it detects as binary. With -a, diff will generate a diff
2504 files it detects as binary. With -a, diff will generate a diff
2500 anyway, probably with undesirable results.
2505 anyway, probably with undesirable results.
2501
2506
2502 Use the -g/--git option to generate diffs in the git extended diff
2507 Use the -g/--git option to generate diffs in the git extended diff
2503 format. For more information, read :hg:`help diffs`.
2508 format. For more information, read :hg:`help diffs`.
2504
2509
2505 .. container:: verbose
2510 .. container:: verbose
2506
2511
2507 Examples:
2512 Examples:
2508
2513
2509 - compare a file in the current working directory to its parent::
2514 - compare a file in the current working directory to its parent::
2510
2515
2511 hg diff foo.c
2516 hg diff foo.c
2512
2517
2513 - compare two historical versions of a directory, with rename info::
2518 - compare two historical versions of a directory, with rename info::
2514
2519
2515 hg diff --git --from 1.0 --to 1.2 lib/
2520 hg diff --git --from 1.0 --to 1.2 lib/
2516
2521
2517 - get change stats relative to the last change on some date::
2522 - get change stats relative to the last change on some date::
2518
2523
2519 hg diff --stat --from "date('may 2')"
2524 hg diff --stat --from "date('may 2')"
2520
2525
2521 - diff all newly-added files that contain a keyword::
2526 - diff all newly-added files that contain a keyword::
2522
2527
2523 hg diff "set:added() and grep(GNU)"
2528 hg diff "set:added() and grep(GNU)"
2524
2529
2525 - compare a revision and its parents::
2530 - compare a revision and its parents::
2526
2531
2527 hg diff -c 9353 # compare against first parent
2532 hg diff -c 9353 # compare against first parent
2528 hg diff --from 9353^ --to 9353 # same using revset syntax
2533 hg diff --from 9353^ --to 9353 # same using revset syntax
2529 hg diff --from 9353^2 --to 9353 # compare against the second parent
2534 hg diff --from 9353^2 --to 9353 # compare against the second parent
2530
2535
2531 Returns 0 on success.
2536 Returns 0 on success.
2532 """
2537 """
2533
2538
2534 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2539 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
2535 opts = pycompat.byteskwargs(opts)
2540 opts = pycompat.byteskwargs(opts)
2536 revs = opts.get(b'rev')
2541 revs = opts.get(b'rev')
2537 change = opts.get(b'change')
2542 change = opts.get(b'change')
2538 from_rev = opts.get(b'from')
2543 from_rev = opts.get(b'from')
2539 to_rev = opts.get(b'to')
2544 to_rev = opts.get(b'to')
2540 stat = opts.get(b'stat')
2545 stat = opts.get(b'stat')
2541 reverse = opts.get(b'reverse')
2546 reverse = opts.get(b'reverse')
2542
2547
2543 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2548 cmdutil.check_incompatible_arguments(opts, b'from', [b'rev', b'change'])
2544 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2549 cmdutil.check_incompatible_arguments(opts, b'to', [b'rev', b'change'])
2545 if change:
2550 if change:
2546 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2551 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
2547 ctx2 = scmutil.revsingle(repo, change, None)
2552 ctx2 = scmutil.revsingle(repo, change, None)
2548 ctx1 = ctx2.p1()
2553 ctx1 = ctx2.p1()
2549 elif from_rev or to_rev:
2554 elif from_rev or to_rev:
2550 repo = scmutil.unhidehashlikerevs(
2555 repo = scmutil.unhidehashlikerevs(
2551 repo, [from_rev] + [to_rev], b'nowarn'
2556 repo, [from_rev] + [to_rev], b'nowarn'
2552 )
2557 )
2553 ctx1 = scmutil.revsingle(repo, from_rev, None)
2558 ctx1 = scmutil.revsingle(repo, from_rev, None)
2554 ctx2 = scmutil.revsingle(repo, to_rev, None)
2559 ctx2 = scmutil.revsingle(repo, to_rev, None)
2555 else:
2560 else:
2556 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2561 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
2557 ctx1, ctx2 = scmutil.revpair(repo, revs)
2562 ctx1, ctx2 = scmutil.revpair(repo, revs)
2558
2563
2559 if reverse:
2564 if reverse:
2560 ctxleft = ctx2
2565 ctxleft = ctx2
2561 ctxright = ctx1
2566 ctxright = ctx1
2562 else:
2567 else:
2563 ctxleft = ctx1
2568 ctxleft = ctx1
2564 ctxright = ctx2
2569 ctxright = ctx2
2565
2570
2566 diffopts = patch.diffallopts(ui, opts)
2571 diffopts = patch.diffallopts(ui, opts)
2567 m = scmutil.match(ctx2, pats, opts)
2572 m = scmutil.match(ctx2, pats, opts)
2568 m = repo.narrowmatch(m)
2573 m = repo.narrowmatch(m)
2569 ui.pager(b'diff')
2574 ui.pager(b'diff')
2570 logcmdutil.diffordiffstat(
2575 logcmdutil.diffordiffstat(
2571 ui,
2576 ui,
2572 repo,
2577 repo,
2573 diffopts,
2578 diffopts,
2574 ctxleft,
2579 ctxleft,
2575 ctxright,
2580 ctxright,
2576 m,
2581 m,
2577 stat=stat,
2582 stat=stat,
2578 listsubrepos=opts.get(b'subrepos'),
2583 listsubrepos=opts.get(b'subrepos'),
2579 root=opts.get(b'root'),
2584 root=opts.get(b'root'),
2580 )
2585 )
2581
2586
2582
2587
2583 @command(
2588 @command(
2584 b'export',
2589 b'export',
2585 [
2590 [
2586 (
2591 (
2587 b'B',
2592 b'B',
2588 b'bookmark',
2593 b'bookmark',
2589 b'',
2594 b'',
2590 _(b'export changes only reachable by given bookmark'),
2595 _(b'export changes only reachable by given bookmark'),
2591 _(b'BOOKMARK'),
2596 _(b'BOOKMARK'),
2592 ),
2597 ),
2593 (
2598 (
2594 b'o',
2599 b'o',
2595 b'output',
2600 b'output',
2596 b'',
2601 b'',
2597 _(b'print output to file with formatted name'),
2602 _(b'print output to file with formatted name'),
2598 _(b'FORMAT'),
2603 _(b'FORMAT'),
2599 ),
2604 ),
2600 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2605 (b'', b'switch-parent', None, _(b'diff against the second parent')),
2601 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2606 (b'r', b'rev', [], _(b'revisions to export'), _(b'REV')),
2602 ]
2607 ]
2603 + diffopts
2608 + diffopts
2604 + formatteropts,
2609 + formatteropts,
2605 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2610 _(b'[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'),
2606 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2611 helpcategory=command.CATEGORY_IMPORT_EXPORT,
2607 helpbasic=True,
2612 helpbasic=True,
2608 intents={INTENT_READONLY},
2613 intents={INTENT_READONLY},
2609 )
2614 )
2610 def export(ui, repo, *changesets, **opts):
2615 def export(ui, repo, *changesets, **opts):
2611 """dump the header and diffs for one or more changesets
2616 """dump the header and diffs for one or more changesets
2612
2617
2613 Print the changeset header and diffs for one or more revisions.
2618 Print the changeset header and diffs for one or more revisions.
2614 If no revision is given, the parent of the working directory is used.
2619 If no revision is given, the parent of the working directory is used.
2615
2620
2616 The information shown in the changeset header is: author, date,
2621 The information shown in the changeset header is: author, date,
2617 branch name (if non-default), changeset hash, parent(s) and commit
2622 branch name (if non-default), changeset hash, parent(s) and commit
2618 comment.
2623 comment.
2619
2624
2620 .. note::
2625 .. note::
2621
2626
2622 :hg:`export` may generate unexpected diff output for merge
2627 :hg:`export` may generate unexpected diff output for merge
2623 changesets, as it will compare the merge changeset against its
2628 changesets, as it will compare the merge changeset against its
2624 first parent only.
2629 first parent only.
2625
2630
2626 Output may be to a file, in which case the name of the file is
2631 Output may be to a file, in which case the name of the file is
2627 given using a template string. See :hg:`help templates`. In addition
2632 given using a template string. See :hg:`help templates`. In addition
2628 to the common template keywords, the following formatting rules are
2633 to the common template keywords, the following formatting rules are
2629 supported:
2634 supported:
2630
2635
2631 :``%%``: literal "%" character
2636 :``%%``: literal "%" character
2632 :``%H``: changeset hash (40 hexadecimal digits)
2637 :``%H``: changeset hash (40 hexadecimal digits)
2633 :``%N``: number of patches being generated
2638 :``%N``: number of patches being generated
2634 :``%R``: changeset revision number
2639 :``%R``: changeset revision number
2635 :``%b``: basename of the exporting repository
2640 :``%b``: basename of the exporting repository
2636 :``%h``: short-form changeset hash (12 hexadecimal digits)
2641 :``%h``: short-form changeset hash (12 hexadecimal digits)
2637 :``%m``: first line of the commit message (only alphanumeric characters)
2642 :``%m``: first line of the commit message (only alphanumeric characters)
2638 :``%n``: zero-padded sequence number, starting at 1
2643 :``%n``: zero-padded sequence number, starting at 1
2639 :``%r``: zero-padded changeset revision number
2644 :``%r``: zero-padded changeset revision number
2640 :``\\``: literal "\\" character
2645 :``\\``: literal "\\" character
2641
2646
2642 Without the -a/--text option, export will avoid generating diffs
2647 Without the -a/--text option, export will avoid generating diffs
2643 of files it detects as binary. With -a, export will generate a
2648 of files it detects as binary. With -a, export will generate a
2644 diff anyway, probably with undesirable results.
2649 diff anyway, probably with undesirable results.
2645
2650
2646 With -B/--bookmark changesets reachable by the given bookmark are
2651 With -B/--bookmark changesets reachable by the given bookmark are
2647 selected.
2652 selected.
2648
2653
2649 Use the -g/--git option to generate diffs in the git extended diff
2654 Use the -g/--git option to generate diffs in the git extended diff
2650 format. See :hg:`help diffs` for more information.
2655 format. See :hg:`help diffs` for more information.
2651
2656
2652 With the --switch-parent option, the diff will be against the
2657 With the --switch-parent option, the diff will be against the
2653 second parent. It can be useful to review a merge.
2658 second parent. It can be useful to review a merge.
2654
2659
2655 .. container:: verbose
2660 .. container:: verbose
2656
2661
2657 Template:
2662 Template:
2658
2663
2659 The following keywords are supported in addition to the common template
2664 The following keywords are supported in addition to the common template
2660 keywords and functions. See also :hg:`help templates`.
2665 keywords and functions. See also :hg:`help templates`.
2661
2666
2662 :diff: String. Diff content.
2667 :diff: String. Diff content.
2663 :parents: List of strings. Parent nodes of the changeset.
2668 :parents: List of strings. Parent nodes of the changeset.
2664
2669
2665 Examples:
2670 Examples:
2666
2671
2667 - use export and import to transplant a bugfix to the current
2672 - use export and import to transplant a bugfix to the current
2668 branch::
2673 branch::
2669
2674
2670 hg export -r 9353 | hg import -
2675 hg export -r 9353 | hg import -
2671
2676
2672 - export all the changesets between two revisions to a file with
2677 - export all the changesets between two revisions to a file with
2673 rename information::
2678 rename information::
2674
2679
2675 hg export --git -r 123:150 > changes.txt
2680 hg export --git -r 123:150 > changes.txt
2676
2681
2677 - split outgoing changes into a series of patches with
2682 - split outgoing changes into a series of patches with
2678 descriptive names::
2683 descriptive names::
2679
2684
2680 hg export -r "outgoing()" -o "%n-%m.patch"
2685 hg export -r "outgoing()" -o "%n-%m.patch"
2681
2686
2682 Returns 0 on success.
2687 Returns 0 on success.
2683 """
2688 """
2684 opts = pycompat.byteskwargs(opts)
2689 opts = pycompat.byteskwargs(opts)
2685 bookmark = opts.get(b'bookmark')
2690 bookmark = opts.get(b'bookmark')
2686 changesets += tuple(opts.get(b'rev', []))
2691 changesets += tuple(opts.get(b'rev', []))
2687
2692
2688 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2693 cmdutil.check_at_most_one_arg(opts, b'rev', b'bookmark')
2689
2694
2690 if bookmark:
2695 if bookmark:
2691 if bookmark not in repo._bookmarks:
2696 if bookmark not in repo._bookmarks:
2692 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2697 raise error.InputError(_(b"bookmark '%s' not found") % bookmark)
2693
2698
2694 revs = scmutil.bookmarkrevs(repo, bookmark)
2699 revs = scmutil.bookmarkrevs(repo, bookmark)
2695 else:
2700 else:
2696 if not changesets:
2701 if not changesets:
2697 changesets = [b'.']
2702 changesets = [b'.']
2698
2703
2699 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2704 repo = scmutil.unhidehashlikerevs(repo, changesets, b'nowarn')
2700 revs = scmutil.revrange(repo, changesets)
2705 revs = scmutil.revrange(repo, changesets)
2701
2706
2702 if not revs:
2707 if not revs:
2703 raise error.InputError(_(b"export requires at least one changeset"))
2708 raise error.InputError(_(b"export requires at least one changeset"))
2704 if len(revs) > 1:
2709 if len(revs) > 1:
2705 ui.note(_(b'exporting patches:\n'))
2710 ui.note(_(b'exporting patches:\n'))
2706 else:
2711 else:
2707 ui.note(_(b'exporting patch:\n'))
2712 ui.note(_(b'exporting patch:\n'))
2708
2713
2709 fntemplate = opts.get(b'output')
2714 fntemplate = opts.get(b'output')
2710 if cmdutil.isstdiofilename(fntemplate):
2715 if cmdutil.isstdiofilename(fntemplate):
2711 fntemplate = b''
2716 fntemplate = b''
2712
2717
2713 if fntemplate:
2718 if fntemplate:
2714 fm = formatter.nullformatter(ui, b'export', opts)
2719 fm = formatter.nullformatter(ui, b'export', opts)
2715 else:
2720 else:
2716 ui.pager(b'export')
2721 ui.pager(b'export')
2717 fm = ui.formatter(b'export', opts)
2722 fm = ui.formatter(b'export', opts)
2718 with fm:
2723 with fm:
2719 cmdutil.export(
2724 cmdutil.export(
2720 repo,
2725 repo,
2721 revs,
2726 revs,
2722 fm,
2727 fm,
2723 fntemplate=fntemplate,
2728 fntemplate=fntemplate,
2724 switch_parent=opts.get(b'switch_parent'),
2729 switch_parent=opts.get(b'switch_parent'),
2725 opts=patch.diffallopts(ui, opts),
2730 opts=patch.diffallopts(ui, opts),
2726 )
2731 )
2727
2732
2728
2733
2729 @command(
2734 @command(
2730 b'files',
2735 b'files',
2731 [
2736 [
2732 (
2737 (
2733 b'r',
2738 b'r',
2734 b'rev',
2739 b'rev',
2735 b'',
2740 b'',
2736 _(b'search the repository as it is in REV'),
2741 _(b'search the repository as it is in REV'),
2737 _(b'REV'),
2742 _(b'REV'),
2738 ),
2743 ),
2739 (
2744 (
2740 b'0',
2745 b'0',
2741 b'print0',
2746 b'print0',
2742 None,
2747 None,
2743 _(b'end filenames with NUL, for use with xargs'),
2748 _(b'end filenames with NUL, for use with xargs'),
2744 ),
2749 ),
2745 ]
2750 ]
2746 + walkopts
2751 + walkopts
2747 + formatteropts
2752 + formatteropts
2748 + subrepoopts,
2753 + subrepoopts,
2749 _(b'[OPTION]... [FILE]...'),
2754 _(b'[OPTION]... [FILE]...'),
2750 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2755 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2751 intents={INTENT_READONLY},
2756 intents={INTENT_READONLY},
2752 )
2757 )
2753 def files(ui, repo, *pats, **opts):
2758 def files(ui, repo, *pats, **opts):
2754 """list tracked files
2759 """list tracked files
2755
2760
2756 Print files under Mercurial control in the working directory or
2761 Print files under Mercurial control in the working directory or
2757 specified revision for given files (excluding removed files).
2762 specified revision for given files (excluding removed files).
2758 Files can be specified as filenames or filesets.
2763 Files can be specified as filenames or filesets.
2759
2764
2760 If no files are given to match, this command prints the names
2765 If no files are given to match, this command prints the names
2761 of all files under Mercurial control.
2766 of all files under Mercurial control.
2762
2767
2763 .. container:: verbose
2768 .. container:: verbose
2764
2769
2765 Template:
2770 Template:
2766
2771
2767 The following keywords are supported in addition to the common template
2772 The following keywords are supported in addition to the common template
2768 keywords and functions. See also :hg:`help templates`.
2773 keywords and functions. See also :hg:`help templates`.
2769
2774
2770 :flags: String. Character denoting file's symlink and executable bits.
2775 :flags: String. Character denoting file's symlink and executable bits.
2771 :path: String. Repository-absolute path of the file.
2776 :path: String. Repository-absolute path of the file.
2772 :size: Integer. Size of the file in bytes.
2777 :size: Integer. Size of the file in bytes.
2773
2778
2774 Examples:
2779 Examples:
2775
2780
2776 - list all files under the current directory::
2781 - list all files under the current directory::
2777
2782
2778 hg files .
2783 hg files .
2779
2784
2780 - shows sizes and flags for current revision::
2785 - shows sizes and flags for current revision::
2781
2786
2782 hg files -vr .
2787 hg files -vr .
2783
2788
2784 - list all files named README::
2789 - list all files named README::
2785
2790
2786 hg files -I "**/README"
2791 hg files -I "**/README"
2787
2792
2788 - list all binary files::
2793 - list all binary files::
2789
2794
2790 hg files "set:binary()"
2795 hg files "set:binary()"
2791
2796
2792 - find files containing a regular expression::
2797 - find files containing a regular expression::
2793
2798
2794 hg files "set:grep('bob')"
2799 hg files "set:grep('bob')"
2795
2800
2796 - search tracked file contents with xargs and grep::
2801 - search tracked file contents with xargs and grep::
2797
2802
2798 hg files -0 | xargs -0 grep foo
2803 hg files -0 | xargs -0 grep foo
2799
2804
2800 See :hg:`help patterns` and :hg:`help filesets` for more information
2805 See :hg:`help patterns` and :hg:`help filesets` for more information
2801 on specifying file patterns.
2806 on specifying file patterns.
2802
2807
2803 Returns 0 if a match is found, 1 otherwise.
2808 Returns 0 if a match is found, 1 otherwise.
2804
2809
2805 """
2810 """
2806
2811
2807 opts = pycompat.byteskwargs(opts)
2812 opts = pycompat.byteskwargs(opts)
2808 rev = opts.get(b'rev')
2813 rev = opts.get(b'rev')
2809 if rev:
2814 if rev:
2810 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2815 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
2811 ctx = scmutil.revsingle(repo, rev, None)
2816 ctx = scmutil.revsingle(repo, rev, None)
2812
2817
2813 end = b'\n'
2818 end = b'\n'
2814 if opts.get(b'print0'):
2819 if opts.get(b'print0'):
2815 end = b'\0'
2820 end = b'\0'
2816 fmt = b'%s' + end
2821 fmt = b'%s' + end
2817
2822
2818 m = scmutil.match(ctx, pats, opts)
2823 m = scmutil.match(ctx, pats, opts)
2819 ui.pager(b'files')
2824 ui.pager(b'files')
2820 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2825 uipathfn = scmutil.getuipathfn(ctx.repo(), legacyrelativevalue=True)
2821 with ui.formatter(b'files', opts) as fm:
2826 with ui.formatter(b'files', opts) as fm:
2822 return cmdutil.files(
2827 return cmdutil.files(
2823 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2828 ui, ctx, m, uipathfn, fm, fmt, opts.get(b'subrepos')
2824 )
2829 )
2825
2830
2826
2831
2827 @command(
2832 @command(
2828 b'forget',
2833 b'forget',
2829 [
2834 [
2830 (b'i', b'interactive', None, _(b'use interactive mode')),
2835 (b'i', b'interactive', None, _(b'use interactive mode')),
2831 ]
2836 ]
2832 + walkopts
2837 + walkopts
2833 + dryrunopts,
2838 + dryrunopts,
2834 _(b'[OPTION]... FILE...'),
2839 _(b'[OPTION]... FILE...'),
2835 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2840 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
2836 helpbasic=True,
2841 helpbasic=True,
2837 inferrepo=True,
2842 inferrepo=True,
2838 )
2843 )
2839 def forget(ui, repo, *pats, **opts):
2844 def forget(ui, repo, *pats, **opts):
2840 """forget the specified files on the next commit
2845 """forget the specified files on the next commit
2841
2846
2842 Mark the specified files so they will no longer be tracked
2847 Mark the specified files so they will no longer be tracked
2843 after the next commit.
2848 after the next commit.
2844
2849
2845 This only removes files from the current branch, not from the
2850 This only removes files from the current branch, not from the
2846 entire project history, and it does not delete them from the
2851 entire project history, and it does not delete them from the
2847 working directory.
2852 working directory.
2848
2853
2849 To delete the file from the working directory, see :hg:`remove`.
2854 To delete the file from the working directory, see :hg:`remove`.
2850
2855
2851 To undo a forget before the next commit, see :hg:`add`.
2856 To undo a forget before the next commit, see :hg:`add`.
2852
2857
2853 .. container:: verbose
2858 .. container:: verbose
2854
2859
2855 Examples:
2860 Examples:
2856
2861
2857 - forget newly-added binary files::
2862 - forget newly-added binary files::
2858
2863
2859 hg forget "set:added() and binary()"
2864 hg forget "set:added() and binary()"
2860
2865
2861 - forget files that would be excluded by .hgignore::
2866 - forget files that would be excluded by .hgignore::
2862
2867
2863 hg forget "set:hgignore()"
2868 hg forget "set:hgignore()"
2864
2869
2865 Returns 0 on success.
2870 Returns 0 on success.
2866 """
2871 """
2867
2872
2868 opts = pycompat.byteskwargs(opts)
2873 opts = pycompat.byteskwargs(opts)
2869 if not pats:
2874 if not pats:
2870 raise error.InputError(_(b'no files specified'))
2875 raise error.InputError(_(b'no files specified'))
2871
2876
2872 m = scmutil.match(repo[None], pats, opts)
2877 m = scmutil.match(repo[None], pats, opts)
2873 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2878 dryrun, interactive = opts.get(b'dry_run'), opts.get(b'interactive')
2874 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2879 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
2875 rejected = cmdutil.forget(
2880 rejected = cmdutil.forget(
2876 ui,
2881 ui,
2877 repo,
2882 repo,
2878 m,
2883 m,
2879 prefix=b"",
2884 prefix=b"",
2880 uipathfn=uipathfn,
2885 uipathfn=uipathfn,
2881 explicitonly=False,
2886 explicitonly=False,
2882 dryrun=dryrun,
2887 dryrun=dryrun,
2883 interactive=interactive,
2888 interactive=interactive,
2884 )[0]
2889 )[0]
2885 return rejected and 1 or 0
2890 return rejected and 1 or 0
2886
2891
2887
2892
2888 @command(
2893 @command(
2889 b'graft',
2894 b'graft',
2890 [
2895 [
2891 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2896 (b'r', b'rev', [], _(b'revisions to graft'), _(b'REV')),
2892 (
2897 (
2893 b'',
2898 b'',
2894 b'base',
2899 b'base',
2895 b'',
2900 b'',
2896 _(b'base revision when doing the graft merge (ADVANCED)'),
2901 _(b'base revision when doing the graft merge (ADVANCED)'),
2897 _(b'REV'),
2902 _(b'REV'),
2898 ),
2903 ),
2899 (b'c', b'continue', False, _(b'resume interrupted graft')),
2904 (b'c', b'continue', False, _(b'resume interrupted graft')),
2900 (b'', b'stop', False, _(b'stop interrupted graft')),
2905 (b'', b'stop', False, _(b'stop interrupted graft')),
2901 (b'', b'abort', False, _(b'abort interrupted graft')),
2906 (b'', b'abort', False, _(b'abort interrupted graft')),
2902 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2907 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
2903 (b'', b'log', None, _(b'append graft info to log message')),
2908 (b'', b'log', None, _(b'append graft info to log message')),
2904 (
2909 (
2905 b'',
2910 b'',
2906 b'no-commit',
2911 b'no-commit',
2907 None,
2912 None,
2908 _(b"don't commit, just apply the changes in working directory"),
2913 _(b"don't commit, just apply the changes in working directory"),
2909 ),
2914 ),
2910 (b'f', b'force', False, _(b'force graft')),
2915 (b'f', b'force', False, _(b'force graft')),
2911 (
2916 (
2912 b'D',
2917 b'D',
2913 b'currentdate',
2918 b'currentdate',
2914 False,
2919 False,
2915 _(b'record the current date as commit date'),
2920 _(b'record the current date as commit date'),
2916 ),
2921 ),
2917 (
2922 (
2918 b'U',
2923 b'U',
2919 b'currentuser',
2924 b'currentuser',
2920 False,
2925 False,
2921 _(b'record the current user as committer'),
2926 _(b'record the current user as committer'),
2922 ),
2927 ),
2923 ]
2928 ]
2924 + commitopts2
2929 + commitopts2
2925 + mergetoolopts
2930 + mergetoolopts
2926 + dryrunopts,
2931 + dryrunopts,
2927 _(b'[OPTION]... [-r REV]... REV...'),
2932 _(b'[OPTION]... [-r REV]... REV...'),
2928 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2933 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
2929 )
2934 )
2930 def graft(ui, repo, *revs, **opts):
2935 def graft(ui, repo, *revs, **opts):
2931 """copy changes from other branches onto the current branch
2936 """copy changes from other branches onto the current branch
2932
2937
2933 This command uses Mercurial's merge logic to copy individual
2938 This command uses Mercurial's merge logic to copy individual
2934 changes from other branches without merging branches in the
2939 changes from other branches without merging branches in the
2935 history graph. This is sometimes known as 'backporting' or
2940 history graph. This is sometimes known as 'backporting' or
2936 'cherry-picking'. By default, graft will copy user, date, and
2941 'cherry-picking'. By default, graft will copy user, date, and
2937 description from the source changesets.
2942 description from the source changesets.
2938
2943
2939 Changesets that are ancestors of the current revision, that have
2944 Changesets that are ancestors of the current revision, that have
2940 already been grafted, or that are merges will be skipped.
2945 already been grafted, or that are merges will be skipped.
2941
2946
2942 If --log is specified, log messages will have a comment appended
2947 If --log is specified, log messages will have a comment appended
2943 of the form::
2948 of the form::
2944
2949
2945 (grafted from CHANGESETHASH)
2950 (grafted from CHANGESETHASH)
2946
2951
2947 If --force is specified, revisions will be grafted even if they
2952 If --force is specified, revisions will be grafted even if they
2948 are already ancestors of, or have been grafted to, the destination.
2953 are already ancestors of, or have been grafted to, the destination.
2949 This is useful when the revisions have since been backed out.
2954 This is useful when the revisions have since been backed out.
2950
2955
2951 If a graft merge results in conflicts, the graft process is
2956 If a graft merge results in conflicts, the graft process is
2952 interrupted so that the current merge can be manually resolved.
2957 interrupted so that the current merge can be manually resolved.
2953 Once all conflicts are addressed, the graft process can be
2958 Once all conflicts are addressed, the graft process can be
2954 continued with the -c/--continue option.
2959 continued with the -c/--continue option.
2955
2960
2956 The -c/--continue option reapplies all the earlier options.
2961 The -c/--continue option reapplies all the earlier options.
2957
2962
2958 .. container:: verbose
2963 .. container:: verbose
2959
2964
2960 The --base option exposes more of how graft internally uses merge with a
2965 The --base option exposes more of how graft internally uses merge with a
2961 custom base revision. --base can be used to specify another ancestor than
2966 custom base revision. --base can be used to specify another ancestor than
2962 the first and only parent.
2967 the first and only parent.
2963
2968
2964 The command::
2969 The command::
2965
2970
2966 hg graft -r 345 --base 234
2971 hg graft -r 345 --base 234
2967
2972
2968 is thus pretty much the same as::
2973 is thus pretty much the same as::
2969
2974
2970 hg diff --from 234 --to 345 | hg import
2975 hg diff --from 234 --to 345 | hg import
2971
2976
2972 but using merge to resolve conflicts and track moved files.
2977 but using merge to resolve conflicts and track moved files.
2973
2978
2974 The result of a merge can thus be backported as a single commit by
2979 The result of a merge can thus be backported as a single commit by
2975 specifying one of the merge parents as base, and thus effectively
2980 specifying one of the merge parents as base, and thus effectively
2976 grafting the changes from the other side.
2981 grafting the changes from the other side.
2977
2982
2978 It is also possible to collapse multiple changesets and clean up history
2983 It is also possible to collapse multiple changesets and clean up history
2979 by specifying another ancestor as base, much like rebase --collapse
2984 by specifying another ancestor as base, much like rebase --collapse
2980 --keep.
2985 --keep.
2981
2986
2982 The commit message can be tweaked after the fact using commit --amend .
2987 The commit message can be tweaked after the fact using commit --amend .
2983
2988
2984 For using non-ancestors as the base to backout changes, see the backout
2989 For using non-ancestors as the base to backout changes, see the backout
2985 command and the hidden --parent option.
2990 command and the hidden --parent option.
2986
2991
2987 .. container:: verbose
2992 .. container:: verbose
2988
2993
2989 Examples:
2994 Examples:
2990
2995
2991 - copy a single change to the stable branch and edit its description::
2996 - copy a single change to the stable branch and edit its description::
2992
2997
2993 hg update stable
2998 hg update stable
2994 hg graft --edit 9393
2999 hg graft --edit 9393
2995
3000
2996 - graft a range of changesets with one exception, updating dates::
3001 - graft a range of changesets with one exception, updating dates::
2997
3002
2998 hg graft -D "2085::2093 and not 2091"
3003 hg graft -D "2085::2093 and not 2091"
2999
3004
3000 - continue a graft after resolving conflicts::
3005 - continue a graft after resolving conflicts::
3001
3006
3002 hg graft -c
3007 hg graft -c
3003
3008
3004 - show the source of a grafted changeset::
3009 - show the source of a grafted changeset::
3005
3010
3006 hg log --debug -r .
3011 hg log --debug -r .
3007
3012
3008 - show revisions sorted by date::
3013 - show revisions sorted by date::
3009
3014
3010 hg log -r "sort(all(), date)"
3015 hg log -r "sort(all(), date)"
3011
3016
3012 - backport the result of a merge as a single commit::
3017 - backport the result of a merge as a single commit::
3013
3018
3014 hg graft -r 123 --base 123^
3019 hg graft -r 123 --base 123^
3015
3020
3016 - land a feature branch as one changeset::
3021 - land a feature branch as one changeset::
3017
3022
3018 hg up -cr default
3023 hg up -cr default
3019 hg graft -r featureX --base "ancestor('featureX', 'default')"
3024 hg graft -r featureX --base "ancestor('featureX', 'default')"
3020
3025
3021 See :hg:`help revisions` for more about specifying revisions.
3026 See :hg:`help revisions` for more about specifying revisions.
3022
3027
3023 Returns 0 on successful completion, 1 if there are unresolved files.
3028 Returns 0 on successful completion, 1 if there are unresolved files.
3024 """
3029 """
3025 with repo.wlock():
3030 with repo.wlock():
3026 return _dograft(ui, repo, *revs, **opts)
3031 return _dograft(ui, repo, *revs, **opts)
3027
3032
3028
3033
3029 def _dograft(ui, repo, *revs, **opts):
3034 def _dograft(ui, repo, *revs, **opts):
3030 opts = pycompat.byteskwargs(opts)
3035 opts = pycompat.byteskwargs(opts)
3031 if revs and opts.get(b'rev'):
3036 if revs and opts.get(b'rev'):
3032 ui.warn(
3037 ui.warn(
3033 _(
3038 _(
3034 b'warning: inconsistent use of --rev might give unexpected '
3039 b'warning: inconsistent use of --rev might give unexpected '
3035 b'revision ordering!\n'
3040 b'revision ordering!\n'
3036 )
3041 )
3037 )
3042 )
3038
3043
3039 revs = list(revs)
3044 revs = list(revs)
3040 revs.extend(opts.get(b'rev'))
3045 revs.extend(opts.get(b'rev'))
3041 # a dict of data to be stored in state file
3046 # a dict of data to be stored in state file
3042 statedata = {}
3047 statedata = {}
3043 # list of new nodes created by ongoing graft
3048 # list of new nodes created by ongoing graft
3044 statedata[b'newnodes'] = []
3049 statedata[b'newnodes'] = []
3045
3050
3046 cmdutil.resolvecommitoptions(ui, opts)
3051 cmdutil.resolvecommitoptions(ui, opts)
3047
3052
3048 editor = cmdutil.getcommiteditor(
3053 editor = cmdutil.getcommiteditor(
3049 editform=b'graft', **pycompat.strkwargs(opts)
3054 editform=b'graft', **pycompat.strkwargs(opts)
3050 )
3055 )
3051
3056
3052 cmdutil.check_at_most_one_arg(opts, b'abort', b'stop', b'continue')
3057 cmdutil.check_at_most_one_arg(opts, b'abort', b'stop', b'continue')
3053
3058
3054 cont = False
3059 cont = False
3055 if opts.get(b'no_commit'):
3060 if opts.get(b'no_commit'):
3056 cmdutil.check_incompatible_arguments(
3061 cmdutil.check_incompatible_arguments(
3057 opts,
3062 opts,
3058 b'no_commit',
3063 b'no_commit',
3059 [b'edit', b'currentuser', b'currentdate', b'log'],
3064 [b'edit', b'currentuser', b'currentdate', b'log'],
3060 )
3065 )
3061
3066
3062 graftstate = statemod.cmdstate(repo, b'graftstate')
3067 graftstate = statemod.cmdstate(repo, b'graftstate')
3063
3068
3064 if opts.get(b'stop'):
3069 if opts.get(b'stop'):
3065 cmdutil.check_incompatible_arguments(
3070 cmdutil.check_incompatible_arguments(
3066 opts,
3071 opts,
3067 b'stop',
3072 b'stop',
3068 [
3073 [
3069 b'edit',
3074 b'edit',
3070 b'log',
3075 b'log',
3071 b'user',
3076 b'user',
3072 b'date',
3077 b'date',
3073 b'currentdate',
3078 b'currentdate',
3074 b'currentuser',
3079 b'currentuser',
3075 b'rev',
3080 b'rev',
3076 ],
3081 ],
3077 )
3082 )
3078 return _stopgraft(ui, repo, graftstate)
3083 return _stopgraft(ui, repo, graftstate)
3079 elif opts.get(b'abort'):
3084 elif opts.get(b'abort'):
3080 cmdutil.check_incompatible_arguments(
3085 cmdutil.check_incompatible_arguments(
3081 opts,
3086 opts,
3082 b'abort',
3087 b'abort',
3083 [
3088 [
3084 b'edit',
3089 b'edit',
3085 b'log',
3090 b'log',
3086 b'user',
3091 b'user',
3087 b'date',
3092 b'date',
3088 b'currentdate',
3093 b'currentdate',
3089 b'currentuser',
3094 b'currentuser',
3090 b'rev',
3095 b'rev',
3091 ],
3096 ],
3092 )
3097 )
3093 return cmdutil.abortgraft(ui, repo, graftstate)
3098 return cmdutil.abortgraft(ui, repo, graftstate)
3094 elif opts.get(b'continue'):
3099 elif opts.get(b'continue'):
3095 cont = True
3100 cont = True
3096 if revs:
3101 if revs:
3097 raise error.InputError(_(b"can't specify --continue and revisions"))
3102 raise error.InputError(_(b"can't specify --continue and revisions"))
3098 # read in unfinished revisions
3103 # read in unfinished revisions
3099 if graftstate.exists():
3104 if graftstate.exists():
3100 statedata = cmdutil.readgraftstate(repo, graftstate)
3105 statedata = cmdutil.readgraftstate(repo, graftstate)
3101 if statedata.get(b'date'):
3106 if statedata.get(b'date'):
3102 opts[b'date'] = statedata[b'date']
3107 opts[b'date'] = statedata[b'date']
3103 if statedata.get(b'user'):
3108 if statedata.get(b'user'):
3104 opts[b'user'] = statedata[b'user']
3109 opts[b'user'] = statedata[b'user']
3105 if statedata.get(b'log'):
3110 if statedata.get(b'log'):
3106 opts[b'log'] = True
3111 opts[b'log'] = True
3107 if statedata.get(b'no_commit'):
3112 if statedata.get(b'no_commit'):
3108 opts[b'no_commit'] = statedata.get(b'no_commit')
3113 opts[b'no_commit'] = statedata.get(b'no_commit')
3109 if statedata.get(b'base'):
3114 if statedata.get(b'base'):
3110 opts[b'base'] = statedata.get(b'base')
3115 opts[b'base'] = statedata.get(b'base')
3111 nodes = statedata[b'nodes']
3116 nodes = statedata[b'nodes']
3112 revs = [repo[node].rev() for node in nodes]
3117 revs = [repo[node].rev() for node in nodes]
3113 else:
3118 else:
3114 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3119 cmdutil.wrongtooltocontinue(repo, _(b'graft'))
3115 else:
3120 else:
3116 if not revs:
3121 if not revs:
3117 raise error.InputError(_(b'no revisions specified'))
3122 raise error.InputError(_(b'no revisions specified'))
3118 cmdutil.checkunfinished(repo)
3123 cmdutil.checkunfinished(repo)
3119 cmdutil.bailifchanged(repo)
3124 cmdutil.bailifchanged(repo)
3120 revs = scmutil.revrange(repo, revs)
3125 revs = scmutil.revrange(repo, revs)
3121
3126
3122 skipped = set()
3127 skipped = set()
3123 basectx = None
3128 basectx = None
3124 if opts.get(b'base'):
3129 if opts.get(b'base'):
3125 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3130 basectx = scmutil.revsingle(repo, opts[b'base'], None)
3126 if basectx is None:
3131 if basectx is None:
3127 # check for merges
3132 # check for merges
3128 for rev in repo.revs(b'%ld and merge()', revs):
3133 for rev in repo.revs(b'%ld and merge()', revs):
3129 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3134 ui.warn(_(b'skipping ungraftable merge revision %d\n') % rev)
3130 skipped.add(rev)
3135 skipped.add(rev)
3131 revs = [r for r in revs if r not in skipped]
3136 revs = [r for r in revs if r not in skipped]
3132 if not revs:
3137 if not revs:
3133 return -1
3138 return -1
3134 if basectx is not None and len(revs) != 1:
3139 if basectx is not None and len(revs) != 1:
3135 raise error.InputError(_(b'only one revision allowed with --base '))
3140 raise error.InputError(_(b'only one revision allowed with --base '))
3136
3141
3137 # Don't check in the --continue case, in effect retaining --force across
3142 # Don't check in the --continue case, in effect retaining --force across
3138 # --continues. That's because without --force, any revisions we decided to
3143 # --continues. That's because without --force, any revisions we decided to
3139 # skip would have been filtered out here, so they wouldn't have made their
3144 # skip would have been filtered out here, so they wouldn't have made their
3140 # way to the graftstate. With --force, any revisions we would have otherwise
3145 # way to the graftstate. With --force, any revisions we would have otherwise
3141 # skipped would not have been filtered out, and if they hadn't been applied
3146 # skipped would not have been filtered out, and if they hadn't been applied
3142 # already, they'd have been in the graftstate.
3147 # already, they'd have been in the graftstate.
3143 if not (cont or opts.get(b'force')) and basectx is None:
3148 if not (cont or opts.get(b'force')) and basectx is None:
3144 # check for ancestors of dest branch
3149 # check for ancestors of dest branch
3145 ancestors = repo.revs(b'%ld & (::.)', revs)
3150 ancestors = repo.revs(b'%ld & (::.)', revs)
3146 for rev in ancestors:
3151 for rev in ancestors:
3147 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3152 ui.warn(_(b'skipping ancestor revision %d:%s\n') % (rev, repo[rev]))
3148
3153
3149 revs = [r for r in revs if r not in ancestors]
3154 revs = [r for r in revs if r not in ancestors]
3150
3155
3151 if not revs:
3156 if not revs:
3152 return -1
3157 return -1
3153
3158
3154 # analyze revs for earlier grafts
3159 # analyze revs for earlier grafts
3155 ids = {}
3160 ids = {}
3156 for ctx in repo.set(b"%ld", revs):
3161 for ctx in repo.set(b"%ld", revs):
3157 ids[ctx.hex()] = ctx.rev()
3162 ids[ctx.hex()] = ctx.rev()
3158 n = ctx.extra().get(b'source')
3163 n = ctx.extra().get(b'source')
3159 if n:
3164 if n:
3160 ids[n] = ctx.rev()
3165 ids[n] = ctx.rev()
3161
3166
3162 # check ancestors for earlier grafts
3167 # check ancestors for earlier grafts
3163 ui.debug(b'scanning for duplicate grafts\n')
3168 ui.debug(b'scanning for duplicate grafts\n')
3164
3169
3165 # The only changesets we can be sure doesn't contain grafts of any
3170 # The only changesets we can be sure doesn't contain grafts of any
3166 # revs, are the ones that are common ancestors of *all* revs:
3171 # revs, are the ones that are common ancestors of *all* revs:
3167 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3172 for rev in repo.revs(b'only(%d,ancestor(%ld))', repo[b'.'].rev(), revs):
3168 ctx = repo[rev]
3173 ctx = repo[rev]
3169 n = ctx.extra().get(b'source')
3174 n = ctx.extra().get(b'source')
3170 if n in ids:
3175 if n in ids:
3171 try:
3176 try:
3172 r = repo[n].rev()
3177 r = repo[n].rev()
3173 except error.RepoLookupError:
3178 except error.RepoLookupError:
3174 r = None
3179 r = None
3175 if r in revs:
3180 if r in revs:
3176 ui.warn(
3181 ui.warn(
3177 _(
3182 _(
3178 b'skipping revision %d:%s '
3183 b'skipping revision %d:%s '
3179 b'(already grafted to %d:%s)\n'
3184 b'(already grafted to %d:%s)\n'
3180 )
3185 )
3181 % (r, repo[r], rev, ctx)
3186 % (r, repo[r], rev, ctx)
3182 )
3187 )
3183 revs.remove(r)
3188 revs.remove(r)
3184 elif ids[n] in revs:
3189 elif ids[n] in revs:
3185 if r is None:
3190 if r is None:
3186 ui.warn(
3191 ui.warn(
3187 _(
3192 _(
3188 b'skipping already grafted revision %d:%s '
3193 b'skipping already grafted revision %d:%s '
3189 b'(%d:%s also has unknown origin %s)\n'
3194 b'(%d:%s also has unknown origin %s)\n'
3190 )
3195 )
3191 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3196 % (ids[n], repo[ids[n]], rev, ctx, n[:12])
3192 )
3197 )
3193 else:
3198 else:
3194 ui.warn(
3199 ui.warn(
3195 _(
3200 _(
3196 b'skipping already grafted revision %d:%s '
3201 b'skipping already grafted revision %d:%s '
3197 b'(%d:%s also has origin %d:%s)\n'
3202 b'(%d:%s also has origin %d:%s)\n'
3198 )
3203 )
3199 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3204 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12])
3200 )
3205 )
3201 revs.remove(ids[n])
3206 revs.remove(ids[n])
3202 elif ctx.hex() in ids:
3207 elif ctx.hex() in ids:
3203 r = ids[ctx.hex()]
3208 r = ids[ctx.hex()]
3204 if r in revs:
3209 if r in revs:
3205 ui.warn(
3210 ui.warn(
3206 _(
3211 _(
3207 b'skipping already grafted revision %d:%s '
3212 b'skipping already grafted revision %d:%s '
3208 b'(was grafted from %d:%s)\n'
3213 b'(was grafted from %d:%s)\n'
3209 )
3214 )
3210 % (r, repo[r], rev, ctx)
3215 % (r, repo[r], rev, ctx)
3211 )
3216 )
3212 revs.remove(r)
3217 revs.remove(r)
3213 if not revs:
3218 if not revs:
3214 return -1
3219 return -1
3215
3220
3216 if opts.get(b'no_commit'):
3221 if opts.get(b'no_commit'):
3217 statedata[b'no_commit'] = True
3222 statedata[b'no_commit'] = True
3218 if opts.get(b'base'):
3223 if opts.get(b'base'):
3219 statedata[b'base'] = opts[b'base']
3224 statedata[b'base'] = opts[b'base']
3220 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3225 for pos, ctx in enumerate(repo.set(b"%ld", revs)):
3221 desc = b'%d:%s "%s"' % (
3226 desc = b'%d:%s "%s"' % (
3222 ctx.rev(),
3227 ctx.rev(),
3223 ctx,
3228 ctx,
3224 ctx.description().split(b'\n', 1)[0],
3229 ctx.description().split(b'\n', 1)[0],
3225 )
3230 )
3226 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3231 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3227 if names:
3232 if names:
3228 desc += b' (%s)' % b' '.join(names)
3233 desc += b' (%s)' % b' '.join(names)
3229 ui.status(_(b'grafting %s\n') % desc)
3234 ui.status(_(b'grafting %s\n') % desc)
3230 if opts.get(b'dry_run'):
3235 if opts.get(b'dry_run'):
3231 continue
3236 continue
3232
3237
3233 source = ctx.extra().get(b'source')
3238 source = ctx.extra().get(b'source')
3234 extra = {}
3239 extra = {}
3235 if source:
3240 if source:
3236 extra[b'source'] = source
3241 extra[b'source'] = source
3237 extra[b'intermediate-source'] = ctx.hex()
3242 extra[b'intermediate-source'] = ctx.hex()
3238 else:
3243 else:
3239 extra[b'source'] = ctx.hex()
3244 extra[b'source'] = ctx.hex()
3240 user = ctx.user()
3245 user = ctx.user()
3241 if opts.get(b'user'):
3246 if opts.get(b'user'):
3242 user = opts[b'user']
3247 user = opts[b'user']
3243 statedata[b'user'] = user
3248 statedata[b'user'] = user
3244 date = ctx.date()
3249 date = ctx.date()
3245 if opts.get(b'date'):
3250 if opts.get(b'date'):
3246 date = opts[b'date']
3251 date = opts[b'date']
3247 statedata[b'date'] = date
3252 statedata[b'date'] = date
3248 message = ctx.description()
3253 message = ctx.description()
3249 if opts.get(b'log'):
3254 if opts.get(b'log'):
3250 message += b'\n(grafted from %s)' % ctx.hex()
3255 message += b'\n(grafted from %s)' % ctx.hex()
3251 statedata[b'log'] = True
3256 statedata[b'log'] = True
3252
3257
3253 # we don't merge the first commit when continuing
3258 # we don't merge the first commit when continuing
3254 if not cont:
3259 if not cont:
3255 # perform the graft merge with p1(rev) as 'ancestor'
3260 # perform the graft merge with p1(rev) as 'ancestor'
3256 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3261 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
3257 base = ctx.p1() if basectx is None else basectx
3262 base = ctx.p1() if basectx is None else basectx
3258 with ui.configoverride(overrides, b'graft'):
3263 with ui.configoverride(overrides, b'graft'):
3259 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3264 stats = mergemod.graft(repo, ctx, base, [b'local', b'graft'])
3260 # report any conflicts
3265 # report any conflicts
3261 if stats.unresolvedcount > 0:
3266 if stats.unresolvedcount > 0:
3262 # write out state for --continue
3267 # write out state for --continue
3263 nodes = [repo[rev].hex() for rev in revs[pos:]]
3268 nodes = [repo[rev].hex() for rev in revs[pos:]]
3264 statedata[b'nodes'] = nodes
3269 statedata[b'nodes'] = nodes
3265 stateversion = 1
3270 stateversion = 1
3266 graftstate.save(stateversion, statedata)
3271 graftstate.save(stateversion, statedata)
3267 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3272 ui.error(_(b"abort: unresolved conflicts, can't continue\n"))
3268 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3273 ui.error(_(b"(use 'hg resolve' and 'hg graft --continue')\n"))
3269 return 1
3274 return 1
3270 else:
3275 else:
3271 cont = False
3276 cont = False
3272
3277
3273 # commit if --no-commit is false
3278 # commit if --no-commit is false
3274 if not opts.get(b'no_commit'):
3279 if not opts.get(b'no_commit'):
3275 node = repo.commit(
3280 node = repo.commit(
3276 text=message, user=user, date=date, extra=extra, editor=editor
3281 text=message, user=user, date=date, extra=extra, editor=editor
3277 )
3282 )
3278 if node is None:
3283 if node is None:
3279 ui.warn(
3284 ui.warn(
3280 _(b'note: graft of %d:%s created no changes to commit\n')
3285 _(b'note: graft of %d:%s created no changes to commit\n')
3281 % (ctx.rev(), ctx)
3286 % (ctx.rev(), ctx)
3282 )
3287 )
3283 # checking that newnodes exist because old state files won't have it
3288 # checking that newnodes exist because old state files won't have it
3284 elif statedata.get(b'newnodes') is not None:
3289 elif statedata.get(b'newnodes') is not None:
3285 statedata[b'newnodes'].append(node)
3290 statedata[b'newnodes'].append(node)
3286
3291
3287 # remove state when we complete successfully
3292 # remove state when we complete successfully
3288 if not opts.get(b'dry_run'):
3293 if not opts.get(b'dry_run'):
3289 graftstate.delete()
3294 graftstate.delete()
3290
3295
3291 return 0
3296 return 0
3292
3297
3293
3298
3294 def _stopgraft(ui, repo, graftstate):
3299 def _stopgraft(ui, repo, graftstate):
3295 """stop the interrupted graft"""
3300 """stop the interrupted graft"""
3296 if not graftstate.exists():
3301 if not graftstate.exists():
3297 raise error.StateError(_(b"no interrupted graft found"))
3302 raise error.StateError(_(b"no interrupted graft found"))
3298 pctx = repo[b'.']
3303 pctx = repo[b'.']
3299 mergemod.clean_update(pctx)
3304 mergemod.clean_update(pctx)
3300 graftstate.delete()
3305 graftstate.delete()
3301 ui.status(_(b"stopped the interrupted graft\n"))
3306 ui.status(_(b"stopped the interrupted graft\n"))
3302 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3307 ui.status(_(b"working directory is now at %s\n") % pctx.hex()[:12])
3303 return 0
3308 return 0
3304
3309
3305
3310
3306 statemod.addunfinished(
3311 statemod.addunfinished(
3307 b'graft',
3312 b'graft',
3308 fname=b'graftstate',
3313 fname=b'graftstate',
3309 clearable=True,
3314 clearable=True,
3310 stopflag=True,
3315 stopflag=True,
3311 continueflag=True,
3316 continueflag=True,
3312 abortfunc=cmdutil.hgabortgraft,
3317 abortfunc=cmdutil.hgabortgraft,
3313 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3318 cmdhint=_(b"use 'hg graft --continue' or 'hg graft --stop' to stop"),
3314 )
3319 )
3315
3320
3316
3321
3317 @command(
3322 @command(
3318 b'grep',
3323 b'grep',
3319 [
3324 [
3320 (b'0', b'print0', None, _(b'end fields with NUL')),
3325 (b'0', b'print0', None, _(b'end fields with NUL')),
3321 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3326 (b'', b'all', None, _(b'an alias to --diff (DEPRECATED)')),
3322 (
3327 (
3323 b'',
3328 b'',
3324 b'diff',
3329 b'diff',
3325 None,
3330 None,
3326 _(
3331 _(
3327 b'search revision differences for when the pattern was added '
3332 b'search revision differences for when the pattern was added '
3328 b'or removed'
3333 b'or removed'
3329 ),
3334 ),
3330 ),
3335 ),
3331 (b'a', b'text', None, _(b'treat all files as text')),
3336 (b'a', b'text', None, _(b'treat all files as text')),
3332 (
3337 (
3333 b'f',
3338 b'f',
3334 b'follow',
3339 b'follow',
3335 None,
3340 None,
3336 _(
3341 _(
3337 b'follow changeset history,'
3342 b'follow changeset history,'
3338 b' or file history across copies and renames'
3343 b' or file history across copies and renames'
3339 ),
3344 ),
3340 ),
3345 ),
3341 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3346 (b'i', b'ignore-case', None, _(b'ignore case when matching')),
3342 (
3347 (
3343 b'l',
3348 b'l',
3344 b'files-with-matches',
3349 b'files-with-matches',
3345 None,
3350 None,
3346 _(b'print only filenames and revisions that match'),
3351 _(b'print only filenames and revisions that match'),
3347 ),
3352 ),
3348 (b'n', b'line-number', None, _(b'print matching line numbers')),
3353 (b'n', b'line-number', None, _(b'print matching line numbers')),
3349 (
3354 (
3350 b'r',
3355 b'r',
3351 b'rev',
3356 b'rev',
3352 [],
3357 [],
3353 _(b'search files changed within revision range'),
3358 _(b'search files changed within revision range'),
3354 _(b'REV'),
3359 _(b'REV'),
3355 ),
3360 ),
3356 (
3361 (
3357 b'',
3362 b'',
3358 b'all-files',
3363 b'all-files',
3359 None,
3364 None,
3360 _(
3365 _(
3361 b'include all files in the changeset while grepping (DEPRECATED)'
3366 b'include all files in the changeset while grepping (DEPRECATED)'
3362 ),
3367 ),
3363 ),
3368 ),
3364 (b'u', b'user', None, _(b'list the author (long with -v)')),
3369 (b'u', b'user', None, _(b'list the author (long with -v)')),
3365 (b'd', b'date', None, _(b'list the date (short with -q)')),
3370 (b'd', b'date', None, _(b'list the date (short with -q)')),
3366 ]
3371 ]
3367 + formatteropts
3372 + formatteropts
3368 + walkopts,
3373 + walkopts,
3369 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3374 _(b'[--diff] [OPTION]... PATTERN [FILE]...'),
3370 helpcategory=command.CATEGORY_FILE_CONTENTS,
3375 helpcategory=command.CATEGORY_FILE_CONTENTS,
3371 inferrepo=True,
3376 inferrepo=True,
3372 intents={INTENT_READONLY},
3377 intents={INTENT_READONLY},
3373 )
3378 )
3374 def grep(ui, repo, pattern, *pats, **opts):
3379 def grep(ui, repo, pattern, *pats, **opts):
3375 """search for a pattern in specified files
3380 """search for a pattern in specified files
3376
3381
3377 Search the working directory or revision history for a regular
3382 Search the working directory or revision history for a regular
3378 expression in the specified files for the entire repository.
3383 expression in the specified files for the entire repository.
3379
3384
3380 By default, grep searches the repository files in the working
3385 By default, grep searches the repository files in the working
3381 directory and prints the files where it finds a match. To specify
3386 directory and prints the files where it finds a match. To specify
3382 historical revisions instead of the working directory, use the
3387 historical revisions instead of the working directory, use the
3383 --rev flag.
3388 --rev flag.
3384
3389
3385 To search instead historical revision differences that contains a
3390 To search instead historical revision differences that contains a
3386 change in match status ("-" for a match that becomes a non-match,
3391 change in match status ("-" for a match that becomes a non-match,
3387 or "+" for a non-match that becomes a match), use the --diff flag.
3392 or "+" for a non-match that becomes a match), use the --diff flag.
3388
3393
3389 PATTERN can be any Python (roughly Perl-compatible) regular
3394 PATTERN can be any Python (roughly Perl-compatible) regular
3390 expression.
3395 expression.
3391
3396
3392 If no FILEs are specified and the --rev flag isn't supplied, all
3397 If no FILEs are specified and the --rev flag isn't supplied, all
3393 files in the working directory are searched. When using the --rev
3398 files in the working directory are searched. When using the --rev
3394 flag and specifying FILEs, use the --follow argument to also
3399 flag and specifying FILEs, use the --follow argument to also
3395 follow the specified FILEs across renames and copies.
3400 follow the specified FILEs across renames and copies.
3396
3401
3397 .. container:: verbose
3402 .. container:: verbose
3398
3403
3399 Template:
3404 Template:
3400
3405
3401 The following keywords are supported in addition to the common template
3406 The following keywords are supported in addition to the common template
3402 keywords and functions. See also :hg:`help templates`.
3407 keywords and functions. See also :hg:`help templates`.
3403
3408
3404 :change: String. Character denoting insertion ``+`` or removal ``-``.
3409 :change: String. Character denoting insertion ``+`` or removal ``-``.
3405 Available if ``--diff`` is specified.
3410 Available if ``--diff`` is specified.
3406 :lineno: Integer. Line number of the match.
3411 :lineno: Integer. Line number of the match.
3407 :path: String. Repository-absolute path of the file.
3412 :path: String. Repository-absolute path of the file.
3408 :texts: List of text chunks.
3413 :texts: List of text chunks.
3409
3414
3410 And each entry of ``{texts}`` provides the following sub-keywords.
3415 And each entry of ``{texts}`` provides the following sub-keywords.
3411
3416
3412 :matched: Boolean. True if the chunk matches the specified pattern.
3417 :matched: Boolean. True if the chunk matches the specified pattern.
3413 :text: String. Chunk content.
3418 :text: String. Chunk content.
3414
3419
3415 See :hg:`help templates.operators` for the list expansion syntax.
3420 See :hg:`help templates.operators` for the list expansion syntax.
3416
3421
3417 Returns 0 if a match is found, 1 otherwise.
3422 Returns 0 if a match is found, 1 otherwise.
3418
3423
3419 """
3424 """
3420 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3425 cmdutil.check_incompatible_arguments(opts, 'all_files', ['all', 'diff'])
3421 opts = pycompat.byteskwargs(opts)
3426 opts = pycompat.byteskwargs(opts)
3422 diff = opts.get(b'all') or opts.get(b'diff')
3427 diff = opts.get(b'all') or opts.get(b'diff')
3423 follow = opts.get(b'follow')
3428 follow = opts.get(b'follow')
3424 if opts.get(b'all_files') is None and not diff:
3429 if opts.get(b'all_files') is None and not diff:
3425 opts[b'all_files'] = True
3430 opts[b'all_files'] = True
3426 plaingrep = (
3431 plaingrep = (
3427 opts.get(b'all_files')
3432 opts.get(b'all_files')
3428 and not opts.get(b'rev')
3433 and not opts.get(b'rev')
3429 and not opts.get(b'follow')
3434 and not opts.get(b'follow')
3430 )
3435 )
3431 all_files = opts.get(b'all_files')
3436 all_files = opts.get(b'all_files')
3432 if plaingrep:
3437 if plaingrep:
3433 opts[b'rev'] = [b'wdir()']
3438 opts[b'rev'] = [b'wdir()']
3434
3439
3435 reflags = re.M
3440 reflags = re.M
3436 if opts.get(b'ignore_case'):
3441 if opts.get(b'ignore_case'):
3437 reflags |= re.I
3442 reflags |= re.I
3438 try:
3443 try:
3439 regexp = util.re.compile(pattern, reflags)
3444 regexp = util.re.compile(pattern, reflags)
3440 except re.error as inst:
3445 except re.error as inst:
3441 ui.warn(
3446 ui.warn(
3442 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3447 _(b"grep: invalid match pattern: %s\n") % pycompat.bytestr(inst)
3443 )
3448 )
3444 return 1
3449 return 1
3445 sep, eol = b':', b'\n'
3450 sep, eol = b':', b'\n'
3446 if opts.get(b'print0'):
3451 if opts.get(b'print0'):
3447 sep = eol = b'\0'
3452 sep = eol = b'\0'
3448
3453
3449 searcher = grepmod.grepsearcher(
3454 searcher = grepmod.grepsearcher(
3450 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3455 ui, repo, regexp, all_files=all_files, diff=diff, follow=follow
3451 )
3456 )
3452
3457
3453 getfile = searcher._getfile
3458 getfile = searcher._getfile
3454
3459
3455 uipathfn = scmutil.getuipathfn(repo)
3460 uipathfn = scmutil.getuipathfn(repo)
3456
3461
3457 def display(fm, fn, ctx, pstates, states):
3462 def display(fm, fn, ctx, pstates, states):
3458 rev = scmutil.intrev(ctx)
3463 rev = scmutil.intrev(ctx)
3459 if fm.isplain():
3464 if fm.isplain():
3460 formatuser = ui.shortuser
3465 formatuser = ui.shortuser
3461 else:
3466 else:
3462 formatuser = pycompat.bytestr
3467 formatuser = pycompat.bytestr
3463 if ui.quiet:
3468 if ui.quiet:
3464 datefmt = b'%Y-%m-%d'
3469 datefmt = b'%Y-%m-%d'
3465 else:
3470 else:
3466 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3471 datefmt = b'%a %b %d %H:%M:%S %Y %1%2'
3467 found = False
3472 found = False
3468
3473
3469 @util.cachefunc
3474 @util.cachefunc
3470 def binary():
3475 def binary():
3471 flog = getfile(fn)
3476 flog = getfile(fn)
3472 try:
3477 try:
3473 return stringutil.binary(flog.read(ctx.filenode(fn)))
3478 return stringutil.binary(flog.read(ctx.filenode(fn)))
3474 except error.WdirUnsupported:
3479 except error.WdirUnsupported:
3475 return ctx[fn].isbinary()
3480 return ctx[fn].isbinary()
3476
3481
3477 fieldnamemap = {b'linenumber': b'lineno'}
3482 fieldnamemap = {b'linenumber': b'lineno'}
3478 if diff:
3483 if diff:
3479 iter = grepmod.difflinestates(pstates, states)
3484 iter = grepmod.difflinestates(pstates, states)
3480 else:
3485 else:
3481 iter = [(b'', l) for l in states]
3486 iter = [(b'', l) for l in states]
3482 for change, l in iter:
3487 for change, l in iter:
3483 fm.startitem()
3488 fm.startitem()
3484 fm.context(ctx=ctx)
3489 fm.context(ctx=ctx)
3485 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3490 fm.data(node=fm.hexfunc(scmutil.binnode(ctx)), path=fn)
3486 fm.plain(uipathfn(fn), label=b'grep.filename')
3491 fm.plain(uipathfn(fn), label=b'grep.filename')
3487
3492
3488 cols = [
3493 cols = [
3489 (b'rev', b'%d', rev, not plaingrep, b''),
3494 (b'rev', b'%d', rev, not plaingrep, b''),
3490 (
3495 (
3491 b'linenumber',
3496 b'linenumber',
3492 b'%d',
3497 b'%d',
3493 l.linenum,
3498 l.linenum,
3494 opts.get(b'line_number'),
3499 opts.get(b'line_number'),
3495 b'',
3500 b'',
3496 ),
3501 ),
3497 ]
3502 ]
3498 if diff:
3503 if diff:
3499 cols.append(
3504 cols.append(
3500 (
3505 (
3501 b'change',
3506 b'change',
3502 b'%s',
3507 b'%s',
3503 change,
3508 change,
3504 True,
3509 True,
3505 b'grep.inserted '
3510 b'grep.inserted '
3506 if change == b'+'
3511 if change == b'+'
3507 else b'grep.deleted ',
3512 else b'grep.deleted ',
3508 )
3513 )
3509 )
3514 )
3510 cols.extend(
3515 cols.extend(
3511 [
3516 [
3512 (
3517 (
3513 b'user',
3518 b'user',
3514 b'%s',
3519 b'%s',
3515 formatuser(ctx.user()),
3520 formatuser(ctx.user()),
3516 opts.get(b'user'),
3521 opts.get(b'user'),
3517 b'',
3522 b'',
3518 ),
3523 ),
3519 (
3524 (
3520 b'date',
3525 b'date',
3521 b'%s',
3526 b'%s',
3522 fm.formatdate(ctx.date(), datefmt),
3527 fm.formatdate(ctx.date(), datefmt),
3523 opts.get(b'date'),
3528 opts.get(b'date'),
3524 b'',
3529 b'',
3525 ),
3530 ),
3526 ]
3531 ]
3527 )
3532 )
3528 for name, fmt, data, cond, extra_label in cols:
3533 for name, fmt, data, cond, extra_label in cols:
3529 if cond:
3534 if cond:
3530 fm.plain(sep, label=b'grep.sep')
3535 fm.plain(sep, label=b'grep.sep')
3531 field = fieldnamemap.get(name, name)
3536 field = fieldnamemap.get(name, name)
3532 label = extra_label + (b'grep.%s' % name)
3537 label = extra_label + (b'grep.%s' % name)
3533 fm.condwrite(cond, field, fmt, data, label=label)
3538 fm.condwrite(cond, field, fmt, data, label=label)
3534 if not opts.get(b'files_with_matches'):
3539 if not opts.get(b'files_with_matches'):
3535 fm.plain(sep, label=b'grep.sep')
3540 fm.plain(sep, label=b'grep.sep')
3536 if not opts.get(b'text') and binary():
3541 if not opts.get(b'text') and binary():
3537 fm.plain(_(b" Binary file matches"))
3542 fm.plain(_(b" Binary file matches"))
3538 else:
3543 else:
3539 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3544 displaymatches(fm.nested(b'texts', tmpl=b'{text}'), l)
3540 fm.plain(eol)
3545 fm.plain(eol)
3541 found = True
3546 found = True
3542 if opts.get(b'files_with_matches'):
3547 if opts.get(b'files_with_matches'):
3543 break
3548 break
3544 return found
3549 return found
3545
3550
3546 def displaymatches(fm, l):
3551 def displaymatches(fm, l):
3547 p = 0
3552 p = 0
3548 for s, e in l.findpos(regexp):
3553 for s, e in l.findpos(regexp):
3549 if p < s:
3554 if p < s:
3550 fm.startitem()
3555 fm.startitem()
3551 fm.write(b'text', b'%s', l.line[p:s])
3556 fm.write(b'text', b'%s', l.line[p:s])
3552 fm.data(matched=False)
3557 fm.data(matched=False)
3553 fm.startitem()
3558 fm.startitem()
3554 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3559 fm.write(b'text', b'%s', l.line[s:e], label=b'grep.match')
3555 fm.data(matched=True)
3560 fm.data(matched=True)
3556 p = e
3561 p = e
3557 if p < len(l.line):
3562 if p < len(l.line):
3558 fm.startitem()
3563 fm.startitem()
3559 fm.write(b'text', b'%s', l.line[p:])
3564 fm.write(b'text', b'%s', l.line[p:])
3560 fm.data(matched=False)
3565 fm.data(matched=False)
3561 fm.end()
3566 fm.end()
3562
3567
3563 found = False
3568 found = False
3564
3569
3565 wopts = logcmdutil.walkopts(
3570 wopts = logcmdutil.walkopts(
3566 pats=pats,
3571 pats=pats,
3567 opts=opts,
3572 opts=opts,
3568 revspec=opts[b'rev'],
3573 revspec=opts[b'rev'],
3569 include_pats=opts[b'include'],
3574 include_pats=opts[b'include'],
3570 exclude_pats=opts[b'exclude'],
3575 exclude_pats=opts[b'exclude'],
3571 follow=follow,
3576 follow=follow,
3572 force_changelog_traversal=all_files,
3577 force_changelog_traversal=all_files,
3573 filter_revisions_by_pats=not all_files,
3578 filter_revisions_by_pats=not all_files,
3574 )
3579 )
3575 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3580 revs, makefilematcher = logcmdutil.makewalker(repo, wopts)
3576
3581
3577 ui.pager(b'grep')
3582 ui.pager(b'grep')
3578 fm = ui.formatter(b'grep', opts)
3583 fm = ui.formatter(b'grep', opts)
3579 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3584 for fn, ctx, pstates, states in searcher.searchfiles(revs, makefilematcher):
3580 r = display(fm, fn, ctx, pstates, states)
3585 r = display(fm, fn, ctx, pstates, states)
3581 found = found or r
3586 found = found or r
3582 if r and not diff and not all_files:
3587 if r and not diff and not all_files:
3583 searcher.skipfile(fn, ctx.rev())
3588 searcher.skipfile(fn, ctx.rev())
3584 fm.end()
3589 fm.end()
3585
3590
3586 return not found
3591 return not found
3587
3592
3588
3593
3589 @command(
3594 @command(
3590 b'heads',
3595 b'heads',
3591 [
3596 [
3592 (
3597 (
3593 b'r',
3598 b'r',
3594 b'rev',
3599 b'rev',
3595 b'',
3600 b'',
3596 _(b'show only heads which are descendants of STARTREV'),
3601 _(b'show only heads which are descendants of STARTREV'),
3597 _(b'STARTREV'),
3602 _(b'STARTREV'),
3598 ),
3603 ),
3599 (b't', b'topo', False, _(b'show topological heads only')),
3604 (b't', b'topo', False, _(b'show topological heads only')),
3600 (
3605 (
3601 b'a',
3606 b'a',
3602 b'active',
3607 b'active',
3603 False,
3608 False,
3604 _(b'show active branchheads only (DEPRECATED)'),
3609 _(b'show active branchheads only (DEPRECATED)'),
3605 ),
3610 ),
3606 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3611 (b'c', b'closed', False, _(b'show normal and closed branch heads')),
3607 ]
3612 ]
3608 + templateopts,
3613 + templateopts,
3609 _(b'[-ct] [-r STARTREV] [REV]...'),
3614 _(b'[-ct] [-r STARTREV] [REV]...'),
3610 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3615 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3611 intents={INTENT_READONLY},
3616 intents={INTENT_READONLY},
3612 )
3617 )
3613 def heads(ui, repo, *branchrevs, **opts):
3618 def heads(ui, repo, *branchrevs, **opts):
3614 """show branch heads
3619 """show branch heads
3615
3620
3616 With no arguments, show all open branch heads in the repository.
3621 With no arguments, show all open branch heads in the repository.
3617 Branch heads are changesets that have no descendants on the
3622 Branch heads are changesets that have no descendants on the
3618 same branch. They are where development generally takes place and
3623 same branch. They are where development generally takes place and
3619 are the usual targets for update and merge operations.
3624 are the usual targets for update and merge operations.
3620
3625
3621 If one or more REVs are given, only open branch heads on the
3626 If one or more REVs are given, only open branch heads on the
3622 branches associated with the specified changesets are shown. This
3627 branches associated with the specified changesets are shown. This
3623 means that you can use :hg:`heads .` to see the heads on the
3628 means that you can use :hg:`heads .` to see the heads on the
3624 currently checked-out branch.
3629 currently checked-out branch.
3625
3630
3626 If -c/--closed is specified, also show branch heads marked closed
3631 If -c/--closed is specified, also show branch heads marked closed
3627 (see :hg:`commit --close-branch`).
3632 (see :hg:`commit --close-branch`).
3628
3633
3629 If STARTREV is specified, only those heads that are descendants of
3634 If STARTREV is specified, only those heads that are descendants of
3630 STARTREV will be displayed.
3635 STARTREV will be displayed.
3631
3636
3632 If -t/--topo is specified, named branch mechanics will be ignored and only
3637 If -t/--topo is specified, named branch mechanics will be ignored and only
3633 topological heads (changesets with no children) will be shown.
3638 topological heads (changesets with no children) will be shown.
3634
3639
3635 Returns 0 if matching heads are found, 1 if not.
3640 Returns 0 if matching heads are found, 1 if not.
3636 """
3641 """
3637
3642
3638 opts = pycompat.byteskwargs(opts)
3643 opts = pycompat.byteskwargs(opts)
3639 start = None
3644 start = None
3640 rev = opts.get(b'rev')
3645 rev = opts.get(b'rev')
3641 if rev:
3646 if rev:
3642 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3647 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3643 start = scmutil.revsingle(repo, rev, None).node()
3648 start = scmutil.revsingle(repo, rev, None).node()
3644
3649
3645 if opts.get(b'topo'):
3650 if opts.get(b'topo'):
3646 heads = [repo[h] for h in repo.heads(start)]
3651 heads = [repo[h] for h in repo.heads(start)]
3647 else:
3652 else:
3648 heads = []
3653 heads = []
3649 for branch in repo.branchmap():
3654 for branch in repo.branchmap():
3650 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3655 heads += repo.branchheads(branch, start, opts.get(b'closed'))
3651 heads = [repo[h] for h in heads]
3656 heads = [repo[h] for h in heads]
3652
3657
3653 if branchrevs:
3658 if branchrevs:
3654 branches = {
3659 branches = {
3655 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3660 repo[r].branch() for r in scmutil.revrange(repo, branchrevs)
3656 }
3661 }
3657 heads = [h for h in heads if h.branch() in branches]
3662 heads = [h for h in heads if h.branch() in branches]
3658
3663
3659 if opts.get(b'active') and branchrevs:
3664 if opts.get(b'active') and branchrevs:
3660 dagheads = repo.heads(start)
3665 dagheads = repo.heads(start)
3661 heads = [h for h in heads if h.node() in dagheads]
3666 heads = [h for h in heads if h.node() in dagheads]
3662
3667
3663 if branchrevs:
3668 if branchrevs:
3664 haveheads = {h.branch() for h in heads}
3669 haveheads = {h.branch() for h in heads}
3665 if branches - haveheads:
3670 if branches - haveheads:
3666 headless = b', '.join(b for b in branches - haveheads)
3671 headless = b', '.join(b for b in branches - haveheads)
3667 msg = _(b'no open branch heads found on branches %s')
3672 msg = _(b'no open branch heads found on branches %s')
3668 if opts.get(b'rev'):
3673 if opts.get(b'rev'):
3669 msg += _(b' (started at %s)') % opts[b'rev']
3674 msg += _(b' (started at %s)') % opts[b'rev']
3670 ui.warn((msg + b'\n') % headless)
3675 ui.warn((msg + b'\n') % headless)
3671
3676
3672 if not heads:
3677 if not heads:
3673 return 1
3678 return 1
3674
3679
3675 ui.pager(b'heads')
3680 ui.pager(b'heads')
3676 heads = sorted(heads, key=lambda x: -(x.rev()))
3681 heads = sorted(heads, key=lambda x: -(x.rev()))
3677 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3682 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
3678 for ctx in heads:
3683 for ctx in heads:
3679 displayer.show(ctx)
3684 displayer.show(ctx)
3680 displayer.close()
3685 displayer.close()
3681
3686
3682
3687
3683 @command(
3688 @command(
3684 b'help',
3689 b'help',
3685 [
3690 [
3686 (b'e', b'extension', None, _(b'show only help for extensions')),
3691 (b'e', b'extension', None, _(b'show only help for extensions')),
3687 (b'c', b'command', None, _(b'show only help for commands')),
3692 (b'c', b'command', None, _(b'show only help for commands')),
3688 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3693 (b'k', b'keyword', None, _(b'show topics matching keyword')),
3689 (
3694 (
3690 b's',
3695 b's',
3691 b'system',
3696 b'system',
3692 [],
3697 [],
3693 _(b'show help for specific platform(s)'),
3698 _(b'show help for specific platform(s)'),
3694 _(b'PLATFORM'),
3699 _(b'PLATFORM'),
3695 ),
3700 ),
3696 ],
3701 ],
3697 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3702 _(b'[-eck] [-s PLATFORM] [TOPIC]'),
3698 helpcategory=command.CATEGORY_HELP,
3703 helpcategory=command.CATEGORY_HELP,
3699 norepo=True,
3704 norepo=True,
3700 intents={INTENT_READONLY},
3705 intents={INTENT_READONLY},
3701 )
3706 )
3702 def help_(ui, name=None, **opts):
3707 def help_(ui, name=None, **opts):
3703 """show help for a given topic or a help overview
3708 """show help for a given topic or a help overview
3704
3709
3705 With no arguments, print a list of commands with short help messages.
3710 With no arguments, print a list of commands with short help messages.
3706
3711
3707 Given a topic, extension, or command name, print help for that
3712 Given a topic, extension, or command name, print help for that
3708 topic.
3713 topic.
3709
3714
3710 Returns 0 if successful.
3715 Returns 0 if successful.
3711 """
3716 """
3712
3717
3713 keep = opts.get('system') or []
3718 keep = opts.get('system') or []
3714 if len(keep) == 0:
3719 if len(keep) == 0:
3715 if pycompat.sysplatform.startswith(b'win'):
3720 if pycompat.sysplatform.startswith(b'win'):
3716 keep.append(b'windows')
3721 keep.append(b'windows')
3717 elif pycompat.sysplatform == b'OpenVMS':
3722 elif pycompat.sysplatform == b'OpenVMS':
3718 keep.append(b'vms')
3723 keep.append(b'vms')
3719 elif pycompat.sysplatform == b'plan9':
3724 elif pycompat.sysplatform == b'plan9':
3720 keep.append(b'plan9')
3725 keep.append(b'plan9')
3721 else:
3726 else:
3722 keep.append(b'unix')
3727 keep.append(b'unix')
3723 keep.append(pycompat.sysplatform.lower())
3728 keep.append(pycompat.sysplatform.lower())
3724 if ui.verbose:
3729 if ui.verbose:
3725 keep.append(b'verbose')
3730 keep.append(b'verbose')
3726
3731
3727 commands = sys.modules[__name__]
3732 commands = sys.modules[__name__]
3728 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3733 formatted = help.formattedhelp(ui, commands, name, keep=keep, **opts)
3729 ui.pager(b'help')
3734 ui.pager(b'help')
3730 ui.write(formatted)
3735 ui.write(formatted)
3731
3736
3732
3737
3733 @command(
3738 @command(
3734 b'identify|id',
3739 b'identify|id',
3735 [
3740 [
3736 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3741 (b'r', b'rev', b'', _(b'identify the specified revision'), _(b'REV')),
3737 (b'n', b'num', None, _(b'show local revision number')),
3742 (b'n', b'num', None, _(b'show local revision number')),
3738 (b'i', b'id', None, _(b'show global revision id')),
3743 (b'i', b'id', None, _(b'show global revision id')),
3739 (b'b', b'branch', None, _(b'show branch')),
3744 (b'b', b'branch', None, _(b'show branch')),
3740 (b't', b'tags', None, _(b'show tags')),
3745 (b't', b'tags', None, _(b'show tags')),
3741 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3746 (b'B', b'bookmarks', None, _(b'show bookmarks')),
3742 ]
3747 ]
3743 + remoteopts
3748 + remoteopts
3744 + formatteropts,
3749 + formatteropts,
3745 _(b'[-nibtB] [-r REV] [SOURCE]'),
3750 _(b'[-nibtB] [-r REV] [SOURCE]'),
3746 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3751 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
3747 optionalrepo=True,
3752 optionalrepo=True,
3748 intents={INTENT_READONLY},
3753 intents={INTENT_READONLY},
3749 )
3754 )
3750 def identify(
3755 def identify(
3751 ui,
3756 ui,
3752 repo,
3757 repo,
3753 source=None,
3758 source=None,
3754 rev=None,
3759 rev=None,
3755 num=None,
3760 num=None,
3756 id=None,
3761 id=None,
3757 branch=None,
3762 branch=None,
3758 tags=None,
3763 tags=None,
3759 bookmarks=None,
3764 bookmarks=None,
3760 **opts
3765 **opts
3761 ):
3766 ):
3762 """identify the working directory or specified revision
3767 """identify the working directory or specified revision
3763
3768
3764 Print a summary identifying the repository state at REV using one or
3769 Print a summary identifying the repository state at REV using one or
3765 two parent hash identifiers, followed by a "+" if the working
3770 two parent hash identifiers, followed by a "+" if the working
3766 directory has uncommitted changes, the branch name (if not default),
3771 directory has uncommitted changes, the branch name (if not default),
3767 a list of tags, and a list of bookmarks.
3772 a list of tags, and a list of bookmarks.
3768
3773
3769 When REV is not given, print a summary of the current state of the
3774 When REV is not given, print a summary of the current state of the
3770 repository including the working directory. Specify -r. to get information
3775 repository including the working directory. Specify -r. to get information
3771 of the working directory parent without scanning uncommitted changes.
3776 of the working directory parent without scanning uncommitted changes.
3772
3777
3773 Specifying a path to a repository root or Mercurial bundle will
3778 Specifying a path to a repository root or Mercurial bundle will
3774 cause lookup to operate on that repository/bundle.
3779 cause lookup to operate on that repository/bundle.
3775
3780
3776 .. container:: verbose
3781 .. container:: verbose
3777
3782
3778 Template:
3783 Template:
3779
3784
3780 The following keywords are supported in addition to the common template
3785 The following keywords are supported in addition to the common template
3781 keywords and functions. See also :hg:`help templates`.
3786 keywords and functions. See also :hg:`help templates`.
3782
3787
3783 :dirty: String. Character ``+`` denoting if the working directory has
3788 :dirty: String. Character ``+`` denoting if the working directory has
3784 uncommitted changes.
3789 uncommitted changes.
3785 :id: String. One or two nodes, optionally followed by ``+``.
3790 :id: String. One or two nodes, optionally followed by ``+``.
3786 :parents: List of strings. Parent nodes of the changeset.
3791 :parents: List of strings. Parent nodes of the changeset.
3787
3792
3788 Examples:
3793 Examples:
3789
3794
3790 - generate a build identifier for the working directory::
3795 - generate a build identifier for the working directory::
3791
3796
3792 hg id --id > build-id.dat
3797 hg id --id > build-id.dat
3793
3798
3794 - find the revision corresponding to a tag::
3799 - find the revision corresponding to a tag::
3795
3800
3796 hg id -n -r 1.3
3801 hg id -n -r 1.3
3797
3802
3798 - check the most recent revision of a remote repository::
3803 - check the most recent revision of a remote repository::
3799
3804
3800 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3805 hg id -r tip https://www.mercurial-scm.org/repo/hg/
3801
3806
3802 See :hg:`log` for generating more information about specific revisions,
3807 See :hg:`log` for generating more information about specific revisions,
3803 including full hash identifiers.
3808 including full hash identifiers.
3804
3809
3805 Returns 0 if successful.
3810 Returns 0 if successful.
3806 """
3811 """
3807
3812
3808 opts = pycompat.byteskwargs(opts)
3813 opts = pycompat.byteskwargs(opts)
3809 if not repo and not source:
3814 if not repo and not source:
3810 raise error.InputError(
3815 raise error.InputError(
3811 _(b"there is no Mercurial repository here (.hg not found)")
3816 _(b"there is no Mercurial repository here (.hg not found)")
3812 )
3817 )
3813
3818
3814 default = not (num or id or branch or tags or bookmarks)
3819 default = not (num or id or branch or tags or bookmarks)
3815 output = []
3820 output = []
3816 revs = []
3821 revs = []
3817
3822
3818 if source:
3823 if source:
3819 source, branches = hg.parseurl(ui.expandpath(source))
3824 source, branches = hg.parseurl(ui.expandpath(source))
3820 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3825 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3821 repo = peer.local()
3826 repo = peer.local()
3822 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3827 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3823
3828
3824 fm = ui.formatter(b'identify', opts)
3829 fm = ui.formatter(b'identify', opts)
3825 fm.startitem()
3830 fm.startitem()
3826
3831
3827 if not repo:
3832 if not repo:
3828 if num or branch or tags:
3833 if num or branch or tags:
3829 raise error.InputError(
3834 raise error.InputError(
3830 _(b"can't query remote revision number, branch, or tags")
3835 _(b"can't query remote revision number, branch, or tags")
3831 )
3836 )
3832 if not rev and revs:
3837 if not rev and revs:
3833 rev = revs[0]
3838 rev = revs[0]
3834 if not rev:
3839 if not rev:
3835 rev = b"tip"
3840 rev = b"tip"
3836
3841
3837 remoterev = peer.lookup(rev)
3842 remoterev = peer.lookup(rev)
3838 hexrev = fm.hexfunc(remoterev)
3843 hexrev = fm.hexfunc(remoterev)
3839 if default or id:
3844 if default or id:
3840 output = [hexrev]
3845 output = [hexrev]
3841 fm.data(id=hexrev)
3846 fm.data(id=hexrev)
3842
3847
3843 @util.cachefunc
3848 @util.cachefunc
3844 def getbms():
3849 def getbms():
3845 bms = []
3850 bms = []
3846
3851
3847 if b'bookmarks' in peer.listkeys(b'namespaces'):
3852 if b'bookmarks' in peer.listkeys(b'namespaces'):
3848 hexremoterev = hex(remoterev)
3853 hexremoterev = hex(remoterev)
3849 bms = [
3854 bms = [
3850 bm
3855 bm
3851 for bm, bmr in pycompat.iteritems(
3856 for bm, bmr in pycompat.iteritems(
3852 peer.listkeys(b'bookmarks')
3857 peer.listkeys(b'bookmarks')
3853 )
3858 )
3854 if bmr == hexremoterev
3859 if bmr == hexremoterev
3855 ]
3860 ]
3856
3861
3857 return sorted(bms)
3862 return sorted(bms)
3858
3863
3859 if fm.isplain():
3864 if fm.isplain():
3860 if bookmarks:
3865 if bookmarks:
3861 output.extend(getbms())
3866 output.extend(getbms())
3862 elif default and not ui.quiet:
3867 elif default and not ui.quiet:
3863 # multiple bookmarks for a single parent separated by '/'
3868 # multiple bookmarks for a single parent separated by '/'
3864 bm = b'/'.join(getbms())
3869 bm = b'/'.join(getbms())
3865 if bm:
3870 if bm:
3866 output.append(bm)
3871 output.append(bm)
3867 else:
3872 else:
3868 fm.data(node=hex(remoterev))
3873 fm.data(node=hex(remoterev))
3869 if bookmarks or b'bookmarks' in fm.datahint():
3874 if bookmarks or b'bookmarks' in fm.datahint():
3870 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3875 fm.data(bookmarks=fm.formatlist(getbms(), name=b'bookmark'))
3871 else:
3876 else:
3872 if rev:
3877 if rev:
3873 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3878 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
3874 ctx = scmutil.revsingle(repo, rev, None)
3879 ctx = scmutil.revsingle(repo, rev, None)
3875
3880
3876 if ctx.rev() is None:
3881 if ctx.rev() is None:
3877 ctx = repo[None]
3882 ctx = repo[None]
3878 parents = ctx.parents()
3883 parents = ctx.parents()
3879 taglist = []
3884 taglist = []
3880 for p in parents:
3885 for p in parents:
3881 taglist.extend(p.tags())
3886 taglist.extend(p.tags())
3882
3887
3883 dirty = b""
3888 dirty = b""
3884 if ctx.dirty(missing=True, merge=False, branch=False):
3889 if ctx.dirty(missing=True, merge=False, branch=False):
3885 dirty = b'+'
3890 dirty = b'+'
3886 fm.data(dirty=dirty)
3891 fm.data(dirty=dirty)
3887
3892
3888 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3893 hexoutput = [fm.hexfunc(p.node()) for p in parents]
3889 if default or id:
3894 if default or id:
3890 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3895 output = [b"%s%s" % (b'+'.join(hexoutput), dirty)]
3891 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3896 fm.data(id=b"%s%s" % (b'+'.join(hexoutput), dirty))
3892
3897
3893 if num:
3898 if num:
3894 numoutput = [b"%d" % p.rev() for p in parents]
3899 numoutput = [b"%d" % p.rev() for p in parents]
3895 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3900 output.append(b"%s%s" % (b'+'.join(numoutput), dirty))
3896
3901
3897 fm.data(
3902 fm.data(
3898 parents=fm.formatlist(
3903 parents=fm.formatlist(
3899 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3904 [fm.hexfunc(p.node()) for p in parents], name=b'node'
3900 )
3905 )
3901 )
3906 )
3902 else:
3907 else:
3903 hexoutput = fm.hexfunc(ctx.node())
3908 hexoutput = fm.hexfunc(ctx.node())
3904 if default or id:
3909 if default or id:
3905 output = [hexoutput]
3910 output = [hexoutput]
3906 fm.data(id=hexoutput)
3911 fm.data(id=hexoutput)
3907
3912
3908 if num:
3913 if num:
3909 output.append(pycompat.bytestr(ctx.rev()))
3914 output.append(pycompat.bytestr(ctx.rev()))
3910 taglist = ctx.tags()
3915 taglist = ctx.tags()
3911
3916
3912 if default and not ui.quiet:
3917 if default and not ui.quiet:
3913 b = ctx.branch()
3918 b = ctx.branch()
3914 if b != b'default':
3919 if b != b'default':
3915 output.append(b"(%s)" % b)
3920 output.append(b"(%s)" % b)
3916
3921
3917 # multiple tags for a single parent separated by '/'
3922 # multiple tags for a single parent separated by '/'
3918 t = b'/'.join(taglist)
3923 t = b'/'.join(taglist)
3919 if t:
3924 if t:
3920 output.append(t)
3925 output.append(t)
3921
3926
3922 # multiple bookmarks for a single parent separated by '/'
3927 # multiple bookmarks for a single parent separated by '/'
3923 bm = b'/'.join(ctx.bookmarks())
3928 bm = b'/'.join(ctx.bookmarks())
3924 if bm:
3929 if bm:
3925 output.append(bm)
3930 output.append(bm)
3926 else:
3931 else:
3927 if branch:
3932 if branch:
3928 output.append(ctx.branch())
3933 output.append(ctx.branch())
3929
3934
3930 if tags:
3935 if tags:
3931 output.extend(taglist)
3936 output.extend(taglist)
3932
3937
3933 if bookmarks:
3938 if bookmarks:
3934 output.extend(ctx.bookmarks())
3939 output.extend(ctx.bookmarks())
3935
3940
3936 fm.data(node=ctx.hex())
3941 fm.data(node=ctx.hex())
3937 fm.data(branch=ctx.branch())
3942 fm.data(branch=ctx.branch())
3938 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3943 fm.data(tags=fm.formatlist(taglist, name=b'tag', sep=b':'))
3939 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3944 fm.data(bookmarks=fm.formatlist(ctx.bookmarks(), name=b'bookmark'))
3940 fm.context(ctx=ctx)
3945 fm.context(ctx=ctx)
3941
3946
3942 fm.plain(b"%s\n" % b' '.join(output))
3947 fm.plain(b"%s\n" % b' '.join(output))
3943 fm.end()
3948 fm.end()
3944
3949
3945
3950
3946 @command(
3951 @command(
3947 b'import|patch',
3952 b'import|patch',
3948 [
3953 [
3949 (
3954 (
3950 b'p',
3955 b'p',
3951 b'strip',
3956 b'strip',
3952 1,
3957 1,
3953 _(
3958 _(
3954 b'directory strip option for patch. This has the same '
3959 b'directory strip option for patch. This has the same '
3955 b'meaning as the corresponding patch option'
3960 b'meaning as the corresponding patch option'
3956 ),
3961 ),
3957 _(b'NUM'),
3962 _(b'NUM'),
3958 ),
3963 ),
3959 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3964 (b'b', b'base', b'', _(b'base path (DEPRECATED)'), _(b'PATH')),
3960 (b'', b'secret', None, _(b'use the secret phase for committing')),
3965 (b'', b'secret', None, _(b'use the secret phase for committing')),
3961 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3966 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
3962 (
3967 (
3963 b'f',
3968 b'f',
3964 b'force',
3969 b'force',
3965 None,
3970 None,
3966 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3971 _(b'skip check for outstanding uncommitted changes (DEPRECATED)'),
3967 ),
3972 ),
3968 (
3973 (
3969 b'',
3974 b'',
3970 b'no-commit',
3975 b'no-commit',
3971 None,
3976 None,
3972 _(b"don't commit, just update the working directory"),
3977 _(b"don't commit, just update the working directory"),
3973 ),
3978 ),
3974 (
3979 (
3975 b'',
3980 b'',
3976 b'bypass',
3981 b'bypass',
3977 None,
3982 None,
3978 _(b"apply patch without touching the working directory"),
3983 _(b"apply patch without touching the working directory"),
3979 ),
3984 ),
3980 (b'', b'partial', None, _(b'commit even if some hunks fail')),
3985 (b'', b'partial', None, _(b'commit even if some hunks fail')),
3981 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
3986 (b'', b'exact', None, _(b'abort if patch would apply lossily')),
3982 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
3987 (b'', b'prefix', b'', _(b'apply patch to subdirectory'), _(b'DIR')),
3983 (
3988 (
3984 b'',
3989 b'',
3985 b'import-branch',
3990 b'import-branch',
3986 None,
3991 None,
3987 _(b'use any branch information in patch (implied by --exact)'),
3992 _(b'use any branch information in patch (implied by --exact)'),
3988 ),
3993 ),
3989 ]
3994 ]
3990 + commitopts
3995 + commitopts
3991 + commitopts2
3996 + commitopts2
3992 + similarityopts,
3997 + similarityopts,
3993 _(b'[OPTION]... PATCH...'),
3998 _(b'[OPTION]... PATCH...'),
3994 helpcategory=command.CATEGORY_IMPORT_EXPORT,
3999 helpcategory=command.CATEGORY_IMPORT_EXPORT,
3995 )
4000 )
3996 def import_(ui, repo, patch1=None, *patches, **opts):
4001 def import_(ui, repo, patch1=None, *patches, **opts):
3997 """import an ordered set of patches
4002 """import an ordered set of patches
3998
4003
3999 Import a list of patches and commit them individually (unless
4004 Import a list of patches and commit them individually (unless
4000 --no-commit is specified).
4005 --no-commit is specified).
4001
4006
4002 To read a patch from standard input (stdin), use "-" as the patch
4007 To read a patch from standard input (stdin), use "-" as the patch
4003 name. If a URL is specified, the patch will be downloaded from
4008 name. If a URL is specified, the patch will be downloaded from
4004 there.
4009 there.
4005
4010
4006 Import first applies changes to the working directory (unless
4011 Import first applies changes to the working directory (unless
4007 --bypass is specified), import will abort if there are outstanding
4012 --bypass is specified), import will abort if there are outstanding
4008 changes.
4013 changes.
4009
4014
4010 Use --bypass to apply and commit patches directly to the
4015 Use --bypass to apply and commit patches directly to the
4011 repository, without affecting the working directory. Without
4016 repository, without affecting the working directory. Without
4012 --exact, patches will be applied on top of the working directory
4017 --exact, patches will be applied on top of the working directory
4013 parent revision.
4018 parent revision.
4014
4019
4015 You can import a patch straight from a mail message. Even patches
4020 You can import a patch straight from a mail message. Even patches
4016 as attachments work (to use the body part, it must have type
4021 as attachments work (to use the body part, it must have type
4017 text/plain or text/x-patch). From and Subject headers of email
4022 text/plain or text/x-patch). From and Subject headers of email
4018 message are used as default committer and commit message. All
4023 message are used as default committer and commit message. All
4019 text/plain body parts before first diff are added to the commit
4024 text/plain body parts before first diff are added to the commit
4020 message.
4025 message.
4021
4026
4022 If the imported patch was generated by :hg:`export`, user and
4027 If the imported patch was generated by :hg:`export`, user and
4023 description from patch override values from message headers and
4028 description from patch override values from message headers and
4024 body. Values given on command line with -m/--message and -u/--user
4029 body. Values given on command line with -m/--message and -u/--user
4025 override these.
4030 override these.
4026
4031
4027 If --exact is specified, import will set the working directory to
4032 If --exact is specified, import will set the working directory to
4028 the parent of each patch before applying it, and will abort if the
4033 the parent of each patch before applying it, and will abort if the
4029 resulting changeset has a different ID than the one recorded in
4034 resulting changeset has a different ID than the one recorded in
4030 the patch. This will guard against various ways that portable
4035 the patch. This will guard against various ways that portable
4031 patch formats and mail systems might fail to transfer Mercurial
4036 patch formats and mail systems might fail to transfer Mercurial
4032 data or metadata. See :hg:`bundle` for lossless transmission.
4037 data or metadata. See :hg:`bundle` for lossless transmission.
4033
4038
4034 Use --partial to ensure a changeset will be created from the patch
4039 Use --partial to ensure a changeset will be created from the patch
4035 even if some hunks fail to apply. Hunks that fail to apply will be
4040 even if some hunks fail to apply. Hunks that fail to apply will be
4036 written to a <target-file>.rej file. Conflicts can then be resolved
4041 written to a <target-file>.rej file. Conflicts can then be resolved
4037 by hand before :hg:`commit --amend` is run to update the created
4042 by hand before :hg:`commit --amend` is run to update the created
4038 changeset. This flag exists to let people import patches that
4043 changeset. This flag exists to let people import patches that
4039 partially apply without losing the associated metadata (author,
4044 partially apply without losing the associated metadata (author,
4040 date, description, ...).
4045 date, description, ...).
4041
4046
4042 .. note::
4047 .. note::
4043
4048
4044 When no hunks apply cleanly, :hg:`import --partial` will create
4049 When no hunks apply cleanly, :hg:`import --partial` will create
4045 an empty changeset, importing only the patch metadata.
4050 an empty changeset, importing only the patch metadata.
4046
4051
4047 With -s/--similarity, hg will attempt to discover renames and
4052 With -s/--similarity, hg will attempt to discover renames and
4048 copies in the patch in the same way as :hg:`addremove`.
4053 copies in the patch in the same way as :hg:`addremove`.
4049
4054
4050 It is possible to use external patch programs to perform the patch
4055 It is possible to use external patch programs to perform the patch
4051 by setting the ``ui.patch`` configuration option. For the default
4056 by setting the ``ui.patch`` configuration option. For the default
4052 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4057 internal tool, the fuzz can also be configured via ``patch.fuzz``.
4053 See :hg:`help config` for more information about configuration
4058 See :hg:`help config` for more information about configuration
4054 files and how to use these options.
4059 files and how to use these options.
4055
4060
4056 See :hg:`help dates` for a list of formats valid for -d/--date.
4061 See :hg:`help dates` for a list of formats valid for -d/--date.
4057
4062
4058 .. container:: verbose
4063 .. container:: verbose
4059
4064
4060 Examples:
4065 Examples:
4061
4066
4062 - import a traditional patch from a website and detect renames::
4067 - import a traditional patch from a website and detect renames::
4063
4068
4064 hg import -s 80 http://example.com/bugfix.patch
4069 hg import -s 80 http://example.com/bugfix.patch
4065
4070
4066 - import a changeset from an hgweb server::
4071 - import a changeset from an hgweb server::
4067
4072
4068 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4073 hg import https://www.mercurial-scm.org/repo/hg/rev/5ca8c111e9aa
4069
4074
4070 - import all the patches in an Unix-style mbox::
4075 - import all the patches in an Unix-style mbox::
4071
4076
4072 hg import incoming-patches.mbox
4077 hg import incoming-patches.mbox
4073
4078
4074 - import patches from stdin::
4079 - import patches from stdin::
4075
4080
4076 hg import -
4081 hg import -
4077
4082
4078 - attempt to exactly restore an exported changeset (not always
4083 - attempt to exactly restore an exported changeset (not always
4079 possible)::
4084 possible)::
4080
4085
4081 hg import --exact proposed-fix.patch
4086 hg import --exact proposed-fix.patch
4082
4087
4083 - use an external tool to apply a patch which is too fuzzy for
4088 - use an external tool to apply a patch which is too fuzzy for
4084 the default internal tool.
4089 the default internal tool.
4085
4090
4086 hg import --config ui.patch="patch --merge" fuzzy.patch
4091 hg import --config ui.patch="patch --merge" fuzzy.patch
4087
4092
4088 - change the default fuzzing from 2 to a less strict 7
4093 - change the default fuzzing from 2 to a less strict 7
4089
4094
4090 hg import --config ui.fuzz=7 fuzz.patch
4095 hg import --config ui.fuzz=7 fuzz.patch
4091
4096
4092 Returns 0 on success, 1 on partial success (see --partial).
4097 Returns 0 on success, 1 on partial success (see --partial).
4093 """
4098 """
4094
4099
4095 cmdutil.check_incompatible_arguments(
4100 cmdutil.check_incompatible_arguments(
4096 opts, 'no_commit', ['bypass', 'secret']
4101 opts, 'no_commit', ['bypass', 'secret']
4097 )
4102 )
4098 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4103 cmdutil.check_incompatible_arguments(opts, 'exact', ['edit', 'prefix'])
4099 opts = pycompat.byteskwargs(opts)
4104 opts = pycompat.byteskwargs(opts)
4100 if not patch1:
4105 if not patch1:
4101 raise error.InputError(_(b'need at least one patch to import'))
4106 raise error.InputError(_(b'need at least one patch to import'))
4102
4107
4103 patches = (patch1,) + patches
4108 patches = (patch1,) + patches
4104
4109
4105 date = opts.get(b'date')
4110 date = opts.get(b'date')
4106 if date:
4111 if date:
4107 opts[b'date'] = dateutil.parsedate(date)
4112 opts[b'date'] = dateutil.parsedate(date)
4108
4113
4109 exact = opts.get(b'exact')
4114 exact = opts.get(b'exact')
4110 update = not opts.get(b'bypass')
4115 update = not opts.get(b'bypass')
4111 try:
4116 try:
4112 sim = float(opts.get(b'similarity') or 0)
4117 sim = float(opts.get(b'similarity') or 0)
4113 except ValueError:
4118 except ValueError:
4114 raise error.InputError(_(b'similarity must be a number'))
4119 raise error.InputError(_(b'similarity must be a number'))
4115 if sim < 0 or sim > 100:
4120 if sim < 0 or sim > 100:
4116 raise error.InputError(_(b'similarity must be between 0 and 100'))
4121 raise error.InputError(_(b'similarity must be between 0 and 100'))
4117 if sim and not update:
4122 if sim and not update:
4118 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4123 raise error.InputError(_(b'cannot use --similarity with --bypass'))
4119
4124
4120 base = opts[b"base"]
4125 base = opts[b"base"]
4121 msgs = []
4126 msgs = []
4122 ret = 0
4127 ret = 0
4123
4128
4124 with repo.wlock():
4129 with repo.wlock():
4125 if update:
4130 if update:
4126 cmdutil.checkunfinished(repo)
4131 cmdutil.checkunfinished(repo)
4127 if exact or not opts.get(b'force'):
4132 if exact or not opts.get(b'force'):
4128 cmdutil.bailifchanged(repo)
4133 cmdutil.bailifchanged(repo)
4129
4134
4130 if not opts.get(b'no_commit'):
4135 if not opts.get(b'no_commit'):
4131 lock = repo.lock
4136 lock = repo.lock
4132 tr = lambda: repo.transaction(b'import')
4137 tr = lambda: repo.transaction(b'import')
4133 dsguard = util.nullcontextmanager
4138 dsguard = util.nullcontextmanager
4134 else:
4139 else:
4135 lock = util.nullcontextmanager
4140 lock = util.nullcontextmanager
4136 tr = util.nullcontextmanager
4141 tr = util.nullcontextmanager
4137 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4142 dsguard = lambda: dirstateguard.dirstateguard(repo, b'import')
4138 with lock(), tr(), dsguard():
4143 with lock(), tr(), dsguard():
4139 parents = repo[None].parents()
4144 parents = repo[None].parents()
4140 for patchurl in patches:
4145 for patchurl in patches:
4141 if patchurl == b'-':
4146 if patchurl == b'-':
4142 ui.status(_(b'applying patch from stdin\n'))
4147 ui.status(_(b'applying patch from stdin\n'))
4143 patchfile = ui.fin
4148 patchfile = ui.fin
4144 patchurl = b'stdin' # for error message
4149 patchurl = b'stdin' # for error message
4145 else:
4150 else:
4146 patchurl = os.path.join(base, patchurl)
4151 patchurl = os.path.join(base, patchurl)
4147 ui.status(_(b'applying %s\n') % patchurl)
4152 ui.status(_(b'applying %s\n') % patchurl)
4148 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4153 patchfile = hg.openpath(ui, patchurl, sendaccept=False)
4149
4154
4150 haspatch = False
4155 haspatch = False
4151 for hunk in patch.split(patchfile):
4156 for hunk in patch.split(patchfile):
4152 with patch.extract(ui, hunk) as patchdata:
4157 with patch.extract(ui, hunk) as patchdata:
4153 msg, node, rej = cmdutil.tryimportone(
4158 msg, node, rej = cmdutil.tryimportone(
4154 ui, repo, patchdata, parents, opts, msgs, hg.clean
4159 ui, repo, patchdata, parents, opts, msgs, hg.clean
4155 )
4160 )
4156 if msg:
4161 if msg:
4157 haspatch = True
4162 haspatch = True
4158 ui.note(msg + b'\n')
4163 ui.note(msg + b'\n')
4159 if update or exact:
4164 if update or exact:
4160 parents = repo[None].parents()
4165 parents = repo[None].parents()
4161 else:
4166 else:
4162 parents = [repo[node]]
4167 parents = [repo[node]]
4163 if rej:
4168 if rej:
4164 ui.write_err(_(b"patch applied partially\n"))
4169 ui.write_err(_(b"patch applied partially\n"))
4165 ui.write_err(
4170 ui.write_err(
4166 _(
4171 _(
4167 b"(fix the .rej files and run "
4172 b"(fix the .rej files and run "
4168 b"`hg commit --amend`)\n"
4173 b"`hg commit --amend`)\n"
4169 )
4174 )
4170 )
4175 )
4171 ret = 1
4176 ret = 1
4172 break
4177 break
4173
4178
4174 if not haspatch:
4179 if not haspatch:
4175 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4180 raise error.InputError(_(b'%s: no diffs found') % patchurl)
4176
4181
4177 if msgs:
4182 if msgs:
4178 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4183 repo.savecommitmessage(b'\n* * *\n'.join(msgs))
4179 return ret
4184 return ret
4180
4185
4181
4186
4182 @command(
4187 @command(
4183 b'incoming|in',
4188 b'incoming|in',
4184 [
4189 [
4185 (
4190 (
4186 b'f',
4191 b'f',
4187 b'force',
4192 b'force',
4188 None,
4193 None,
4189 _(b'run even if remote repository is unrelated'),
4194 _(b'run even if remote repository is unrelated'),
4190 ),
4195 ),
4191 (b'n', b'newest-first', None, _(b'show newest record first')),
4196 (b'n', b'newest-first', None, _(b'show newest record first')),
4192 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4197 (b'', b'bundle', b'', _(b'file to store the bundles into'), _(b'FILE')),
4193 (
4198 (
4194 b'r',
4199 b'r',
4195 b'rev',
4200 b'rev',
4196 [],
4201 [],
4197 _(b'a remote changeset intended to be added'),
4202 _(b'a remote changeset intended to be added'),
4198 _(b'REV'),
4203 _(b'REV'),
4199 ),
4204 ),
4200 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4205 (b'B', b'bookmarks', False, _(b"compare bookmarks")),
4201 (
4206 (
4202 b'b',
4207 b'b',
4203 b'branch',
4208 b'branch',
4204 [],
4209 [],
4205 _(b'a specific branch you would like to pull'),
4210 _(b'a specific branch you would like to pull'),
4206 _(b'BRANCH'),
4211 _(b'BRANCH'),
4207 ),
4212 ),
4208 ]
4213 ]
4209 + logopts
4214 + logopts
4210 + remoteopts
4215 + remoteopts
4211 + subrepoopts,
4216 + subrepoopts,
4212 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4217 _(b'[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'),
4213 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4218 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4214 )
4219 )
4215 def incoming(ui, repo, source=b"default", **opts):
4220 def incoming(ui, repo, source=b"default", **opts):
4216 """show new changesets found in source
4221 """show new changesets found in source
4217
4222
4218 Show new changesets found in the specified path/URL or the default
4223 Show new changesets found in the specified path/URL or the default
4219 pull location. These are the changesets that would have been pulled
4224 pull location. These are the changesets that would have been pulled
4220 by :hg:`pull` at the time you issued this command.
4225 by :hg:`pull` at the time you issued this command.
4221
4226
4222 See pull for valid source format details.
4227 See pull for valid source format details.
4223
4228
4224 .. container:: verbose
4229 .. container:: verbose
4225
4230
4226 With -B/--bookmarks, the result of bookmark comparison between
4231 With -B/--bookmarks, the result of bookmark comparison between
4227 local and remote repositories is displayed. With -v/--verbose,
4232 local and remote repositories is displayed. With -v/--verbose,
4228 status is also displayed for each bookmark like below::
4233 status is also displayed for each bookmark like below::
4229
4234
4230 BM1 01234567890a added
4235 BM1 01234567890a added
4231 BM2 1234567890ab advanced
4236 BM2 1234567890ab advanced
4232 BM3 234567890abc diverged
4237 BM3 234567890abc diverged
4233 BM4 34567890abcd changed
4238 BM4 34567890abcd changed
4234
4239
4235 The action taken locally when pulling depends on the
4240 The action taken locally when pulling depends on the
4236 status of each bookmark:
4241 status of each bookmark:
4237
4242
4238 :``added``: pull will create it
4243 :``added``: pull will create it
4239 :``advanced``: pull will update it
4244 :``advanced``: pull will update it
4240 :``diverged``: pull will create a divergent bookmark
4245 :``diverged``: pull will create a divergent bookmark
4241 :``changed``: result depends on remote changesets
4246 :``changed``: result depends on remote changesets
4242
4247
4243 From the point of view of pulling behavior, bookmark
4248 From the point of view of pulling behavior, bookmark
4244 existing only in the remote repository are treated as ``added``,
4249 existing only in the remote repository are treated as ``added``,
4245 even if it is in fact locally deleted.
4250 even if it is in fact locally deleted.
4246
4251
4247 .. container:: verbose
4252 .. container:: verbose
4248
4253
4249 For remote repository, using --bundle avoids downloading the
4254 For remote repository, using --bundle avoids downloading the
4250 changesets twice if the incoming is followed by a pull.
4255 changesets twice if the incoming is followed by a pull.
4251
4256
4252 Examples:
4257 Examples:
4253
4258
4254 - show incoming changes with patches and full description::
4259 - show incoming changes with patches and full description::
4255
4260
4256 hg incoming -vp
4261 hg incoming -vp
4257
4262
4258 - show incoming changes excluding merges, store a bundle::
4263 - show incoming changes excluding merges, store a bundle::
4259
4264
4260 hg in -vpM --bundle incoming.hg
4265 hg in -vpM --bundle incoming.hg
4261 hg pull incoming.hg
4266 hg pull incoming.hg
4262
4267
4263 - briefly list changes inside a bundle::
4268 - briefly list changes inside a bundle::
4264
4269
4265 hg in changes.hg -T "{desc|firstline}\\n"
4270 hg in changes.hg -T "{desc|firstline}\\n"
4266
4271
4267 Returns 0 if there are incoming changes, 1 otherwise.
4272 Returns 0 if there are incoming changes, 1 otherwise.
4268 """
4273 """
4269 opts = pycompat.byteskwargs(opts)
4274 opts = pycompat.byteskwargs(opts)
4270 if opts.get(b'graph'):
4275 if opts.get(b'graph'):
4271 logcmdutil.checkunsupportedgraphflags([], opts)
4276 logcmdutil.checkunsupportedgraphflags([], opts)
4272
4277
4273 def display(other, chlist, displayer):
4278 def display(other, chlist, displayer):
4274 revdag = logcmdutil.graphrevs(other, chlist, opts)
4279 revdag = logcmdutil.graphrevs(other, chlist, opts)
4275 logcmdutil.displaygraph(
4280 logcmdutil.displaygraph(
4276 ui, repo, revdag, displayer, graphmod.asciiedges
4281 ui, repo, revdag, displayer, graphmod.asciiedges
4277 )
4282 )
4278
4283
4279 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4284 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4280 return 0
4285 return 0
4281
4286
4282 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4287 cmdutil.check_incompatible_arguments(opts, b'subrepos', [b'bundle'])
4283
4288
4284 if opts.get(b'bookmarks'):
4289 if opts.get(b'bookmarks'):
4285 source, branches = hg.parseurl(
4290 source, branches = hg.parseurl(
4286 ui.expandpath(source), opts.get(b'branch')
4291 ui.expandpath(source), opts.get(b'branch')
4287 )
4292 )
4288 other = hg.peer(repo, opts, source)
4293 other = hg.peer(repo, opts, source)
4289 if b'bookmarks' not in other.listkeys(b'namespaces'):
4294 if b'bookmarks' not in other.listkeys(b'namespaces'):
4290 ui.warn(_(b"remote doesn't support bookmarks\n"))
4295 ui.warn(_(b"remote doesn't support bookmarks\n"))
4291 return 0
4296 return 0
4292 ui.pager(b'incoming')
4297 ui.pager(b'incoming')
4293 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4298 ui.status(_(b'comparing with %s\n') % util.hidepassword(source))
4294 return bookmarks.incoming(ui, repo, other)
4299 return bookmarks.incoming(ui, repo, other)
4295
4300
4296 repo._subtoppath = ui.expandpath(source)
4301 repo._subtoppath = ui.expandpath(source)
4297 try:
4302 try:
4298 return hg.incoming(ui, repo, source, opts)
4303 return hg.incoming(ui, repo, source, opts)
4299 finally:
4304 finally:
4300 del repo._subtoppath
4305 del repo._subtoppath
4301
4306
4302
4307
4303 @command(
4308 @command(
4304 b'init',
4309 b'init',
4305 remoteopts,
4310 remoteopts,
4306 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4311 _(b'[-e CMD] [--remotecmd CMD] [DEST]'),
4307 helpcategory=command.CATEGORY_REPO_CREATION,
4312 helpcategory=command.CATEGORY_REPO_CREATION,
4308 helpbasic=True,
4313 helpbasic=True,
4309 norepo=True,
4314 norepo=True,
4310 )
4315 )
4311 def init(ui, dest=b".", **opts):
4316 def init(ui, dest=b".", **opts):
4312 """create a new repository in the given directory
4317 """create a new repository in the given directory
4313
4318
4314 Initialize a new repository in the given directory. If the given
4319 Initialize a new repository in the given directory. If the given
4315 directory does not exist, it will be created.
4320 directory does not exist, it will be created.
4316
4321
4317 If no directory is given, the current directory is used.
4322 If no directory is given, the current directory is used.
4318
4323
4319 It is possible to specify an ``ssh://`` URL as the destination.
4324 It is possible to specify an ``ssh://`` URL as the destination.
4320 See :hg:`help urls` for more information.
4325 See :hg:`help urls` for more information.
4321
4326
4322 Returns 0 on success.
4327 Returns 0 on success.
4323 """
4328 """
4324 opts = pycompat.byteskwargs(opts)
4329 opts = pycompat.byteskwargs(opts)
4325 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4330 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4326
4331
4327
4332
4328 @command(
4333 @command(
4329 b'locate',
4334 b'locate',
4330 [
4335 [
4331 (
4336 (
4332 b'r',
4337 b'r',
4333 b'rev',
4338 b'rev',
4334 b'',
4339 b'',
4335 _(b'search the repository as it is in REV'),
4340 _(b'search the repository as it is in REV'),
4336 _(b'REV'),
4341 _(b'REV'),
4337 ),
4342 ),
4338 (
4343 (
4339 b'0',
4344 b'0',
4340 b'print0',
4345 b'print0',
4341 None,
4346 None,
4342 _(b'end filenames with NUL, for use with xargs'),
4347 _(b'end filenames with NUL, for use with xargs'),
4343 ),
4348 ),
4344 (
4349 (
4345 b'f',
4350 b'f',
4346 b'fullpath',
4351 b'fullpath',
4347 None,
4352 None,
4348 _(b'print complete paths from the filesystem root'),
4353 _(b'print complete paths from the filesystem root'),
4349 ),
4354 ),
4350 ]
4355 ]
4351 + walkopts,
4356 + walkopts,
4352 _(b'[OPTION]... [PATTERN]...'),
4357 _(b'[OPTION]... [PATTERN]...'),
4353 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4358 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
4354 )
4359 )
4355 def locate(ui, repo, *pats, **opts):
4360 def locate(ui, repo, *pats, **opts):
4356 """locate files matching specific patterns (DEPRECATED)
4361 """locate files matching specific patterns (DEPRECATED)
4357
4362
4358 Print files under Mercurial control in the working directory whose
4363 Print files under Mercurial control in the working directory whose
4359 names match the given patterns.
4364 names match the given patterns.
4360
4365
4361 By default, this command searches all directories in the working
4366 By default, this command searches all directories in the working
4362 directory. To search just the current directory and its
4367 directory. To search just the current directory and its
4363 subdirectories, use "--include .".
4368 subdirectories, use "--include .".
4364
4369
4365 If no patterns are given to match, this command prints the names
4370 If no patterns are given to match, this command prints the names
4366 of all files under Mercurial control in the working directory.
4371 of all files under Mercurial control in the working directory.
4367
4372
4368 If you want to feed the output of this command into the "xargs"
4373 If you want to feed the output of this command into the "xargs"
4369 command, use the -0 option to both this command and "xargs". This
4374 command, use the -0 option to both this command and "xargs". This
4370 will avoid the problem of "xargs" treating single filenames that
4375 will avoid the problem of "xargs" treating single filenames that
4371 contain whitespace as multiple filenames.
4376 contain whitespace as multiple filenames.
4372
4377
4373 See :hg:`help files` for a more versatile command.
4378 See :hg:`help files` for a more versatile command.
4374
4379
4375 Returns 0 if a match is found, 1 otherwise.
4380 Returns 0 if a match is found, 1 otherwise.
4376 """
4381 """
4377 opts = pycompat.byteskwargs(opts)
4382 opts = pycompat.byteskwargs(opts)
4378 if opts.get(b'print0'):
4383 if opts.get(b'print0'):
4379 end = b'\0'
4384 end = b'\0'
4380 else:
4385 else:
4381 end = b'\n'
4386 end = b'\n'
4382 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4387 ctx = scmutil.revsingle(repo, opts.get(b'rev'), None)
4383
4388
4384 ret = 1
4389 ret = 1
4385 m = scmutil.match(
4390 m = scmutil.match(
4386 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4391 ctx, pats, opts, default=b'relglob', badfn=lambda x, y: False
4387 )
4392 )
4388
4393
4389 ui.pager(b'locate')
4394 ui.pager(b'locate')
4390 if ctx.rev() is None:
4395 if ctx.rev() is None:
4391 # When run on the working copy, "locate" includes removed files, so
4396 # When run on the working copy, "locate" includes removed files, so
4392 # we get the list of files from the dirstate.
4397 # we get the list of files from the dirstate.
4393 filesgen = sorted(repo.dirstate.matches(m))
4398 filesgen = sorted(repo.dirstate.matches(m))
4394 else:
4399 else:
4395 filesgen = ctx.matches(m)
4400 filesgen = ctx.matches(m)
4396 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4401 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=bool(pats))
4397 for abs in filesgen:
4402 for abs in filesgen:
4398 if opts.get(b'fullpath'):
4403 if opts.get(b'fullpath'):
4399 ui.write(repo.wjoin(abs), end)
4404 ui.write(repo.wjoin(abs), end)
4400 else:
4405 else:
4401 ui.write(uipathfn(abs), end)
4406 ui.write(uipathfn(abs), end)
4402 ret = 0
4407 ret = 0
4403
4408
4404 return ret
4409 return ret
4405
4410
4406
4411
4407 @command(
4412 @command(
4408 b'log|history',
4413 b'log|history',
4409 [
4414 [
4410 (
4415 (
4411 b'f',
4416 b'f',
4412 b'follow',
4417 b'follow',
4413 None,
4418 None,
4414 _(
4419 _(
4415 b'follow changeset history, or file history across copies and renames'
4420 b'follow changeset history, or file history across copies and renames'
4416 ),
4421 ),
4417 ),
4422 ),
4418 (
4423 (
4419 b'',
4424 b'',
4420 b'follow-first',
4425 b'follow-first',
4421 None,
4426 None,
4422 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4427 _(b'only follow the first parent of merge changesets (DEPRECATED)'),
4423 ),
4428 ),
4424 (
4429 (
4425 b'd',
4430 b'd',
4426 b'date',
4431 b'date',
4427 b'',
4432 b'',
4428 _(b'show revisions matching date spec'),
4433 _(b'show revisions matching date spec'),
4429 _(b'DATE'),
4434 _(b'DATE'),
4430 ),
4435 ),
4431 (b'C', b'copies', None, _(b'show copied files')),
4436 (b'C', b'copies', None, _(b'show copied files')),
4432 (
4437 (
4433 b'k',
4438 b'k',
4434 b'keyword',
4439 b'keyword',
4435 [],
4440 [],
4436 _(b'do case-insensitive search for a given text'),
4441 _(b'do case-insensitive search for a given text'),
4437 _(b'TEXT'),
4442 _(b'TEXT'),
4438 ),
4443 ),
4439 (
4444 (
4440 b'r',
4445 b'r',
4441 b'rev',
4446 b'rev',
4442 [],
4447 [],
4443 _(b'show the specified revision or revset'),
4448 _(b'show the specified revision or revset'),
4444 _(b'REV'),
4449 _(b'REV'),
4445 ),
4450 ),
4446 (
4451 (
4447 b'L',
4452 b'L',
4448 b'line-range',
4453 b'line-range',
4449 [],
4454 [],
4450 _(b'follow line range of specified file (EXPERIMENTAL)'),
4455 _(b'follow line range of specified file (EXPERIMENTAL)'),
4451 _(b'FILE,RANGE'),
4456 _(b'FILE,RANGE'),
4452 ),
4457 ),
4453 (
4458 (
4454 b'',
4459 b'',
4455 b'removed',
4460 b'removed',
4456 None,
4461 None,
4457 _(b'include revisions where files were removed'),
4462 _(b'include revisions where files were removed'),
4458 ),
4463 ),
4459 (
4464 (
4460 b'm',
4465 b'm',
4461 b'only-merges',
4466 b'only-merges',
4462 None,
4467 None,
4463 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4468 _(b'show only merges (DEPRECATED) (use -r "merge()" instead)'),
4464 ),
4469 ),
4465 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4470 (b'u', b'user', [], _(b'revisions committed by user'), _(b'USER')),
4466 (
4471 (
4467 b'',
4472 b'',
4468 b'only-branch',
4473 b'only-branch',
4469 [],
4474 [],
4470 _(
4475 _(
4471 b'show only changesets within the given named branch (DEPRECATED)'
4476 b'show only changesets within the given named branch (DEPRECATED)'
4472 ),
4477 ),
4473 _(b'BRANCH'),
4478 _(b'BRANCH'),
4474 ),
4479 ),
4475 (
4480 (
4476 b'b',
4481 b'b',
4477 b'branch',
4482 b'branch',
4478 [],
4483 [],
4479 _(b'show changesets within the given named branch'),
4484 _(b'show changesets within the given named branch'),
4480 _(b'BRANCH'),
4485 _(b'BRANCH'),
4481 ),
4486 ),
4482 (
4487 (
4483 b'B',
4488 b'B',
4484 b'bookmark',
4489 b'bookmark',
4485 [],
4490 [],
4486 _(b"show changesets within the given bookmark"),
4491 _(b"show changesets within the given bookmark"),
4487 _(b'BOOKMARK'),
4492 _(b'BOOKMARK'),
4488 ),
4493 ),
4489 (
4494 (
4490 b'P',
4495 b'P',
4491 b'prune',
4496 b'prune',
4492 [],
4497 [],
4493 _(b'do not display revision or any of its ancestors'),
4498 _(b'do not display revision or any of its ancestors'),
4494 _(b'REV'),
4499 _(b'REV'),
4495 ),
4500 ),
4496 ]
4501 ]
4497 + logopts
4502 + logopts
4498 + walkopts,
4503 + walkopts,
4499 _(b'[OPTION]... [FILE]'),
4504 _(b'[OPTION]... [FILE]'),
4500 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4505 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4501 helpbasic=True,
4506 helpbasic=True,
4502 inferrepo=True,
4507 inferrepo=True,
4503 intents={INTENT_READONLY},
4508 intents={INTENT_READONLY},
4504 )
4509 )
4505 def log(ui, repo, *pats, **opts):
4510 def log(ui, repo, *pats, **opts):
4506 """show revision history of entire repository or files
4511 """show revision history of entire repository or files
4507
4512
4508 Print the revision history of the specified files or the entire
4513 Print the revision history of the specified files or the entire
4509 project.
4514 project.
4510
4515
4511 If no revision range is specified, the default is ``tip:0`` unless
4516 If no revision range is specified, the default is ``tip:0`` unless
4512 --follow is set, in which case the working directory parent is
4517 --follow is set, in which case the working directory parent is
4513 used as the starting revision.
4518 used as the starting revision.
4514
4519
4515 File history is shown without following rename or copy history of
4520 File history is shown without following rename or copy history of
4516 files. Use -f/--follow with a filename to follow history across
4521 files. Use -f/--follow with a filename to follow history across
4517 renames and copies. --follow without a filename will only show
4522 renames and copies. --follow without a filename will only show
4518 ancestors of the starting revision.
4523 ancestors of the starting revision.
4519
4524
4520 By default this command prints revision number and changeset id,
4525 By default this command prints revision number and changeset id,
4521 tags, non-trivial parents, user, date and time, and a summary for
4526 tags, non-trivial parents, user, date and time, and a summary for
4522 each commit. When the -v/--verbose switch is used, the list of
4527 each commit. When the -v/--verbose switch is used, the list of
4523 changed files and full commit message are shown.
4528 changed files and full commit message are shown.
4524
4529
4525 With --graph the revisions are shown as an ASCII art DAG with the most
4530 With --graph the revisions are shown as an ASCII art DAG with the most
4526 recent changeset at the top.
4531 recent changeset at the top.
4527 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4532 'o' is a changeset, '@' is a working directory parent, '%' is a changeset
4528 involved in an unresolved merge conflict, '_' closes a branch,
4533 involved in an unresolved merge conflict, '_' closes a branch,
4529 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4534 'x' is obsolete, '*' is unstable, and '+' represents a fork where the
4530 changeset from the lines below is a parent of the 'o' merge on the same
4535 changeset from the lines below is a parent of the 'o' merge on the same
4531 line.
4536 line.
4532 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4537 Paths in the DAG are represented with '|', '/' and so forth. ':' in place
4533 of a '|' indicates one or more revisions in a path are omitted.
4538 of a '|' indicates one or more revisions in a path are omitted.
4534
4539
4535 .. container:: verbose
4540 .. container:: verbose
4536
4541
4537 Use -L/--line-range FILE,M:N options to follow the history of lines
4542 Use -L/--line-range FILE,M:N options to follow the history of lines
4538 from M to N in FILE. With -p/--patch only diff hunks affecting
4543 from M to N in FILE. With -p/--patch only diff hunks affecting
4539 specified line range will be shown. This option requires --follow;
4544 specified line range will be shown. This option requires --follow;
4540 it can be specified multiple times. Currently, this option is not
4545 it can be specified multiple times. Currently, this option is not
4541 compatible with --graph. This option is experimental.
4546 compatible with --graph. This option is experimental.
4542
4547
4543 .. note::
4548 .. note::
4544
4549
4545 :hg:`log --patch` may generate unexpected diff output for merge
4550 :hg:`log --patch` may generate unexpected diff output for merge
4546 changesets, as it will only compare the merge changeset against
4551 changesets, as it will only compare the merge changeset against
4547 its first parent. Also, only files different from BOTH parents
4552 its first parent. Also, only files different from BOTH parents
4548 will appear in files:.
4553 will appear in files:.
4549
4554
4550 .. note::
4555 .. note::
4551
4556
4552 For performance reasons, :hg:`log FILE` may omit duplicate changes
4557 For performance reasons, :hg:`log FILE` may omit duplicate changes
4553 made on branches and will not show removals or mode changes. To
4558 made on branches and will not show removals or mode changes. To
4554 see all such changes, use the --removed switch.
4559 see all such changes, use the --removed switch.
4555
4560
4556 .. container:: verbose
4561 .. container:: verbose
4557
4562
4558 .. note::
4563 .. note::
4559
4564
4560 The history resulting from -L/--line-range options depends on diff
4565 The history resulting from -L/--line-range options depends on diff
4561 options; for instance if white-spaces are ignored, respective changes
4566 options; for instance if white-spaces are ignored, respective changes
4562 with only white-spaces in specified line range will not be listed.
4567 with only white-spaces in specified line range will not be listed.
4563
4568
4564 .. container:: verbose
4569 .. container:: verbose
4565
4570
4566 Some examples:
4571 Some examples:
4567
4572
4568 - changesets with full descriptions and file lists::
4573 - changesets with full descriptions and file lists::
4569
4574
4570 hg log -v
4575 hg log -v
4571
4576
4572 - changesets ancestral to the working directory::
4577 - changesets ancestral to the working directory::
4573
4578
4574 hg log -f
4579 hg log -f
4575
4580
4576 - last 10 commits on the current branch::
4581 - last 10 commits on the current branch::
4577
4582
4578 hg log -l 10 -b .
4583 hg log -l 10 -b .
4579
4584
4580 - changesets showing all modifications of a file, including removals::
4585 - changesets showing all modifications of a file, including removals::
4581
4586
4582 hg log --removed file.c
4587 hg log --removed file.c
4583
4588
4584 - all changesets that touch a directory, with diffs, excluding merges::
4589 - all changesets that touch a directory, with diffs, excluding merges::
4585
4590
4586 hg log -Mp lib/
4591 hg log -Mp lib/
4587
4592
4588 - all revision numbers that match a keyword::
4593 - all revision numbers that match a keyword::
4589
4594
4590 hg log -k bug --template "{rev}\\n"
4595 hg log -k bug --template "{rev}\\n"
4591
4596
4592 - the full hash identifier of the working directory parent::
4597 - the full hash identifier of the working directory parent::
4593
4598
4594 hg log -r . --template "{node}\\n"
4599 hg log -r . --template "{node}\\n"
4595
4600
4596 - list available log templates::
4601 - list available log templates::
4597
4602
4598 hg log -T list
4603 hg log -T list
4599
4604
4600 - check if a given changeset is included in a tagged release::
4605 - check if a given changeset is included in a tagged release::
4601
4606
4602 hg log -r "a21ccf and ancestor(1.9)"
4607 hg log -r "a21ccf and ancestor(1.9)"
4603
4608
4604 - find all changesets by some user in a date range::
4609 - find all changesets by some user in a date range::
4605
4610
4606 hg log -k alice -d "may 2008 to jul 2008"
4611 hg log -k alice -d "may 2008 to jul 2008"
4607
4612
4608 - summary of all changesets after the last tag::
4613 - summary of all changesets after the last tag::
4609
4614
4610 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4615 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4611
4616
4612 - changesets touching lines 13 to 23 for file.c::
4617 - changesets touching lines 13 to 23 for file.c::
4613
4618
4614 hg log -L file.c,13:23
4619 hg log -L file.c,13:23
4615
4620
4616 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4621 - changesets touching lines 13 to 23 for file.c and lines 2 to 6 of
4617 main.c with patch::
4622 main.c with patch::
4618
4623
4619 hg log -L file.c,13:23 -L main.c,2:6 -p
4624 hg log -L file.c,13:23 -L main.c,2:6 -p
4620
4625
4621 See :hg:`help dates` for a list of formats valid for -d/--date.
4626 See :hg:`help dates` for a list of formats valid for -d/--date.
4622
4627
4623 See :hg:`help revisions` for more about specifying and ordering
4628 See :hg:`help revisions` for more about specifying and ordering
4624 revisions.
4629 revisions.
4625
4630
4626 See :hg:`help templates` for more about pre-packaged styles and
4631 See :hg:`help templates` for more about pre-packaged styles and
4627 specifying custom templates. The default template used by the log
4632 specifying custom templates. The default template used by the log
4628 command can be customized via the ``command-templates.log`` configuration
4633 command can be customized via the ``command-templates.log`` configuration
4629 setting.
4634 setting.
4630
4635
4631 Returns 0 on success.
4636 Returns 0 on success.
4632
4637
4633 """
4638 """
4634 opts = pycompat.byteskwargs(opts)
4639 opts = pycompat.byteskwargs(opts)
4635 linerange = opts.get(b'line_range')
4640 linerange = opts.get(b'line_range')
4636
4641
4637 if linerange and not opts.get(b'follow'):
4642 if linerange and not opts.get(b'follow'):
4638 raise error.InputError(_(b'--line-range requires --follow'))
4643 raise error.InputError(_(b'--line-range requires --follow'))
4639
4644
4640 if linerange and pats:
4645 if linerange and pats:
4641 # TODO: take pats as patterns with no line-range filter
4646 # TODO: take pats as patterns with no line-range filter
4642 raise error.InputError(
4647 raise error.InputError(
4643 _(b'FILE arguments are not compatible with --line-range option')
4648 _(b'FILE arguments are not compatible with --line-range option')
4644 )
4649 )
4645
4650
4646 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4651 repo = scmutil.unhidehashlikerevs(repo, opts.get(b'rev'), b'nowarn')
4647 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4652 walk_opts = logcmdutil.parseopts(ui, pats, opts)
4648 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4653 revs, differ = logcmdutil.getrevs(repo, walk_opts)
4649 if linerange:
4654 if linerange:
4650 # TODO: should follow file history from logcmdutil._initialrevs(),
4655 # TODO: should follow file history from logcmdutil._initialrevs(),
4651 # then filter the result by logcmdutil._makerevset() and --limit
4656 # then filter the result by logcmdutil._makerevset() and --limit
4652 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4657 revs, differ = logcmdutil.getlinerangerevs(repo, revs, opts)
4653
4658
4654 getcopies = None
4659 getcopies = None
4655 if opts.get(b'copies'):
4660 if opts.get(b'copies'):
4656 endrev = None
4661 endrev = None
4657 if revs:
4662 if revs:
4658 endrev = revs.max() + 1
4663 endrev = revs.max() + 1
4659 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4664 getcopies = scmutil.getcopiesfn(repo, endrev=endrev)
4660
4665
4661 ui.pager(b'log')
4666 ui.pager(b'log')
4662 displayer = logcmdutil.changesetdisplayer(
4667 displayer = logcmdutil.changesetdisplayer(
4663 ui, repo, opts, differ, buffered=True
4668 ui, repo, opts, differ, buffered=True
4664 )
4669 )
4665 if opts.get(b'graph'):
4670 if opts.get(b'graph'):
4666 displayfn = logcmdutil.displaygraphrevs
4671 displayfn = logcmdutil.displaygraphrevs
4667 else:
4672 else:
4668 displayfn = logcmdutil.displayrevs
4673 displayfn = logcmdutil.displayrevs
4669 displayfn(ui, repo, revs, displayer, getcopies)
4674 displayfn(ui, repo, revs, displayer, getcopies)
4670
4675
4671
4676
4672 @command(
4677 @command(
4673 b'manifest',
4678 b'manifest',
4674 [
4679 [
4675 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4680 (b'r', b'rev', b'', _(b'revision to display'), _(b'REV')),
4676 (b'', b'all', False, _(b"list files from all revisions")),
4681 (b'', b'all', False, _(b"list files from all revisions")),
4677 ]
4682 ]
4678 + formatteropts,
4683 + formatteropts,
4679 _(b'[-r REV]'),
4684 _(b'[-r REV]'),
4680 helpcategory=command.CATEGORY_MAINTENANCE,
4685 helpcategory=command.CATEGORY_MAINTENANCE,
4681 intents={INTENT_READONLY},
4686 intents={INTENT_READONLY},
4682 )
4687 )
4683 def manifest(ui, repo, node=None, rev=None, **opts):
4688 def manifest(ui, repo, node=None, rev=None, **opts):
4684 """output the current or given revision of the project manifest
4689 """output the current or given revision of the project manifest
4685
4690
4686 Print a list of version controlled files for the given revision.
4691 Print a list of version controlled files for the given revision.
4687 If no revision is given, the first parent of the working directory
4692 If no revision is given, the first parent of the working directory
4688 is used, or the null revision if no revision is checked out.
4693 is used, or the null revision if no revision is checked out.
4689
4694
4690 With -v, print file permissions, symlink and executable bits.
4695 With -v, print file permissions, symlink and executable bits.
4691 With --debug, print file revision hashes.
4696 With --debug, print file revision hashes.
4692
4697
4693 If option --all is specified, the list of all files from all revisions
4698 If option --all is specified, the list of all files from all revisions
4694 is printed. This includes deleted and renamed files.
4699 is printed. This includes deleted and renamed files.
4695
4700
4696 Returns 0 on success.
4701 Returns 0 on success.
4697 """
4702 """
4698 opts = pycompat.byteskwargs(opts)
4703 opts = pycompat.byteskwargs(opts)
4699 fm = ui.formatter(b'manifest', opts)
4704 fm = ui.formatter(b'manifest', opts)
4700
4705
4701 if opts.get(b'all'):
4706 if opts.get(b'all'):
4702 if rev or node:
4707 if rev or node:
4703 raise error.InputError(_(b"can't specify a revision with --all"))
4708 raise error.InputError(_(b"can't specify a revision with --all"))
4704
4709
4705 res = set()
4710 res = set()
4706 for rev in repo:
4711 for rev in repo:
4707 ctx = repo[rev]
4712 ctx = repo[rev]
4708 res |= set(ctx.files())
4713 res |= set(ctx.files())
4709
4714
4710 ui.pager(b'manifest')
4715 ui.pager(b'manifest')
4711 for f in sorted(res):
4716 for f in sorted(res):
4712 fm.startitem()
4717 fm.startitem()
4713 fm.write(b"path", b'%s\n', f)
4718 fm.write(b"path", b'%s\n', f)
4714 fm.end()
4719 fm.end()
4715 return
4720 return
4716
4721
4717 if rev and node:
4722 if rev and node:
4718 raise error.InputError(_(b"please specify just one revision"))
4723 raise error.InputError(_(b"please specify just one revision"))
4719
4724
4720 if not node:
4725 if not node:
4721 node = rev
4726 node = rev
4722
4727
4723 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4728 char = {b'l': b'@', b'x': b'*', b'': b'', b't': b'd'}
4724 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4729 mode = {b'l': b'644', b'x': b'755', b'': b'644', b't': b'755'}
4725 if node:
4730 if node:
4726 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4731 repo = scmutil.unhidehashlikerevs(repo, [node], b'nowarn')
4727 ctx = scmutil.revsingle(repo, node)
4732 ctx = scmutil.revsingle(repo, node)
4728 mf = ctx.manifest()
4733 mf = ctx.manifest()
4729 ui.pager(b'manifest')
4734 ui.pager(b'manifest')
4730 for f in ctx:
4735 for f in ctx:
4731 fm.startitem()
4736 fm.startitem()
4732 fm.context(ctx=ctx)
4737 fm.context(ctx=ctx)
4733 fl = ctx[f].flags()
4738 fl = ctx[f].flags()
4734 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4739 fm.condwrite(ui.debugflag, b'hash', b'%s ', hex(mf[f]))
4735 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4740 fm.condwrite(ui.verbose, b'mode type', b'%s %1s ', mode[fl], char[fl])
4736 fm.write(b'path', b'%s\n', f)
4741 fm.write(b'path', b'%s\n', f)
4737 fm.end()
4742 fm.end()
4738
4743
4739
4744
4740 @command(
4745 @command(
4741 b'merge',
4746 b'merge',
4742 [
4747 [
4743 (
4748 (
4744 b'f',
4749 b'f',
4745 b'force',
4750 b'force',
4746 None,
4751 None,
4747 _(b'force a merge including outstanding changes (DEPRECATED)'),
4752 _(b'force a merge including outstanding changes (DEPRECATED)'),
4748 ),
4753 ),
4749 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4754 (b'r', b'rev', b'', _(b'revision to merge'), _(b'REV')),
4750 (
4755 (
4751 b'P',
4756 b'P',
4752 b'preview',
4757 b'preview',
4753 None,
4758 None,
4754 _(b'review revisions to merge (no merge is performed)'),
4759 _(b'review revisions to merge (no merge is performed)'),
4755 ),
4760 ),
4756 (b'', b'abort', None, _(b'abort the ongoing merge')),
4761 (b'', b'abort', None, _(b'abort the ongoing merge')),
4757 ]
4762 ]
4758 + mergetoolopts,
4763 + mergetoolopts,
4759 _(b'[-P] [[-r] REV]'),
4764 _(b'[-P] [[-r] REV]'),
4760 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4765 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
4761 helpbasic=True,
4766 helpbasic=True,
4762 )
4767 )
4763 def merge(ui, repo, node=None, **opts):
4768 def merge(ui, repo, node=None, **opts):
4764 """merge another revision into working directory
4769 """merge another revision into working directory
4765
4770
4766 The current working directory is updated with all changes made in
4771 The current working directory is updated with all changes made in
4767 the requested revision since the last common predecessor revision.
4772 the requested revision since the last common predecessor revision.
4768
4773
4769 Files that changed between either parent are marked as changed for
4774 Files that changed between either parent are marked as changed for
4770 the next commit and a commit must be performed before any further
4775 the next commit and a commit must be performed before any further
4771 updates to the repository are allowed. The next commit will have
4776 updates to the repository are allowed. The next commit will have
4772 two parents.
4777 two parents.
4773
4778
4774 ``--tool`` can be used to specify the merge tool used for file
4779 ``--tool`` can be used to specify the merge tool used for file
4775 merges. It overrides the HGMERGE environment variable and your
4780 merges. It overrides the HGMERGE environment variable and your
4776 configuration files. See :hg:`help merge-tools` for options.
4781 configuration files. See :hg:`help merge-tools` for options.
4777
4782
4778 If no revision is specified, the working directory's parent is a
4783 If no revision is specified, the working directory's parent is a
4779 head revision, and the current branch contains exactly one other
4784 head revision, and the current branch contains exactly one other
4780 head, the other head is merged with by default. Otherwise, an
4785 head, the other head is merged with by default. Otherwise, an
4781 explicit revision with which to merge must be provided.
4786 explicit revision with which to merge must be provided.
4782
4787
4783 See :hg:`help resolve` for information on handling file conflicts.
4788 See :hg:`help resolve` for information on handling file conflicts.
4784
4789
4785 To undo an uncommitted merge, use :hg:`merge --abort` which
4790 To undo an uncommitted merge, use :hg:`merge --abort` which
4786 will check out a clean copy of the original merge parent, losing
4791 will check out a clean copy of the original merge parent, losing
4787 all changes.
4792 all changes.
4788
4793
4789 Returns 0 on success, 1 if there are unresolved files.
4794 Returns 0 on success, 1 if there are unresolved files.
4790 """
4795 """
4791
4796
4792 opts = pycompat.byteskwargs(opts)
4797 opts = pycompat.byteskwargs(opts)
4793 abort = opts.get(b'abort')
4798 abort = opts.get(b'abort')
4794 if abort and repo.dirstate.p2() == nullid:
4799 if abort and repo.dirstate.p2() == nullid:
4795 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4800 cmdutil.wrongtooltocontinue(repo, _(b'merge'))
4796 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4801 cmdutil.check_incompatible_arguments(opts, b'abort', [b'rev', b'preview'])
4797 if abort:
4802 if abort:
4798 state = cmdutil.getunfinishedstate(repo)
4803 state = cmdutil.getunfinishedstate(repo)
4799 if state and state._opname != b'merge':
4804 if state and state._opname != b'merge':
4800 raise error.StateError(
4805 raise error.StateError(
4801 _(b'cannot abort merge with %s in progress') % (state._opname),
4806 _(b'cannot abort merge with %s in progress') % (state._opname),
4802 hint=state.hint(),
4807 hint=state.hint(),
4803 )
4808 )
4804 if node:
4809 if node:
4805 raise error.InputError(_(b"cannot specify a node with --abort"))
4810 raise error.InputError(_(b"cannot specify a node with --abort"))
4806 return hg.abortmerge(repo.ui, repo)
4811 return hg.abortmerge(repo.ui, repo)
4807
4812
4808 if opts.get(b'rev') and node:
4813 if opts.get(b'rev') and node:
4809 raise error.InputError(_(b"please specify just one revision"))
4814 raise error.InputError(_(b"please specify just one revision"))
4810 if not node:
4815 if not node:
4811 node = opts.get(b'rev')
4816 node = opts.get(b'rev')
4812
4817
4813 if node:
4818 if node:
4814 ctx = scmutil.revsingle(repo, node)
4819 ctx = scmutil.revsingle(repo, node)
4815 else:
4820 else:
4816 if ui.configbool(b'commands', b'merge.require-rev'):
4821 if ui.configbool(b'commands', b'merge.require-rev'):
4817 raise error.InputError(
4822 raise error.InputError(
4818 _(
4823 _(
4819 b'configuration requires specifying revision to merge '
4824 b'configuration requires specifying revision to merge '
4820 b'with'
4825 b'with'
4821 )
4826 )
4822 )
4827 )
4823 ctx = repo[destutil.destmerge(repo)]
4828 ctx = repo[destutil.destmerge(repo)]
4824
4829
4825 if ctx.node() is None:
4830 if ctx.node() is None:
4826 raise error.InputError(
4831 raise error.InputError(
4827 _(b'merging with the working copy has no effect')
4832 _(b'merging with the working copy has no effect')
4828 )
4833 )
4829
4834
4830 if opts.get(b'preview'):
4835 if opts.get(b'preview'):
4831 # find nodes that are ancestors of p2 but not of p1
4836 # find nodes that are ancestors of p2 but not of p1
4832 p1 = repo[b'.'].node()
4837 p1 = repo[b'.'].node()
4833 p2 = ctx.node()
4838 p2 = ctx.node()
4834 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4839 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4835
4840
4836 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4841 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
4837 for node in nodes:
4842 for node in nodes:
4838 displayer.show(repo[node])
4843 displayer.show(repo[node])
4839 displayer.close()
4844 displayer.close()
4840 return 0
4845 return 0
4841
4846
4842 # ui.forcemerge is an internal variable, do not document
4847 # ui.forcemerge is an internal variable, do not document
4843 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4848 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
4844 with ui.configoverride(overrides, b'merge'):
4849 with ui.configoverride(overrides, b'merge'):
4845 force = opts.get(b'force')
4850 force = opts.get(b'force')
4846 labels = [b'working copy', b'merge rev']
4851 labels = [b'working copy', b'merge rev']
4847 return hg.merge(ctx, force=force, labels=labels)
4852 return hg.merge(ctx, force=force, labels=labels)
4848
4853
4849
4854
4850 statemod.addunfinished(
4855 statemod.addunfinished(
4851 b'merge',
4856 b'merge',
4852 fname=None,
4857 fname=None,
4853 clearable=True,
4858 clearable=True,
4854 allowcommit=True,
4859 allowcommit=True,
4855 cmdmsg=_(b'outstanding uncommitted merge'),
4860 cmdmsg=_(b'outstanding uncommitted merge'),
4856 abortfunc=hg.abortmerge,
4861 abortfunc=hg.abortmerge,
4857 statushint=_(
4862 statushint=_(
4858 b'To continue: hg commit\nTo abort: hg merge --abort'
4863 b'To continue: hg commit\nTo abort: hg merge --abort'
4859 ),
4864 ),
4860 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4865 cmdhint=_(b"use 'hg commit' or 'hg merge --abort'"),
4861 )
4866 )
4862
4867
4863
4868
4864 @command(
4869 @command(
4865 b'outgoing|out',
4870 b'outgoing|out',
4866 [
4871 [
4867 (
4872 (
4868 b'f',
4873 b'f',
4869 b'force',
4874 b'force',
4870 None,
4875 None,
4871 _(b'run even when the destination is unrelated'),
4876 _(b'run even when the destination is unrelated'),
4872 ),
4877 ),
4873 (
4878 (
4874 b'r',
4879 b'r',
4875 b'rev',
4880 b'rev',
4876 [],
4881 [],
4877 _(b'a changeset intended to be included in the destination'),
4882 _(b'a changeset intended to be included in the destination'),
4878 _(b'REV'),
4883 _(b'REV'),
4879 ),
4884 ),
4880 (b'n', b'newest-first', None, _(b'show newest record first')),
4885 (b'n', b'newest-first', None, _(b'show newest record first')),
4881 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4886 (b'B', b'bookmarks', False, _(b'compare bookmarks')),
4882 (
4887 (
4883 b'b',
4888 b'b',
4884 b'branch',
4889 b'branch',
4885 [],
4890 [],
4886 _(b'a specific branch you would like to push'),
4891 _(b'a specific branch you would like to push'),
4887 _(b'BRANCH'),
4892 _(b'BRANCH'),
4888 ),
4893 ),
4889 ]
4894 ]
4890 + logopts
4895 + logopts
4891 + remoteopts
4896 + remoteopts
4892 + subrepoopts,
4897 + subrepoopts,
4893 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4898 _(b'[-M] [-p] [-n] [-f] [-r REV]... [DEST]'),
4894 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4899 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
4895 )
4900 )
4896 def outgoing(ui, repo, dest=None, **opts):
4901 def outgoing(ui, repo, dest=None, **opts):
4897 """show changesets not found in the destination
4902 """show changesets not found in the destination
4898
4903
4899 Show changesets not found in the specified destination repository
4904 Show changesets not found in the specified destination repository
4900 or the default push location. These are the changesets that would
4905 or the default push location. These are the changesets that would
4901 be pushed if a push was requested.
4906 be pushed if a push was requested.
4902
4907
4903 See pull for details of valid destination formats.
4908 See pull for details of valid destination formats.
4904
4909
4905 .. container:: verbose
4910 .. container:: verbose
4906
4911
4907 With -B/--bookmarks, the result of bookmark comparison between
4912 With -B/--bookmarks, the result of bookmark comparison between
4908 local and remote repositories is displayed. With -v/--verbose,
4913 local and remote repositories is displayed. With -v/--verbose,
4909 status is also displayed for each bookmark like below::
4914 status is also displayed for each bookmark like below::
4910
4915
4911 BM1 01234567890a added
4916 BM1 01234567890a added
4912 BM2 deleted
4917 BM2 deleted
4913 BM3 234567890abc advanced
4918 BM3 234567890abc advanced
4914 BM4 34567890abcd diverged
4919 BM4 34567890abcd diverged
4915 BM5 4567890abcde changed
4920 BM5 4567890abcde changed
4916
4921
4917 The action taken when pushing depends on the
4922 The action taken when pushing depends on the
4918 status of each bookmark:
4923 status of each bookmark:
4919
4924
4920 :``added``: push with ``-B`` will create it
4925 :``added``: push with ``-B`` will create it
4921 :``deleted``: push with ``-B`` will delete it
4926 :``deleted``: push with ``-B`` will delete it
4922 :``advanced``: push will update it
4927 :``advanced``: push will update it
4923 :``diverged``: push with ``-B`` will update it
4928 :``diverged``: push with ``-B`` will update it
4924 :``changed``: push with ``-B`` will update it
4929 :``changed``: push with ``-B`` will update it
4925
4930
4926 From the point of view of pushing behavior, bookmarks
4931 From the point of view of pushing behavior, bookmarks
4927 existing only in the remote repository are treated as
4932 existing only in the remote repository are treated as
4928 ``deleted``, even if it is in fact added remotely.
4933 ``deleted``, even if it is in fact added remotely.
4929
4934
4930 Returns 0 if there are outgoing changes, 1 otherwise.
4935 Returns 0 if there are outgoing changes, 1 otherwise.
4931 """
4936 """
4932 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4937 # hg._outgoing() needs to re-resolve the path in order to handle #branch
4933 # style URLs, so don't overwrite dest.
4938 # style URLs, so don't overwrite dest.
4934 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4939 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
4935 if not path:
4940 if not path:
4936 raise error.ConfigError(
4941 raise error.ConfigError(
4937 _(b'default repository not configured!'),
4942 _(b'default repository not configured!'),
4938 hint=_(b"see 'hg help config.paths'"),
4943 hint=_(b"see 'hg help config.paths'"),
4939 )
4944 )
4940
4945
4941 opts = pycompat.byteskwargs(opts)
4946 opts = pycompat.byteskwargs(opts)
4942 if opts.get(b'graph'):
4947 if opts.get(b'graph'):
4943 logcmdutil.checkunsupportedgraphflags([], opts)
4948 logcmdutil.checkunsupportedgraphflags([], opts)
4944 o, other = hg._outgoing(ui, repo, dest, opts)
4949 o, other = hg._outgoing(ui, repo, dest, opts)
4945 if not o:
4950 if not o:
4946 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4951 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4947 return
4952 return
4948
4953
4949 revdag = logcmdutil.graphrevs(repo, o, opts)
4954 revdag = logcmdutil.graphrevs(repo, o, opts)
4950 ui.pager(b'outgoing')
4955 ui.pager(b'outgoing')
4951 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4956 displayer = logcmdutil.changesetdisplayer(ui, repo, opts, buffered=True)
4952 logcmdutil.displaygraph(
4957 logcmdutil.displaygraph(
4953 ui, repo, revdag, displayer, graphmod.asciiedges
4958 ui, repo, revdag, displayer, graphmod.asciiedges
4954 )
4959 )
4955 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4960 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4956 return 0
4961 return 0
4957
4962
4958 if opts.get(b'bookmarks'):
4963 if opts.get(b'bookmarks'):
4959 dest = path.pushloc or path.loc
4964 dest = path.pushloc or path.loc
4960 other = hg.peer(repo, opts, dest)
4965 other = hg.peer(repo, opts, dest)
4961 if b'bookmarks' not in other.listkeys(b'namespaces'):
4966 if b'bookmarks' not in other.listkeys(b'namespaces'):
4962 ui.warn(_(b"remote doesn't support bookmarks\n"))
4967 ui.warn(_(b"remote doesn't support bookmarks\n"))
4963 return 0
4968 return 0
4964 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
4969 ui.status(_(b'comparing with %s\n') % util.hidepassword(dest))
4965 ui.pager(b'outgoing')
4970 ui.pager(b'outgoing')
4966 return bookmarks.outgoing(ui, repo, other)
4971 return bookmarks.outgoing(ui, repo, other)
4967
4972
4968 repo._subtoppath = path.pushloc or path.loc
4973 repo._subtoppath = path.pushloc or path.loc
4969 try:
4974 try:
4970 return hg.outgoing(ui, repo, dest, opts)
4975 return hg.outgoing(ui, repo, dest, opts)
4971 finally:
4976 finally:
4972 del repo._subtoppath
4977 del repo._subtoppath
4973
4978
4974
4979
4975 @command(
4980 @command(
4976 b'parents',
4981 b'parents',
4977 [
4982 [
4978 (
4983 (
4979 b'r',
4984 b'r',
4980 b'rev',
4985 b'rev',
4981 b'',
4986 b'',
4982 _(b'show parents of the specified revision'),
4987 _(b'show parents of the specified revision'),
4983 _(b'REV'),
4988 _(b'REV'),
4984 ),
4989 ),
4985 ]
4990 ]
4986 + templateopts,
4991 + templateopts,
4987 _(b'[-r REV] [FILE]'),
4992 _(b'[-r REV] [FILE]'),
4988 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4993 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
4989 inferrepo=True,
4994 inferrepo=True,
4990 )
4995 )
4991 def parents(ui, repo, file_=None, **opts):
4996 def parents(ui, repo, file_=None, **opts):
4992 """show the parents of the working directory or revision (DEPRECATED)
4997 """show the parents of the working directory or revision (DEPRECATED)
4993
4998
4994 Print the working directory's parent revisions. If a revision is
4999 Print the working directory's parent revisions. If a revision is
4995 given via -r/--rev, the parent of that revision will be printed.
5000 given via -r/--rev, the parent of that revision will be printed.
4996 If a file argument is given, the revision in which the file was
5001 If a file argument is given, the revision in which the file was
4997 last changed (before the working directory revision or the
5002 last changed (before the working directory revision or the
4998 argument to --rev if given) is printed.
5003 argument to --rev if given) is printed.
4999
5004
5000 This command is equivalent to::
5005 This command is equivalent to::
5001
5006
5002 hg log -r "p1()+p2()" or
5007 hg log -r "p1()+p2()" or
5003 hg log -r "p1(REV)+p2(REV)" or
5008 hg log -r "p1(REV)+p2(REV)" or
5004 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5009 hg log -r "max(::p1() and file(FILE))+max(::p2() and file(FILE))" or
5005 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5010 hg log -r "max(::p1(REV) and file(FILE))+max(::p2(REV) and file(FILE))"
5006
5011
5007 See :hg:`summary` and :hg:`help revsets` for related information.
5012 See :hg:`summary` and :hg:`help revsets` for related information.
5008
5013
5009 Returns 0 on success.
5014 Returns 0 on success.
5010 """
5015 """
5011
5016
5012 opts = pycompat.byteskwargs(opts)
5017 opts = pycompat.byteskwargs(opts)
5013 rev = opts.get(b'rev')
5018 rev = opts.get(b'rev')
5014 if rev:
5019 if rev:
5015 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5020 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
5016 ctx = scmutil.revsingle(repo, rev, None)
5021 ctx = scmutil.revsingle(repo, rev, None)
5017
5022
5018 if file_:
5023 if file_:
5019 m = scmutil.match(ctx, (file_,), opts)
5024 m = scmutil.match(ctx, (file_,), opts)
5020 if m.anypats() or len(m.files()) != 1:
5025 if m.anypats() or len(m.files()) != 1:
5021 raise error.InputError(_(b'can only specify an explicit filename'))
5026 raise error.InputError(_(b'can only specify an explicit filename'))
5022 file_ = m.files()[0]
5027 file_ = m.files()[0]
5023 filenodes = []
5028 filenodes = []
5024 for cp in ctx.parents():
5029 for cp in ctx.parents():
5025 if not cp:
5030 if not cp:
5026 continue
5031 continue
5027 try:
5032 try:
5028 filenodes.append(cp.filenode(file_))
5033 filenodes.append(cp.filenode(file_))
5029 except error.LookupError:
5034 except error.LookupError:
5030 pass
5035 pass
5031 if not filenodes:
5036 if not filenodes:
5032 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5037 raise error.InputError(_(b"'%s' not found in manifest") % file_)
5033 p = []
5038 p = []
5034 for fn in filenodes:
5039 for fn in filenodes:
5035 fctx = repo.filectx(file_, fileid=fn)
5040 fctx = repo.filectx(file_, fileid=fn)
5036 p.append(fctx.node())
5041 p.append(fctx.node())
5037 else:
5042 else:
5038 p = [cp.node() for cp in ctx.parents()]
5043 p = [cp.node() for cp in ctx.parents()]
5039
5044
5040 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5045 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
5041 for n in p:
5046 for n in p:
5042 if n != nullid:
5047 if n != nullid:
5043 displayer.show(repo[n])
5048 displayer.show(repo[n])
5044 displayer.close()
5049 displayer.close()
5045
5050
5046
5051
5047 @command(
5052 @command(
5048 b'paths',
5053 b'paths',
5049 formatteropts,
5054 formatteropts,
5050 _(b'[NAME]'),
5055 _(b'[NAME]'),
5051 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5056 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5052 optionalrepo=True,
5057 optionalrepo=True,
5053 intents={INTENT_READONLY},
5058 intents={INTENT_READONLY},
5054 )
5059 )
5055 def paths(ui, repo, search=None, **opts):
5060 def paths(ui, repo, search=None, **opts):
5056 """show aliases for remote repositories
5061 """show aliases for remote repositories
5057
5062
5058 Show definition of symbolic path name NAME. If no name is given,
5063 Show definition of symbolic path name NAME. If no name is given,
5059 show definition of all available names.
5064 show definition of all available names.
5060
5065
5061 Option -q/--quiet suppresses all output when searching for NAME
5066 Option -q/--quiet suppresses all output when searching for NAME
5062 and shows only the path names when listing all definitions.
5067 and shows only the path names when listing all definitions.
5063
5068
5064 Path names are defined in the [paths] section of your
5069 Path names are defined in the [paths] section of your
5065 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5070 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
5066 repository, ``.hg/hgrc`` is used, too.
5071 repository, ``.hg/hgrc`` is used, too.
5067
5072
5068 The path names ``default`` and ``default-push`` have a special
5073 The path names ``default`` and ``default-push`` have a special
5069 meaning. When performing a push or pull operation, they are used
5074 meaning. When performing a push or pull operation, they are used
5070 as fallbacks if no location is specified on the command-line.
5075 as fallbacks if no location is specified on the command-line.
5071 When ``default-push`` is set, it will be used for push and
5076 When ``default-push`` is set, it will be used for push and
5072 ``default`` will be used for pull; otherwise ``default`` is used
5077 ``default`` will be used for pull; otherwise ``default`` is used
5073 as the fallback for both. When cloning a repository, the clone
5078 as the fallback for both. When cloning a repository, the clone
5074 source is written as ``default`` in ``.hg/hgrc``.
5079 source is written as ``default`` in ``.hg/hgrc``.
5075
5080
5076 .. note::
5081 .. note::
5077
5082
5078 ``default`` and ``default-push`` apply to all inbound (e.g.
5083 ``default`` and ``default-push`` apply to all inbound (e.g.
5079 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5084 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email`
5080 and :hg:`bundle`) operations.
5085 and :hg:`bundle`) operations.
5081
5086
5082 See :hg:`help urls` for more information.
5087 See :hg:`help urls` for more information.
5083
5088
5084 .. container:: verbose
5089 .. container:: verbose
5085
5090
5086 Template:
5091 Template:
5087
5092
5088 The following keywords are supported. See also :hg:`help templates`.
5093 The following keywords are supported. See also :hg:`help templates`.
5089
5094
5090 :name: String. Symbolic name of the path alias.
5095 :name: String. Symbolic name of the path alias.
5091 :pushurl: String. URL for push operations.
5096 :pushurl: String. URL for push operations.
5092 :url: String. URL or directory path for the other operations.
5097 :url: String. URL or directory path for the other operations.
5093
5098
5094 Returns 0 on success.
5099 Returns 0 on success.
5095 """
5100 """
5096
5101
5097 opts = pycompat.byteskwargs(opts)
5102 opts = pycompat.byteskwargs(opts)
5098 ui.pager(b'paths')
5103 ui.pager(b'paths')
5099 if search:
5104 if search:
5100 pathitems = [
5105 pathitems = [
5101 (name, path)
5106 (name, path)
5102 for name, path in pycompat.iteritems(ui.paths)
5107 for name, path in pycompat.iteritems(ui.paths)
5103 if name == search
5108 if name == search
5104 ]
5109 ]
5105 else:
5110 else:
5106 pathitems = sorted(pycompat.iteritems(ui.paths))
5111 pathitems = sorted(pycompat.iteritems(ui.paths))
5107
5112
5108 fm = ui.formatter(b'paths', opts)
5113 fm = ui.formatter(b'paths', opts)
5109 if fm.isplain():
5114 if fm.isplain():
5110 hidepassword = util.hidepassword
5115 hidepassword = util.hidepassword
5111 else:
5116 else:
5112 hidepassword = bytes
5117 hidepassword = bytes
5113 if ui.quiet:
5118 if ui.quiet:
5114 namefmt = b'%s\n'
5119 namefmt = b'%s\n'
5115 else:
5120 else:
5116 namefmt = b'%s = '
5121 namefmt = b'%s = '
5117 showsubopts = not search and not ui.quiet
5122 showsubopts = not search and not ui.quiet
5118
5123
5119 for name, path in pathitems:
5124 for name, path in pathitems:
5120 fm.startitem()
5125 fm.startitem()
5121 fm.condwrite(not search, b'name', namefmt, name)
5126 fm.condwrite(not search, b'name', namefmt, name)
5122 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5127 fm.condwrite(not ui.quiet, b'url', b'%s\n', hidepassword(path.rawloc))
5123 for subopt, value in sorted(path.suboptions.items()):
5128 for subopt, value in sorted(path.suboptions.items()):
5124 assert subopt not in (b'name', b'url')
5129 assert subopt not in (b'name', b'url')
5125 if showsubopts:
5130 if showsubopts:
5126 fm.plain(b'%s:%s = ' % (name, subopt))
5131 fm.plain(b'%s:%s = ' % (name, subopt))
5127 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5132 fm.condwrite(showsubopts, subopt, b'%s\n', value)
5128
5133
5129 fm.end()
5134 fm.end()
5130
5135
5131 if search and not pathitems:
5136 if search and not pathitems:
5132 if not ui.quiet:
5137 if not ui.quiet:
5133 ui.warn(_(b"not found!\n"))
5138 ui.warn(_(b"not found!\n"))
5134 return 1
5139 return 1
5135 else:
5140 else:
5136 return 0
5141 return 0
5137
5142
5138
5143
5139 @command(
5144 @command(
5140 b'phase',
5145 b'phase',
5141 [
5146 [
5142 (b'p', b'public', False, _(b'set changeset phase to public')),
5147 (b'p', b'public', False, _(b'set changeset phase to public')),
5143 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5148 (b'd', b'draft', False, _(b'set changeset phase to draft')),
5144 (b's', b'secret', False, _(b'set changeset phase to secret')),
5149 (b's', b'secret', False, _(b'set changeset phase to secret')),
5145 (b'f', b'force', False, _(b'allow to move boundary backward')),
5150 (b'f', b'force', False, _(b'allow to move boundary backward')),
5146 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5151 (b'r', b'rev', [], _(b'target revision'), _(b'REV')),
5147 ],
5152 ],
5148 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5153 _(b'[-p|-d|-s] [-f] [-r] [REV...]'),
5149 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5154 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
5150 )
5155 )
5151 def phase(ui, repo, *revs, **opts):
5156 def phase(ui, repo, *revs, **opts):
5152 """set or show the current phase name
5157 """set or show the current phase name
5153
5158
5154 With no argument, show the phase name of the current revision(s).
5159 With no argument, show the phase name of the current revision(s).
5155
5160
5156 With one of -p/--public, -d/--draft or -s/--secret, change the
5161 With one of -p/--public, -d/--draft or -s/--secret, change the
5157 phase value of the specified revisions.
5162 phase value of the specified revisions.
5158
5163
5159 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5164 Unless -f/--force is specified, :hg:`phase` won't move changesets from a
5160 lower phase to a higher phase. Phases are ordered as follows::
5165 lower phase to a higher phase. Phases are ordered as follows::
5161
5166
5162 public < draft < secret
5167 public < draft < secret
5163
5168
5164 Returns 0 on success, 1 if some phases could not be changed.
5169 Returns 0 on success, 1 if some phases could not be changed.
5165
5170
5166 (For more information about the phases concept, see :hg:`help phases`.)
5171 (For more information about the phases concept, see :hg:`help phases`.)
5167 """
5172 """
5168 opts = pycompat.byteskwargs(opts)
5173 opts = pycompat.byteskwargs(opts)
5169 # search for a unique phase argument
5174 # search for a unique phase argument
5170 targetphase = None
5175 targetphase = None
5171 for idx, name in enumerate(phases.cmdphasenames):
5176 for idx, name in enumerate(phases.cmdphasenames):
5172 if opts[name]:
5177 if opts[name]:
5173 if targetphase is not None:
5178 if targetphase is not None:
5174 raise error.InputError(_(b'only one phase can be specified'))
5179 raise error.InputError(_(b'only one phase can be specified'))
5175 targetphase = idx
5180 targetphase = idx
5176
5181
5177 # look for specified revision
5182 # look for specified revision
5178 revs = list(revs)
5183 revs = list(revs)
5179 revs.extend(opts[b'rev'])
5184 revs.extend(opts[b'rev'])
5180 if not revs:
5185 if not revs:
5181 # display both parents as the second parent phase can influence
5186 # display both parents as the second parent phase can influence
5182 # the phase of a merge commit
5187 # the phase of a merge commit
5183 revs = [c.rev() for c in repo[None].parents()]
5188 revs = [c.rev() for c in repo[None].parents()]
5184
5189
5185 revs = scmutil.revrange(repo, revs)
5190 revs = scmutil.revrange(repo, revs)
5186
5191
5187 ret = 0
5192 ret = 0
5188 if targetphase is None:
5193 if targetphase is None:
5189 # display
5194 # display
5190 for r in revs:
5195 for r in revs:
5191 ctx = repo[r]
5196 ctx = repo[r]
5192 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5197 ui.write(b'%i: %s\n' % (ctx.rev(), ctx.phasestr()))
5193 else:
5198 else:
5194 with repo.lock(), repo.transaction(b"phase") as tr:
5199 with repo.lock(), repo.transaction(b"phase") as tr:
5195 # set phase
5200 # set phase
5196 if not revs:
5201 if not revs:
5197 raise error.InputError(_(b'empty revision set'))
5202 raise error.InputError(_(b'empty revision set'))
5198 nodes = [repo[r].node() for r in revs]
5203 nodes = [repo[r].node() for r in revs]
5199 # moving revision from public to draft may hide them
5204 # moving revision from public to draft may hide them
5200 # We have to check result on an unfiltered repository
5205 # We have to check result on an unfiltered repository
5201 unfi = repo.unfiltered()
5206 unfi = repo.unfiltered()
5202 getphase = unfi._phasecache.phase
5207 getphase = unfi._phasecache.phase
5203 olddata = [getphase(unfi, r) for r in unfi]
5208 olddata = [getphase(unfi, r) for r in unfi]
5204 phases.advanceboundary(repo, tr, targetphase, nodes)
5209 phases.advanceboundary(repo, tr, targetphase, nodes)
5205 if opts[b'force']:
5210 if opts[b'force']:
5206 phases.retractboundary(repo, tr, targetphase, nodes)
5211 phases.retractboundary(repo, tr, targetphase, nodes)
5207 getphase = unfi._phasecache.phase
5212 getphase = unfi._phasecache.phase
5208 newdata = [getphase(unfi, r) for r in unfi]
5213 newdata = [getphase(unfi, r) for r in unfi]
5209 changes = sum(newdata[r] != olddata[r] for r in unfi)
5214 changes = sum(newdata[r] != olddata[r] for r in unfi)
5210 cl = unfi.changelog
5215 cl = unfi.changelog
5211 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5216 rejected = [n for n in nodes if newdata[cl.rev(n)] < targetphase]
5212 if rejected:
5217 if rejected:
5213 ui.warn(
5218 ui.warn(
5214 _(
5219 _(
5215 b'cannot move %i changesets to a higher '
5220 b'cannot move %i changesets to a higher '
5216 b'phase, use --force\n'
5221 b'phase, use --force\n'
5217 )
5222 )
5218 % len(rejected)
5223 % len(rejected)
5219 )
5224 )
5220 ret = 1
5225 ret = 1
5221 if changes:
5226 if changes:
5222 msg = _(b'phase changed for %i changesets\n') % changes
5227 msg = _(b'phase changed for %i changesets\n') % changes
5223 if ret:
5228 if ret:
5224 ui.status(msg)
5229 ui.status(msg)
5225 else:
5230 else:
5226 ui.note(msg)
5231 ui.note(msg)
5227 else:
5232 else:
5228 ui.warn(_(b'no phases changed\n'))
5233 ui.warn(_(b'no phases changed\n'))
5229 return ret
5234 return ret
5230
5235
5231
5236
5232 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5237 def postincoming(ui, repo, modheads, optupdate, checkout, brev):
5233 """Run after a changegroup has been added via pull/unbundle
5238 """Run after a changegroup has been added via pull/unbundle
5234
5239
5235 This takes arguments below:
5240 This takes arguments below:
5236
5241
5237 :modheads: change of heads by pull/unbundle
5242 :modheads: change of heads by pull/unbundle
5238 :optupdate: updating working directory is needed or not
5243 :optupdate: updating working directory is needed or not
5239 :checkout: update destination revision (or None to default destination)
5244 :checkout: update destination revision (or None to default destination)
5240 :brev: a name, which might be a bookmark to be activated after updating
5245 :brev: a name, which might be a bookmark to be activated after updating
5241 """
5246 """
5242 if modheads == 0:
5247 if modheads == 0:
5243 return
5248 return
5244 if optupdate:
5249 if optupdate:
5245 try:
5250 try:
5246 return hg.updatetotally(ui, repo, checkout, brev)
5251 return hg.updatetotally(ui, repo, checkout, brev)
5247 except error.UpdateAbort as inst:
5252 except error.UpdateAbort as inst:
5248 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5253 msg = _(b"not updating: %s") % stringutil.forcebytestr(inst)
5249 hint = inst.hint
5254 hint = inst.hint
5250 raise error.UpdateAbort(msg, hint=hint)
5255 raise error.UpdateAbort(msg, hint=hint)
5251 if modheads is not None and modheads > 1:
5256 if modheads is not None and modheads > 1:
5252 currentbranchheads = len(repo.branchheads())
5257 currentbranchheads = len(repo.branchheads())
5253 if currentbranchheads == modheads:
5258 if currentbranchheads == modheads:
5254 ui.status(
5259 ui.status(
5255 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5260 _(b"(run 'hg heads' to see heads, 'hg merge' to merge)\n")
5256 )
5261 )
5257 elif currentbranchheads > 1:
5262 elif currentbranchheads > 1:
5258 ui.status(
5263 ui.status(
5259 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5264 _(b"(run 'hg heads .' to see heads, 'hg merge' to merge)\n")
5260 )
5265 )
5261 else:
5266 else:
5262 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5267 ui.status(_(b"(run 'hg heads' to see heads)\n"))
5263 elif not ui.configbool(b'commands', b'update.requiredest'):
5268 elif not ui.configbool(b'commands', b'update.requiredest'):
5264 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5269 ui.status(_(b"(run 'hg update' to get a working copy)\n"))
5265
5270
5266
5271
5267 @command(
5272 @command(
5268 b'pull',
5273 b'pull',
5269 [
5274 [
5270 (
5275 (
5271 b'u',
5276 b'u',
5272 b'update',
5277 b'update',
5273 None,
5278 None,
5274 _(b'update to new branch head if new descendants were pulled'),
5279 _(b'update to new branch head if new descendants were pulled'),
5275 ),
5280 ),
5276 (
5281 (
5277 b'f',
5282 b'f',
5278 b'force',
5283 b'force',
5279 None,
5284 None,
5280 _(b'run even when remote repository is unrelated'),
5285 _(b'run even when remote repository is unrelated'),
5281 ),
5286 ),
5282 (
5287 (
5283 b'',
5288 b'',
5284 b'confirm',
5289 b'confirm',
5285 None,
5290 None,
5286 _(b'confirm pull before applying changes'),
5291 _(b'confirm pull before applying changes'),
5287 ),
5292 ),
5288 (
5293 (
5289 b'r',
5294 b'r',
5290 b'rev',
5295 b'rev',
5291 [],
5296 [],
5292 _(b'a remote changeset intended to be added'),
5297 _(b'a remote changeset intended to be added'),
5293 _(b'REV'),
5298 _(b'REV'),
5294 ),
5299 ),
5295 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5300 (b'B', b'bookmark', [], _(b"bookmark to pull"), _(b'BOOKMARK')),
5296 (
5301 (
5297 b'b',
5302 b'b',
5298 b'branch',
5303 b'branch',
5299 [],
5304 [],
5300 _(b'a specific branch you would like to pull'),
5305 _(b'a specific branch you would like to pull'),
5301 _(b'BRANCH'),
5306 _(b'BRANCH'),
5302 ),
5307 ),
5303 ]
5308 ]
5304 + remoteopts,
5309 + remoteopts,
5305 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5310 _(b'[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'),
5306 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5311 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5307 helpbasic=True,
5312 helpbasic=True,
5308 )
5313 )
5309 def pull(ui, repo, source=b"default", **opts):
5314 def pull(ui, repo, source=b"default", **opts):
5310 """pull changes from the specified source
5315 """pull changes from the specified source
5311
5316
5312 Pull changes from a remote repository to a local one.
5317 Pull changes from a remote repository to a local one.
5313
5318
5314 This finds all changes from the repository at the specified path
5319 This finds all changes from the repository at the specified path
5315 or URL and adds them to a local repository (the current one unless
5320 or URL and adds them to a local repository (the current one unless
5316 -R is specified). By default, this does not update the copy of the
5321 -R is specified). By default, this does not update the copy of the
5317 project in the working directory.
5322 project in the working directory.
5318
5323
5319 When cloning from servers that support it, Mercurial may fetch
5324 When cloning from servers that support it, Mercurial may fetch
5320 pre-generated data. When this is done, hooks operating on incoming
5325 pre-generated data. When this is done, hooks operating on incoming
5321 changesets and changegroups may fire more than once, once for each
5326 changesets and changegroups may fire more than once, once for each
5322 pre-generated bundle and as well as for any additional remaining
5327 pre-generated bundle and as well as for any additional remaining
5323 data. See :hg:`help -e clonebundles` for more.
5328 data. See :hg:`help -e clonebundles` for more.
5324
5329
5325 Use :hg:`incoming` if you want to see what would have been added
5330 Use :hg:`incoming` if you want to see what would have been added
5326 by a pull at the time you issued this command. If you then decide
5331 by a pull at the time you issued this command. If you then decide
5327 to add those changes to the repository, you should use :hg:`pull
5332 to add those changes to the repository, you should use :hg:`pull
5328 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5333 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5329
5334
5330 If SOURCE is omitted, the 'default' path will be used.
5335 If SOURCE is omitted, the 'default' path will be used.
5331 See :hg:`help urls` for more information.
5336 See :hg:`help urls` for more information.
5332
5337
5333 Specifying bookmark as ``.`` is equivalent to specifying the active
5338 Specifying bookmark as ``.`` is equivalent to specifying the active
5334 bookmark's name.
5339 bookmark's name.
5335
5340
5336 Returns 0 on success, 1 if an update had unresolved files.
5341 Returns 0 on success, 1 if an update had unresolved files.
5337 """
5342 """
5338
5343
5339 opts = pycompat.byteskwargs(opts)
5344 opts = pycompat.byteskwargs(opts)
5340 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5345 if ui.configbool(b'commands', b'update.requiredest') and opts.get(
5341 b'update'
5346 b'update'
5342 ):
5347 ):
5343 msg = _(b'update destination required by configuration')
5348 msg = _(b'update destination required by configuration')
5344 hint = _(b'use hg pull followed by hg update DEST')
5349 hint = _(b'use hg pull followed by hg update DEST')
5345 raise error.InputError(msg, hint=hint)
5350 raise error.InputError(msg, hint=hint)
5346
5351
5347 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5352 source, branches = hg.parseurl(ui.expandpath(source), opts.get(b'branch'))
5348 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5353 ui.status(_(b'pulling from %s\n') % util.hidepassword(source))
5349 ui.flush()
5354 ui.flush()
5350 other = hg.peer(repo, opts, source)
5355 other = hg.peer(repo, opts, source)
5351 try:
5356 try:
5352 revs, checkout = hg.addbranchrevs(
5357 revs, checkout = hg.addbranchrevs(
5353 repo, other, branches, opts.get(b'rev')
5358 repo, other, branches, opts.get(b'rev')
5354 )
5359 )
5355
5360
5356 pullopargs = {}
5361 pullopargs = {}
5357
5362
5358 nodes = None
5363 nodes = None
5359 if opts.get(b'bookmark') or revs:
5364 if opts.get(b'bookmark') or revs:
5360 # The list of bookmark used here is the same used to actually update
5365 # The list of bookmark used here is the same used to actually update
5361 # the bookmark names, to avoid the race from issue 4689 and we do
5366 # the bookmark names, to avoid the race from issue 4689 and we do
5362 # all lookup and bookmark queries in one go so they see the same
5367 # all lookup and bookmark queries in one go so they see the same
5363 # version of the server state (issue 4700).
5368 # version of the server state (issue 4700).
5364 nodes = []
5369 nodes = []
5365 fnodes = []
5370 fnodes = []
5366 revs = revs or []
5371 revs = revs or []
5367 if revs and not other.capable(b'lookup'):
5372 if revs and not other.capable(b'lookup'):
5368 err = _(
5373 err = _(
5369 b"other repository doesn't support revision lookup, "
5374 b"other repository doesn't support revision lookup, "
5370 b"so a rev cannot be specified."
5375 b"so a rev cannot be specified."
5371 )
5376 )
5372 raise error.Abort(err)
5377 raise error.Abort(err)
5373 with other.commandexecutor() as e:
5378 with other.commandexecutor() as e:
5374 fremotebookmarks = e.callcommand(
5379 fremotebookmarks = e.callcommand(
5375 b'listkeys', {b'namespace': b'bookmarks'}
5380 b'listkeys', {b'namespace': b'bookmarks'}
5376 )
5381 )
5377 for r in revs:
5382 for r in revs:
5378 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5383 fnodes.append(e.callcommand(b'lookup', {b'key': r}))
5379 remotebookmarks = fremotebookmarks.result()
5384 remotebookmarks = fremotebookmarks.result()
5380 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5385 remotebookmarks = bookmarks.unhexlifybookmarks(remotebookmarks)
5381 pullopargs[b'remotebookmarks'] = remotebookmarks
5386 pullopargs[b'remotebookmarks'] = remotebookmarks
5382 for b in opts.get(b'bookmark', []):
5387 for b in opts.get(b'bookmark', []):
5383 b = repo._bookmarks.expandname(b)
5388 b = repo._bookmarks.expandname(b)
5384 if b not in remotebookmarks:
5389 if b not in remotebookmarks:
5385 raise error.InputError(
5390 raise error.InputError(
5386 _(b'remote bookmark %s not found!') % b
5391 _(b'remote bookmark %s not found!') % b
5387 )
5392 )
5388 nodes.append(remotebookmarks[b])
5393 nodes.append(remotebookmarks[b])
5389 for i, rev in enumerate(revs):
5394 for i, rev in enumerate(revs):
5390 node = fnodes[i].result()
5395 node = fnodes[i].result()
5391 nodes.append(node)
5396 nodes.append(node)
5392 if rev == checkout:
5397 if rev == checkout:
5393 checkout = node
5398 checkout = node
5394
5399
5395 wlock = util.nullcontextmanager()
5400 wlock = util.nullcontextmanager()
5396 if opts.get(b'update'):
5401 if opts.get(b'update'):
5397 wlock = repo.wlock()
5402 wlock = repo.wlock()
5398 with wlock:
5403 with wlock:
5399 pullopargs.update(opts.get(b'opargs', {}))
5404 pullopargs.update(opts.get(b'opargs', {}))
5400 modheads = exchange.pull(
5405 modheads = exchange.pull(
5401 repo,
5406 repo,
5402 other,
5407 other,
5403 heads=nodes,
5408 heads=nodes,
5404 force=opts.get(b'force'),
5409 force=opts.get(b'force'),
5405 bookmarks=opts.get(b'bookmark', ()),
5410 bookmarks=opts.get(b'bookmark', ()),
5406 opargs=pullopargs,
5411 opargs=pullopargs,
5407 confirm=opts.get(b'confirm'),
5412 confirm=opts.get(b'confirm'),
5408 ).cgresult
5413 ).cgresult
5409
5414
5410 # brev is a name, which might be a bookmark to be activated at
5415 # brev is a name, which might be a bookmark to be activated at
5411 # the end of the update. In other words, it is an explicit
5416 # the end of the update. In other words, it is an explicit
5412 # destination of the update
5417 # destination of the update
5413 brev = None
5418 brev = None
5414
5419
5415 if checkout:
5420 if checkout:
5416 checkout = repo.unfiltered().changelog.rev(checkout)
5421 checkout = repo.unfiltered().changelog.rev(checkout)
5417
5422
5418 # order below depends on implementation of
5423 # order below depends on implementation of
5419 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5424 # hg.addbranchrevs(). opts['bookmark'] is ignored,
5420 # because 'checkout' is determined without it.
5425 # because 'checkout' is determined without it.
5421 if opts.get(b'rev'):
5426 if opts.get(b'rev'):
5422 brev = opts[b'rev'][0]
5427 brev = opts[b'rev'][0]
5423 elif opts.get(b'branch'):
5428 elif opts.get(b'branch'):
5424 brev = opts[b'branch'][0]
5429 brev = opts[b'branch'][0]
5425 else:
5430 else:
5426 brev = branches[0]
5431 brev = branches[0]
5427 repo._subtoppath = source
5432 repo._subtoppath = source
5428 try:
5433 try:
5429 ret = postincoming(
5434 ret = postincoming(
5430 ui, repo, modheads, opts.get(b'update'), checkout, brev
5435 ui, repo, modheads, opts.get(b'update'), checkout, brev
5431 )
5436 )
5432 except error.FilteredRepoLookupError as exc:
5437 except error.FilteredRepoLookupError as exc:
5433 msg = _(b'cannot update to target: %s') % exc.args[0]
5438 msg = _(b'cannot update to target: %s') % exc.args[0]
5434 exc.args = (msg,) + exc.args[1:]
5439 exc.args = (msg,) + exc.args[1:]
5435 raise
5440 raise
5436 finally:
5441 finally:
5437 del repo._subtoppath
5442 del repo._subtoppath
5438
5443
5439 finally:
5444 finally:
5440 other.close()
5445 other.close()
5441 return ret
5446 return ret
5442
5447
5443
5448
5444 @command(
5449 @command(
5445 b'push',
5450 b'push',
5446 [
5451 [
5447 (b'f', b'force', None, _(b'force push')),
5452 (b'f', b'force', None, _(b'force push')),
5448 (
5453 (
5449 b'r',
5454 b'r',
5450 b'rev',
5455 b'rev',
5451 [],
5456 [],
5452 _(b'a changeset intended to be included in the destination'),
5457 _(b'a changeset intended to be included in the destination'),
5453 _(b'REV'),
5458 _(b'REV'),
5454 ),
5459 ),
5455 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5460 (b'B', b'bookmark', [], _(b"bookmark to push"), _(b'BOOKMARK')),
5456 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5461 (b'', b'all-bookmarks', None, _(b"push all bookmarks (EXPERIMENTAL)")),
5457 (
5462 (
5458 b'b',
5463 b'b',
5459 b'branch',
5464 b'branch',
5460 [],
5465 [],
5461 _(b'a specific branch you would like to push'),
5466 _(b'a specific branch you would like to push'),
5462 _(b'BRANCH'),
5467 _(b'BRANCH'),
5463 ),
5468 ),
5464 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5469 (b'', b'new-branch', False, _(b'allow pushing a new branch')),
5465 (
5470 (
5466 b'',
5471 b'',
5467 b'pushvars',
5472 b'pushvars',
5468 [],
5473 [],
5469 _(b'variables that can be sent to server (ADVANCED)'),
5474 _(b'variables that can be sent to server (ADVANCED)'),
5470 ),
5475 ),
5471 (
5476 (
5472 b'',
5477 b'',
5473 b'publish',
5478 b'publish',
5474 False,
5479 False,
5475 _(b'push the changeset as public (EXPERIMENTAL)'),
5480 _(b'push the changeset as public (EXPERIMENTAL)'),
5476 ),
5481 ),
5477 ]
5482 ]
5478 + remoteopts,
5483 + remoteopts,
5479 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5484 _(b'[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'),
5480 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5485 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
5481 helpbasic=True,
5486 helpbasic=True,
5482 )
5487 )
5483 def push(ui, repo, dest=None, **opts):
5488 def push(ui, repo, dest=None, **opts):
5484 """push changes to the specified destination
5489 """push changes to the specified destination
5485
5490
5486 Push changesets from the local repository to the specified
5491 Push changesets from the local repository to the specified
5487 destination.
5492 destination.
5488
5493
5489 This operation is symmetrical to pull: it is identical to a pull
5494 This operation is symmetrical to pull: it is identical to a pull
5490 in the destination repository from the current one.
5495 in the destination repository from the current one.
5491
5496
5492 By default, push will not allow creation of new heads at the
5497 By default, push will not allow creation of new heads at the
5493 destination, since multiple heads would make it unclear which head
5498 destination, since multiple heads would make it unclear which head
5494 to use. In this situation, it is recommended to pull and merge
5499 to use. In this situation, it is recommended to pull and merge
5495 before pushing.
5500 before pushing.
5496
5501
5497 Use --new-branch if you want to allow push to create a new named
5502 Use --new-branch if you want to allow push to create a new named
5498 branch that is not present at the destination. This allows you to
5503 branch that is not present at the destination. This allows you to
5499 only create a new branch without forcing other changes.
5504 only create a new branch without forcing other changes.
5500
5505
5501 .. note::
5506 .. note::
5502
5507
5503 Extra care should be taken with the -f/--force option,
5508 Extra care should be taken with the -f/--force option,
5504 which will push all new heads on all branches, an action which will
5509 which will push all new heads on all branches, an action which will
5505 almost always cause confusion for collaborators.
5510 almost always cause confusion for collaborators.
5506
5511
5507 If -r/--rev is used, the specified revision and all its ancestors
5512 If -r/--rev is used, the specified revision and all its ancestors
5508 will be pushed to the remote repository.
5513 will be pushed to the remote repository.
5509
5514
5510 If -B/--bookmark is used, the specified bookmarked revision, its
5515 If -B/--bookmark is used, the specified bookmarked revision, its
5511 ancestors, and the bookmark will be pushed to the remote
5516 ancestors, and the bookmark will be pushed to the remote
5512 repository. Specifying ``.`` is equivalent to specifying the active
5517 repository. Specifying ``.`` is equivalent to specifying the active
5513 bookmark's name. Use the --all-bookmarks option for pushing all
5518 bookmark's name. Use the --all-bookmarks option for pushing all
5514 current bookmarks.
5519 current bookmarks.
5515
5520
5516 Please see :hg:`help urls` for important details about ``ssh://``
5521 Please see :hg:`help urls` for important details about ``ssh://``
5517 URLs. If DESTINATION is omitted, a default path will be used.
5522 URLs. If DESTINATION is omitted, a default path will be used.
5518
5523
5519 .. container:: verbose
5524 .. container:: verbose
5520
5525
5521 The --pushvars option sends strings to the server that become
5526 The --pushvars option sends strings to the server that become
5522 environment variables prepended with ``HG_USERVAR_``. For example,
5527 environment variables prepended with ``HG_USERVAR_``. For example,
5523 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5528 ``--pushvars ENABLE_FEATURE=true``, provides the server side hooks with
5524 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5529 ``HG_USERVAR_ENABLE_FEATURE=true`` as part of their environment.
5525
5530
5526 pushvars can provide for user-overridable hooks as well as set debug
5531 pushvars can provide for user-overridable hooks as well as set debug
5527 levels. One example is having a hook that blocks commits containing
5532 levels. One example is having a hook that blocks commits containing
5528 conflict markers, but enables the user to override the hook if the file
5533 conflict markers, but enables the user to override the hook if the file
5529 is using conflict markers for testing purposes or the file format has
5534 is using conflict markers for testing purposes or the file format has
5530 strings that look like conflict markers.
5535 strings that look like conflict markers.
5531
5536
5532 By default, servers will ignore `--pushvars`. To enable it add the
5537 By default, servers will ignore `--pushvars`. To enable it add the
5533 following to your configuration file::
5538 following to your configuration file::
5534
5539
5535 [push]
5540 [push]
5536 pushvars.server = true
5541 pushvars.server = true
5537
5542
5538 Returns 0 if push was successful, 1 if nothing to push.
5543 Returns 0 if push was successful, 1 if nothing to push.
5539 """
5544 """
5540
5545
5541 opts = pycompat.byteskwargs(opts)
5546 opts = pycompat.byteskwargs(opts)
5542
5547
5543 if opts.get(b'all_bookmarks'):
5548 if opts.get(b'all_bookmarks'):
5544 cmdutil.check_incompatible_arguments(
5549 cmdutil.check_incompatible_arguments(
5545 opts,
5550 opts,
5546 b'all_bookmarks',
5551 b'all_bookmarks',
5547 [b'bookmark', b'rev'],
5552 [b'bookmark', b'rev'],
5548 )
5553 )
5549 opts[b'bookmark'] = list(repo._bookmarks)
5554 opts[b'bookmark'] = list(repo._bookmarks)
5550
5555
5551 if opts.get(b'bookmark'):
5556 if opts.get(b'bookmark'):
5552 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5557 ui.setconfig(b'bookmarks', b'pushing', opts[b'bookmark'], b'push')
5553 for b in opts[b'bookmark']:
5558 for b in opts[b'bookmark']:
5554 # translate -B options to -r so changesets get pushed
5559 # translate -B options to -r so changesets get pushed
5555 b = repo._bookmarks.expandname(b)
5560 b = repo._bookmarks.expandname(b)
5556 if b in repo._bookmarks:
5561 if b in repo._bookmarks:
5557 opts.setdefault(b'rev', []).append(b)
5562 opts.setdefault(b'rev', []).append(b)
5558 else:
5563 else:
5559 # if we try to push a deleted bookmark, translate it to null
5564 # if we try to push a deleted bookmark, translate it to null
5560 # this lets simultaneous -r, -b options continue working
5565 # this lets simultaneous -r, -b options continue working
5561 opts.setdefault(b'rev', []).append(b"null")
5566 opts.setdefault(b'rev', []).append(b"null")
5562
5567
5563 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5568 path = ui.paths.getpath(dest, default=(b'default-push', b'default'))
5564 if not path:
5569 if not path:
5565 raise error.ConfigError(
5570 raise error.ConfigError(
5566 _(b'default repository not configured!'),
5571 _(b'default repository not configured!'),
5567 hint=_(b"see 'hg help config.paths'"),
5572 hint=_(b"see 'hg help config.paths'"),
5568 )
5573 )
5569 dest = path.pushloc or path.loc
5574 dest = path.pushloc or path.loc
5570 branches = (path.branch, opts.get(b'branch') or [])
5575 branches = (path.branch, opts.get(b'branch') or [])
5571 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5576 ui.status(_(b'pushing to %s\n') % util.hidepassword(dest))
5572 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5577 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get(b'rev'))
5573 other = hg.peer(repo, opts, dest)
5578 other = hg.peer(repo, opts, dest)
5574
5579
5575 if revs:
5580 if revs:
5576 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5581 revs = [repo[r].node() for r in scmutil.revrange(repo, revs)]
5577 if not revs:
5582 if not revs:
5578 raise error.InputError(
5583 raise error.InputError(
5579 _(b"specified revisions evaluate to an empty set"),
5584 _(b"specified revisions evaluate to an empty set"),
5580 hint=_(b"use different revision arguments"),
5585 hint=_(b"use different revision arguments"),
5581 )
5586 )
5582 elif path.pushrev:
5587 elif path.pushrev:
5583 # It doesn't make any sense to specify ancestor revisions. So limit
5588 # It doesn't make any sense to specify ancestor revisions. So limit
5584 # to DAG heads to make discovery simpler.
5589 # to DAG heads to make discovery simpler.
5585 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5590 expr = revsetlang.formatspec(b'heads(%r)', path.pushrev)
5586 revs = scmutil.revrange(repo, [expr])
5591 revs = scmutil.revrange(repo, [expr])
5587 revs = [repo[rev].node() for rev in revs]
5592 revs = [repo[rev].node() for rev in revs]
5588 if not revs:
5593 if not revs:
5589 raise error.InputError(
5594 raise error.InputError(
5590 _(b'default push revset for path evaluates to an empty set')
5595 _(b'default push revset for path evaluates to an empty set')
5591 )
5596 )
5592 elif ui.configbool(b'commands', b'push.require-revs'):
5597 elif ui.configbool(b'commands', b'push.require-revs'):
5593 raise error.InputError(
5598 raise error.InputError(
5594 _(b'no revisions specified to push'),
5599 _(b'no revisions specified to push'),
5595 hint=_(b'did you mean "hg push -r ."?'),
5600 hint=_(b'did you mean "hg push -r ."?'),
5596 )
5601 )
5597
5602
5598 repo._subtoppath = dest
5603 repo._subtoppath = dest
5599 try:
5604 try:
5600 # push subrepos depth-first for coherent ordering
5605 # push subrepos depth-first for coherent ordering
5601 c = repo[b'.']
5606 c = repo[b'.']
5602 subs = c.substate # only repos that are committed
5607 subs = c.substate # only repos that are committed
5603 for s in sorted(subs):
5608 for s in sorted(subs):
5604 result = c.sub(s).push(opts)
5609 result = c.sub(s).push(opts)
5605 if result == 0:
5610 if result == 0:
5606 return not result
5611 return not result
5607 finally:
5612 finally:
5608 del repo._subtoppath
5613 del repo._subtoppath
5609
5614
5610 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5615 opargs = dict(opts.get(b'opargs', {})) # copy opargs since we may mutate it
5611 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5616 opargs.setdefault(b'pushvars', []).extend(opts.get(b'pushvars', []))
5612
5617
5613 pushop = exchange.push(
5618 pushop = exchange.push(
5614 repo,
5619 repo,
5615 other,
5620 other,
5616 opts.get(b'force'),
5621 opts.get(b'force'),
5617 revs=revs,
5622 revs=revs,
5618 newbranch=opts.get(b'new_branch'),
5623 newbranch=opts.get(b'new_branch'),
5619 bookmarks=opts.get(b'bookmark', ()),
5624 bookmarks=opts.get(b'bookmark', ()),
5620 publish=opts.get(b'publish'),
5625 publish=opts.get(b'publish'),
5621 opargs=opargs,
5626 opargs=opargs,
5622 )
5627 )
5623
5628
5624 result = not pushop.cgresult
5629 result = not pushop.cgresult
5625
5630
5626 if pushop.bkresult is not None:
5631 if pushop.bkresult is not None:
5627 if pushop.bkresult == 2:
5632 if pushop.bkresult == 2:
5628 result = 2
5633 result = 2
5629 elif not result and pushop.bkresult:
5634 elif not result and pushop.bkresult:
5630 result = 2
5635 result = 2
5631
5636
5632 return result
5637 return result
5633
5638
5634
5639
5635 @command(
5640 @command(
5636 b'recover',
5641 b'recover',
5637 [
5642 [
5638 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5643 (b'', b'verify', False, b"run `hg verify` after successful recover"),
5639 ],
5644 ],
5640 helpcategory=command.CATEGORY_MAINTENANCE,
5645 helpcategory=command.CATEGORY_MAINTENANCE,
5641 )
5646 )
5642 def recover(ui, repo, **opts):
5647 def recover(ui, repo, **opts):
5643 """roll back an interrupted transaction
5648 """roll back an interrupted transaction
5644
5649
5645 Recover from an interrupted commit or pull.
5650 Recover from an interrupted commit or pull.
5646
5651
5647 This command tries to fix the repository status after an
5652 This command tries to fix the repository status after an
5648 interrupted operation. It should only be necessary when Mercurial
5653 interrupted operation. It should only be necessary when Mercurial
5649 suggests it.
5654 suggests it.
5650
5655
5651 Returns 0 if successful, 1 if nothing to recover or verify fails.
5656 Returns 0 if successful, 1 if nothing to recover or verify fails.
5652 """
5657 """
5653 ret = repo.recover()
5658 ret = repo.recover()
5654 if ret:
5659 if ret:
5655 if opts['verify']:
5660 if opts['verify']:
5656 return hg.verify(repo)
5661 return hg.verify(repo)
5657 else:
5662 else:
5658 msg = _(
5663 msg = _(
5659 b"(verify step skipped, run `hg verify` to check your "
5664 b"(verify step skipped, run `hg verify` to check your "
5660 b"repository content)\n"
5665 b"repository content)\n"
5661 )
5666 )
5662 ui.warn(msg)
5667 ui.warn(msg)
5663 return 0
5668 return 0
5664 return 1
5669 return 1
5665
5670
5666
5671
5667 @command(
5672 @command(
5668 b'remove|rm',
5673 b'remove|rm',
5669 [
5674 [
5670 (b'A', b'after', None, _(b'record delete for missing files')),
5675 (b'A', b'after', None, _(b'record delete for missing files')),
5671 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5676 (b'f', b'force', None, _(b'forget added files, delete modified files')),
5672 ]
5677 ]
5673 + subrepoopts
5678 + subrepoopts
5674 + walkopts
5679 + walkopts
5675 + dryrunopts,
5680 + dryrunopts,
5676 _(b'[OPTION]... FILE...'),
5681 _(b'[OPTION]... FILE...'),
5677 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5682 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5678 helpbasic=True,
5683 helpbasic=True,
5679 inferrepo=True,
5684 inferrepo=True,
5680 )
5685 )
5681 def remove(ui, repo, *pats, **opts):
5686 def remove(ui, repo, *pats, **opts):
5682 """remove the specified files on the next commit
5687 """remove the specified files on the next commit
5683
5688
5684 Schedule the indicated files for removal from the current branch.
5689 Schedule the indicated files for removal from the current branch.
5685
5690
5686 This command schedules the files to be removed at the next commit.
5691 This command schedules the files to be removed at the next commit.
5687 To undo a remove before that, see :hg:`revert`. To undo added
5692 To undo a remove before that, see :hg:`revert`. To undo added
5688 files, see :hg:`forget`.
5693 files, see :hg:`forget`.
5689
5694
5690 .. container:: verbose
5695 .. container:: verbose
5691
5696
5692 -A/--after can be used to remove only files that have already
5697 -A/--after can be used to remove only files that have already
5693 been deleted, -f/--force can be used to force deletion, and -Af
5698 been deleted, -f/--force can be used to force deletion, and -Af
5694 can be used to remove files from the next revision without
5699 can be used to remove files from the next revision without
5695 deleting them from the working directory.
5700 deleting them from the working directory.
5696
5701
5697 The following table details the behavior of remove for different
5702 The following table details the behavior of remove for different
5698 file states (columns) and option combinations (rows). The file
5703 file states (columns) and option combinations (rows). The file
5699 states are Added [A], Clean [C], Modified [M] and Missing [!]
5704 states are Added [A], Clean [C], Modified [M] and Missing [!]
5700 (as reported by :hg:`status`). The actions are Warn, Remove
5705 (as reported by :hg:`status`). The actions are Warn, Remove
5701 (from branch) and Delete (from disk):
5706 (from branch) and Delete (from disk):
5702
5707
5703 ========= == == == ==
5708 ========= == == == ==
5704 opt/state A C M !
5709 opt/state A C M !
5705 ========= == == == ==
5710 ========= == == == ==
5706 none W RD W R
5711 none W RD W R
5707 -f R RD RD R
5712 -f R RD RD R
5708 -A W W W R
5713 -A W W W R
5709 -Af R R R R
5714 -Af R R R R
5710 ========= == == == ==
5715 ========= == == == ==
5711
5716
5712 .. note::
5717 .. note::
5713
5718
5714 :hg:`remove` never deletes files in Added [A] state from the
5719 :hg:`remove` never deletes files in Added [A] state from the
5715 working directory, not even if ``--force`` is specified.
5720 working directory, not even if ``--force`` is specified.
5716
5721
5717 Returns 0 on success, 1 if any warnings encountered.
5722 Returns 0 on success, 1 if any warnings encountered.
5718 """
5723 """
5719
5724
5720 opts = pycompat.byteskwargs(opts)
5725 opts = pycompat.byteskwargs(opts)
5721 after, force = opts.get(b'after'), opts.get(b'force')
5726 after, force = opts.get(b'after'), opts.get(b'force')
5722 dryrun = opts.get(b'dry_run')
5727 dryrun = opts.get(b'dry_run')
5723 if not pats and not after:
5728 if not pats and not after:
5724 raise error.InputError(_(b'no files specified'))
5729 raise error.InputError(_(b'no files specified'))
5725
5730
5726 m = scmutil.match(repo[None], pats, opts)
5731 m = scmutil.match(repo[None], pats, opts)
5727 subrepos = opts.get(b'subrepos')
5732 subrepos = opts.get(b'subrepos')
5728 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5733 uipathfn = scmutil.getuipathfn(repo, legacyrelativevalue=True)
5729 return cmdutil.remove(
5734 return cmdutil.remove(
5730 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5735 ui, repo, m, b"", uipathfn, after, force, subrepos, dryrun=dryrun
5731 )
5736 )
5732
5737
5733
5738
5734 @command(
5739 @command(
5735 b'rename|move|mv',
5740 b'rename|move|mv',
5736 [
5741 [
5737 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5742 (b'A', b'after', None, _(b'record a rename that has already occurred')),
5738 (
5743 (
5739 b'',
5744 b'',
5740 b'at-rev',
5745 b'at-rev',
5741 b'',
5746 b'',
5742 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5747 _(b'(un)mark renames in the given revision (EXPERIMENTAL)'),
5743 _(b'REV'),
5748 _(b'REV'),
5744 ),
5749 ),
5745 (
5750 (
5746 b'f',
5751 b'f',
5747 b'force',
5752 b'force',
5748 None,
5753 None,
5749 _(b'forcibly move over an existing managed file'),
5754 _(b'forcibly move over an existing managed file'),
5750 ),
5755 ),
5751 ]
5756 ]
5752 + walkopts
5757 + walkopts
5753 + dryrunopts,
5758 + dryrunopts,
5754 _(b'[OPTION]... SOURCE... DEST'),
5759 _(b'[OPTION]... SOURCE... DEST'),
5755 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5760 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5756 )
5761 )
5757 def rename(ui, repo, *pats, **opts):
5762 def rename(ui, repo, *pats, **opts):
5758 """rename files; equivalent of copy + remove
5763 """rename files; equivalent of copy + remove
5759
5764
5760 Mark dest as copies of sources; mark sources for deletion. If dest
5765 Mark dest as copies of sources; mark sources for deletion. If dest
5761 is a directory, copies are put in that directory. If dest is a
5766 is a directory, copies are put in that directory. If dest is a
5762 file, there can only be one source.
5767 file, there can only be one source.
5763
5768
5764 By default, this command copies the contents of files as they
5769 By default, this command copies the contents of files as they
5765 exist in the working directory. If invoked with -A/--after, the
5770 exist in the working directory. If invoked with -A/--after, the
5766 operation is recorded, but no copying is performed.
5771 operation is recorded, but no copying is performed.
5767
5772
5768 This command takes effect at the next commit. To undo a rename
5773 This command takes effect at the next commit. To undo a rename
5769 before that, see :hg:`revert`.
5774 before that, see :hg:`revert`.
5770
5775
5771 Returns 0 on success, 1 if errors are encountered.
5776 Returns 0 on success, 1 if errors are encountered.
5772 """
5777 """
5773 opts = pycompat.byteskwargs(opts)
5778 opts = pycompat.byteskwargs(opts)
5774 with repo.wlock():
5779 with repo.wlock():
5775 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5780 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5776
5781
5777
5782
5778 @command(
5783 @command(
5779 b'resolve',
5784 b'resolve',
5780 [
5785 [
5781 (b'a', b'all', None, _(b'select all unresolved files')),
5786 (b'a', b'all', None, _(b'select all unresolved files')),
5782 (b'l', b'list', None, _(b'list state of files needing merge')),
5787 (b'l', b'list', None, _(b'list state of files needing merge')),
5783 (b'm', b'mark', None, _(b'mark files as resolved')),
5788 (b'm', b'mark', None, _(b'mark files as resolved')),
5784 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5789 (b'u', b'unmark', None, _(b'mark files as unresolved')),
5785 (b'n', b'no-status', None, _(b'hide status prefix')),
5790 (b'n', b'no-status', None, _(b'hide status prefix')),
5786 (b'', b're-merge', None, _(b're-merge files')),
5791 (b'', b're-merge', None, _(b're-merge files')),
5787 ]
5792 ]
5788 + mergetoolopts
5793 + mergetoolopts
5789 + walkopts
5794 + walkopts
5790 + formatteropts,
5795 + formatteropts,
5791 _(b'[OPTION]... [FILE]...'),
5796 _(b'[OPTION]... [FILE]...'),
5792 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5797 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
5793 inferrepo=True,
5798 inferrepo=True,
5794 )
5799 )
5795 def resolve(ui, repo, *pats, **opts):
5800 def resolve(ui, repo, *pats, **opts):
5796 """redo merges or set/view the merge status of files
5801 """redo merges or set/view the merge status of files
5797
5802
5798 Merges with unresolved conflicts are often the result of
5803 Merges with unresolved conflicts are often the result of
5799 non-interactive merging using the ``internal:merge`` configuration
5804 non-interactive merging using the ``internal:merge`` configuration
5800 setting, or a command-line merge tool like ``diff3``. The resolve
5805 setting, or a command-line merge tool like ``diff3``. The resolve
5801 command is used to manage the files involved in a merge, after
5806 command is used to manage the files involved in a merge, after
5802 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5807 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5803 working directory must have two parents). See :hg:`help
5808 working directory must have two parents). See :hg:`help
5804 merge-tools` for information on configuring merge tools.
5809 merge-tools` for information on configuring merge tools.
5805
5810
5806 The resolve command can be used in the following ways:
5811 The resolve command can be used in the following ways:
5807
5812
5808 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5813 - :hg:`resolve [--re-merge] [--tool TOOL] FILE...`: attempt to re-merge
5809 the specified files, discarding any previous merge attempts. Re-merging
5814 the specified files, discarding any previous merge attempts. Re-merging
5810 is not performed for files already marked as resolved. Use ``--all/-a``
5815 is not performed for files already marked as resolved. Use ``--all/-a``
5811 to select all unresolved files. ``--tool`` can be used to specify
5816 to select all unresolved files. ``--tool`` can be used to specify
5812 the merge tool used for the given files. It overrides the HGMERGE
5817 the merge tool used for the given files. It overrides the HGMERGE
5813 environment variable and your configuration files. Previous file
5818 environment variable and your configuration files. Previous file
5814 contents are saved with a ``.orig`` suffix.
5819 contents are saved with a ``.orig`` suffix.
5815
5820
5816 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5821 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5817 (e.g. after having manually fixed-up the files). The default is
5822 (e.g. after having manually fixed-up the files). The default is
5818 to mark all unresolved files.
5823 to mark all unresolved files.
5819
5824
5820 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5825 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5821 default is to mark all resolved files.
5826 default is to mark all resolved files.
5822
5827
5823 - :hg:`resolve -l`: list files which had or still have conflicts.
5828 - :hg:`resolve -l`: list files which had or still have conflicts.
5824 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5829 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5825 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5830 You can use ``set:unresolved()`` or ``set:resolved()`` to filter
5826 the list. See :hg:`help filesets` for details.
5831 the list. See :hg:`help filesets` for details.
5827
5832
5828 .. note::
5833 .. note::
5829
5834
5830 Mercurial will not let you commit files with unresolved merge
5835 Mercurial will not let you commit files with unresolved merge
5831 conflicts. You must use :hg:`resolve -m ...` before you can
5836 conflicts. You must use :hg:`resolve -m ...` before you can
5832 commit after a conflicting merge.
5837 commit after a conflicting merge.
5833
5838
5834 .. container:: verbose
5839 .. container:: verbose
5835
5840
5836 Template:
5841 Template:
5837
5842
5838 The following keywords are supported in addition to the common template
5843 The following keywords are supported in addition to the common template
5839 keywords and functions. See also :hg:`help templates`.
5844 keywords and functions. See also :hg:`help templates`.
5840
5845
5841 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5846 :mergestatus: String. Character denoting merge conflicts, ``U`` or ``R``.
5842 :path: String. Repository-absolute path of the file.
5847 :path: String. Repository-absolute path of the file.
5843
5848
5844 Returns 0 on success, 1 if any files fail a resolve attempt.
5849 Returns 0 on success, 1 if any files fail a resolve attempt.
5845 """
5850 """
5846
5851
5847 opts = pycompat.byteskwargs(opts)
5852 opts = pycompat.byteskwargs(opts)
5848 confirm = ui.configbool(b'commands', b'resolve.confirm')
5853 confirm = ui.configbool(b'commands', b'resolve.confirm')
5849 flaglist = b'all mark unmark list no_status re_merge'.split()
5854 flaglist = b'all mark unmark list no_status re_merge'.split()
5850 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5855 all, mark, unmark, show, nostatus, remerge = [opts.get(o) for o in flaglist]
5851
5856
5852 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5857 actioncount = len(list(filter(None, [show, mark, unmark, remerge])))
5853 if actioncount > 1:
5858 if actioncount > 1:
5854 raise error.InputError(_(b"too many actions specified"))
5859 raise error.InputError(_(b"too many actions specified"))
5855 elif actioncount == 0 and ui.configbool(
5860 elif actioncount == 0 and ui.configbool(
5856 b'commands', b'resolve.explicit-re-merge'
5861 b'commands', b'resolve.explicit-re-merge'
5857 ):
5862 ):
5858 hint = _(b'use --mark, --unmark, --list or --re-merge')
5863 hint = _(b'use --mark, --unmark, --list or --re-merge')
5859 raise error.InputError(_(b'no action specified'), hint=hint)
5864 raise error.InputError(_(b'no action specified'), hint=hint)
5860 if pats and all:
5865 if pats and all:
5861 raise error.InputError(_(b"can't specify --all and patterns"))
5866 raise error.InputError(_(b"can't specify --all and patterns"))
5862 if not (all or pats or show or mark or unmark):
5867 if not (all or pats or show or mark or unmark):
5863 raise error.InputError(
5868 raise error.InputError(
5864 _(b'no files or directories specified'),
5869 _(b'no files or directories specified'),
5865 hint=b'use --all to re-merge all unresolved files',
5870 hint=b'use --all to re-merge all unresolved files',
5866 )
5871 )
5867
5872
5868 if confirm:
5873 if confirm:
5869 if all:
5874 if all:
5870 if ui.promptchoice(
5875 if ui.promptchoice(
5871 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5876 _(b're-merge all unresolved files (yn)?$$ &Yes $$ &No')
5872 ):
5877 ):
5873 raise error.CanceledError(_(b'user quit'))
5878 raise error.CanceledError(_(b'user quit'))
5874 if mark and not pats:
5879 if mark and not pats:
5875 if ui.promptchoice(
5880 if ui.promptchoice(
5876 _(
5881 _(
5877 b'mark all unresolved files as resolved (yn)?'
5882 b'mark all unresolved files as resolved (yn)?'
5878 b'$$ &Yes $$ &No'
5883 b'$$ &Yes $$ &No'
5879 )
5884 )
5880 ):
5885 ):
5881 raise error.CanceledError(_(b'user quit'))
5886 raise error.CanceledError(_(b'user quit'))
5882 if unmark and not pats:
5887 if unmark and not pats:
5883 if ui.promptchoice(
5888 if ui.promptchoice(
5884 _(
5889 _(
5885 b'mark all resolved files as unresolved (yn)?'
5890 b'mark all resolved files as unresolved (yn)?'
5886 b'$$ &Yes $$ &No'
5891 b'$$ &Yes $$ &No'
5887 )
5892 )
5888 ):
5893 ):
5889 raise error.CanceledError(_(b'user quit'))
5894 raise error.CanceledError(_(b'user quit'))
5890
5895
5891 uipathfn = scmutil.getuipathfn(repo)
5896 uipathfn = scmutil.getuipathfn(repo)
5892
5897
5893 if show:
5898 if show:
5894 ui.pager(b'resolve')
5899 ui.pager(b'resolve')
5895 fm = ui.formatter(b'resolve', opts)
5900 fm = ui.formatter(b'resolve', opts)
5896 ms = mergestatemod.mergestate.read(repo)
5901 ms = mergestatemod.mergestate.read(repo)
5897 wctx = repo[None]
5902 wctx = repo[None]
5898 m = scmutil.match(wctx, pats, opts)
5903 m = scmutil.match(wctx, pats, opts)
5899
5904
5900 # Labels and keys based on merge state. Unresolved path conflicts show
5905 # Labels and keys based on merge state. Unresolved path conflicts show
5901 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5906 # as 'P'. Resolved path conflicts show as 'R', the same as normal
5902 # resolved conflicts.
5907 # resolved conflicts.
5903 mergestateinfo = {
5908 mergestateinfo = {
5904 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5909 mergestatemod.MERGE_RECORD_UNRESOLVED: (
5905 b'resolve.unresolved',
5910 b'resolve.unresolved',
5906 b'U',
5911 b'U',
5907 ),
5912 ),
5908 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5913 mergestatemod.MERGE_RECORD_RESOLVED: (b'resolve.resolved', b'R'),
5909 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5914 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH: (
5910 b'resolve.unresolved',
5915 b'resolve.unresolved',
5911 b'P',
5916 b'P',
5912 ),
5917 ),
5913 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5918 mergestatemod.MERGE_RECORD_RESOLVED_PATH: (
5914 b'resolve.resolved',
5919 b'resolve.resolved',
5915 b'R',
5920 b'R',
5916 ),
5921 ),
5917 }
5922 }
5918
5923
5919 for f in ms:
5924 for f in ms:
5920 if not m(f):
5925 if not m(f):
5921 continue
5926 continue
5922
5927
5923 label, key = mergestateinfo[ms[f]]
5928 label, key = mergestateinfo[ms[f]]
5924 fm.startitem()
5929 fm.startitem()
5925 fm.context(ctx=wctx)
5930 fm.context(ctx=wctx)
5926 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5931 fm.condwrite(not nostatus, b'mergestatus', b'%s ', key, label=label)
5927 fm.data(path=f)
5932 fm.data(path=f)
5928 fm.plain(b'%s\n' % uipathfn(f), label=label)
5933 fm.plain(b'%s\n' % uipathfn(f), label=label)
5929 fm.end()
5934 fm.end()
5930 return 0
5935 return 0
5931
5936
5932 with repo.wlock():
5937 with repo.wlock():
5933 ms = mergestatemod.mergestate.read(repo)
5938 ms = mergestatemod.mergestate.read(repo)
5934
5939
5935 if not (ms.active() or repo.dirstate.p2() != nullid):
5940 if not (ms.active() or repo.dirstate.p2() != nullid):
5936 raise error.StateError(
5941 raise error.StateError(
5937 _(b'resolve command not applicable when not merging')
5942 _(b'resolve command not applicable when not merging')
5938 )
5943 )
5939
5944
5940 wctx = repo[None]
5945 wctx = repo[None]
5941 m = scmutil.match(wctx, pats, opts)
5946 m = scmutil.match(wctx, pats, opts)
5942 ret = 0
5947 ret = 0
5943 didwork = False
5948 didwork = False
5944
5949
5945 tocomplete = []
5950 tocomplete = []
5946 hasconflictmarkers = []
5951 hasconflictmarkers = []
5947 if mark:
5952 if mark:
5948 markcheck = ui.config(b'commands', b'resolve.mark-check')
5953 markcheck = ui.config(b'commands', b'resolve.mark-check')
5949 if markcheck not in [b'warn', b'abort']:
5954 if markcheck not in [b'warn', b'abort']:
5950 # Treat all invalid / unrecognized values as 'none'.
5955 # Treat all invalid / unrecognized values as 'none'.
5951 markcheck = False
5956 markcheck = False
5952 for f in ms:
5957 for f in ms:
5953 if not m(f):
5958 if not m(f):
5954 continue
5959 continue
5955
5960
5956 didwork = True
5961 didwork = True
5957
5962
5958 # path conflicts must be resolved manually
5963 # path conflicts must be resolved manually
5959 if ms[f] in (
5964 if ms[f] in (
5960 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
5965 mergestatemod.MERGE_RECORD_UNRESOLVED_PATH,
5961 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
5966 mergestatemod.MERGE_RECORD_RESOLVED_PATH,
5962 ):
5967 ):
5963 if mark:
5968 if mark:
5964 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
5969 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED_PATH)
5965 elif unmark:
5970 elif unmark:
5966 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
5971 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED_PATH)
5967 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
5972 elif ms[f] == mergestatemod.MERGE_RECORD_UNRESOLVED_PATH:
5968 ui.warn(
5973 ui.warn(
5969 _(b'%s: path conflict must be resolved manually\n')
5974 _(b'%s: path conflict must be resolved manually\n')
5970 % uipathfn(f)
5975 % uipathfn(f)
5971 )
5976 )
5972 continue
5977 continue
5973
5978
5974 if mark:
5979 if mark:
5975 if markcheck:
5980 if markcheck:
5976 fdata = repo.wvfs.tryread(f)
5981 fdata = repo.wvfs.tryread(f)
5977 if (
5982 if (
5978 filemerge.hasconflictmarkers(fdata)
5983 filemerge.hasconflictmarkers(fdata)
5979 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
5984 and ms[f] != mergestatemod.MERGE_RECORD_RESOLVED
5980 ):
5985 ):
5981 hasconflictmarkers.append(f)
5986 hasconflictmarkers.append(f)
5982 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
5987 ms.mark(f, mergestatemod.MERGE_RECORD_RESOLVED)
5983 elif unmark:
5988 elif unmark:
5984 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
5989 ms.mark(f, mergestatemod.MERGE_RECORD_UNRESOLVED)
5985 else:
5990 else:
5986 # backup pre-resolve (merge uses .orig for its own purposes)
5991 # backup pre-resolve (merge uses .orig for its own purposes)
5987 a = repo.wjoin(f)
5992 a = repo.wjoin(f)
5988 try:
5993 try:
5989 util.copyfile(a, a + b".resolve")
5994 util.copyfile(a, a + b".resolve")
5990 except (IOError, OSError) as inst:
5995 except (IOError, OSError) as inst:
5991 if inst.errno != errno.ENOENT:
5996 if inst.errno != errno.ENOENT:
5992 raise
5997 raise
5993
5998
5994 try:
5999 try:
5995 # preresolve file
6000 # preresolve file
5996 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6001 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
5997 with ui.configoverride(overrides, b'resolve'):
6002 with ui.configoverride(overrides, b'resolve'):
5998 complete, r = ms.preresolve(f, wctx)
6003 complete, r = ms.preresolve(f, wctx)
5999 if not complete:
6004 if not complete:
6000 tocomplete.append(f)
6005 tocomplete.append(f)
6001 elif r:
6006 elif r:
6002 ret = 1
6007 ret = 1
6003 finally:
6008 finally:
6004 ms.commit()
6009 ms.commit()
6005
6010
6006 # replace filemerge's .orig file with our resolve file, but only
6011 # replace filemerge's .orig file with our resolve file, but only
6007 # for merges that are complete
6012 # for merges that are complete
6008 if complete:
6013 if complete:
6009 try:
6014 try:
6010 util.rename(
6015 util.rename(
6011 a + b".resolve", scmutil.backuppath(ui, repo, f)
6016 a + b".resolve", scmutil.backuppath(ui, repo, f)
6012 )
6017 )
6013 except OSError as inst:
6018 except OSError as inst:
6014 if inst.errno != errno.ENOENT:
6019 if inst.errno != errno.ENOENT:
6015 raise
6020 raise
6016
6021
6017 if hasconflictmarkers:
6022 if hasconflictmarkers:
6018 ui.warn(
6023 ui.warn(
6019 _(
6024 _(
6020 b'warning: the following files still have conflict '
6025 b'warning: the following files still have conflict '
6021 b'markers:\n'
6026 b'markers:\n'
6022 )
6027 )
6023 + b''.join(
6028 + b''.join(
6024 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6029 b' ' + uipathfn(f) + b'\n' for f in hasconflictmarkers
6025 )
6030 )
6026 )
6031 )
6027 if markcheck == b'abort' and not all and not pats:
6032 if markcheck == b'abort' and not all and not pats:
6028 raise error.StateError(
6033 raise error.StateError(
6029 _(b'conflict markers detected'),
6034 _(b'conflict markers detected'),
6030 hint=_(b'use --all to mark anyway'),
6035 hint=_(b'use --all to mark anyway'),
6031 )
6036 )
6032
6037
6033 for f in tocomplete:
6038 for f in tocomplete:
6034 try:
6039 try:
6035 # resolve file
6040 # resolve file
6036 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6041 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
6037 with ui.configoverride(overrides, b'resolve'):
6042 with ui.configoverride(overrides, b'resolve'):
6038 r = ms.resolve(f, wctx)
6043 r = ms.resolve(f, wctx)
6039 if r:
6044 if r:
6040 ret = 1
6045 ret = 1
6041 finally:
6046 finally:
6042 ms.commit()
6047 ms.commit()
6043
6048
6044 # replace filemerge's .orig file with our resolve file
6049 # replace filemerge's .orig file with our resolve file
6045 a = repo.wjoin(f)
6050 a = repo.wjoin(f)
6046 try:
6051 try:
6047 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6052 util.rename(a + b".resolve", scmutil.backuppath(ui, repo, f))
6048 except OSError as inst:
6053 except OSError as inst:
6049 if inst.errno != errno.ENOENT:
6054 if inst.errno != errno.ENOENT:
6050 raise
6055 raise
6051
6056
6052 ms.commit()
6057 ms.commit()
6053 branchmerge = repo.dirstate.p2() != nullid
6058 branchmerge = repo.dirstate.p2() != nullid
6054 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6059 mergestatemod.recordupdates(repo, ms.actions(), branchmerge, None)
6055
6060
6056 if not didwork and pats:
6061 if not didwork and pats:
6057 hint = None
6062 hint = None
6058 if not any([p for p in pats if p.find(b':') >= 0]):
6063 if not any([p for p in pats if p.find(b':') >= 0]):
6059 pats = [b'path:%s' % p for p in pats]
6064 pats = [b'path:%s' % p for p in pats]
6060 m = scmutil.match(wctx, pats, opts)
6065 m = scmutil.match(wctx, pats, opts)
6061 for f in ms:
6066 for f in ms:
6062 if not m(f):
6067 if not m(f):
6063 continue
6068 continue
6064
6069
6065 def flag(o):
6070 def flag(o):
6066 if o == b're_merge':
6071 if o == b're_merge':
6067 return b'--re-merge '
6072 return b'--re-merge '
6068 return b'-%s ' % o[0:1]
6073 return b'-%s ' % o[0:1]
6069
6074
6070 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6075 flags = b''.join([flag(o) for o in flaglist if opts.get(o)])
6071 hint = _(b"(try: hg resolve %s%s)\n") % (
6076 hint = _(b"(try: hg resolve %s%s)\n") % (
6072 flags,
6077 flags,
6073 b' '.join(pats),
6078 b' '.join(pats),
6074 )
6079 )
6075 break
6080 break
6076 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6081 ui.warn(_(b"arguments do not match paths that need resolving\n"))
6077 if hint:
6082 if hint:
6078 ui.warn(hint)
6083 ui.warn(hint)
6079
6084
6080 unresolvedf = list(ms.unresolved())
6085 unresolvedf = list(ms.unresolved())
6081 if not unresolvedf:
6086 if not unresolvedf:
6082 ui.status(_(b'(no more unresolved files)\n'))
6087 ui.status(_(b'(no more unresolved files)\n'))
6083 cmdutil.checkafterresolved(repo)
6088 cmdutil.checkafterresolved(repo)
6084
6089
6085 return ret
6090 return ret
6086
6091
6087
6092
6088 @command(
6093 @command(
6089 b'revert',
6094 b'revert',
6090 [
6095 [
6091 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6096 (b'a', b'all', None, _(b'revert all changes when no arguments given')),
6092 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6097 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
6093 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6098 (b'r', b'rev', b'', _(b'revert to the specified revision'), _(b'REV')),
6094 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6099 (b'C', b'no-backup', None, _(b'do not save backup copies of files')),
6095 (b'i', b'interactive', None, _(b'interactively select the changes')),
6100 (b'i', b'interactive', None, _(b'interactively select the changes')),
6096 ]
6101 ]
6097 + walkopts
6102 + walkopts
6098 + dryrunopts,
6103 + dryrunopts,
6099 _(b'[OPTION]... [-r REV] [NAME]...'),
6104 _(b'[OPTION]... [-r REV] [NAME]...'),
6100 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6105 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6101 )
6106 )
6102 def revert(ui, repo, *pats, **opts):
6107 def revert(ui, repo, *pats, **opts):
6103 """restore files to their checkout state
6108 """restore files to their checkout state
6104
6109
6105 .. note::
6110 .. note::
6106
6111
6107 To check out earlier revisions, you should use :hg:`update REV`.
6112 To check out earlier revisions, you should use :hg:`update REV`.
6108 To cancel an uncommitted merge (and lose your changes),
6113 To cancel an uncommitted merge (and lose your changes),
6109 use :hg:`merge --abort`.
6114 use :hg:`merge --abort`.
6110
6115
6111 With no revision specified, revert the specified files or directories
6116 With no revision specified, revert the specified files or directories
6112 to the contents they had in the parent of the working directory.
6117 to the contents they had in the parent of the working directory.
6113 This restores the contents of files to an unmodified
6118 This restores the contents of files to an unmodified
6114 state and unschedules adds, removes, copies, and renames. If the
6119 state and unschedules adds, removes, copies, and renames. If the
6115 working directory has two parents, you must explicitly specify a
6120 working directory has two parents, you must explicitly specify a
6116 revision.
6121 revision.
6117
6122
6118 Using the -r/--rev or -d/--date options, revert the given files or
6123 Using the -r/--rev or -d/--date options, revert the given files or
6119 directories to their states as of a specific revision. Because
6124 directories to their states as of a specific revision. Because
6120 revert does not change the working directory parents, this will
6125 revert does not change the working directory parents, this will
6121 cause these files to appear modified. This can be helpful to "back
6126 cause these files to appear modified. This can be helpful to "back
6122 out" some or all of an earlier change. See :hg:`backout` for a
6127 out" some or all of an earlier change. See :hg:`backout` for a
6123 related method.
6128 related method.
6124
6129
6125 Modified files are saved with a .orig suffix before reverting.
6130 Modified files are saved with a .orig suffix before reverting.
6126 To disable these backups, use --no-backup. It is possible to store
6131 To disable these backups, use --no-backup. It is possible to store
6127 the backup files in a custom directory relative to the root of the
6132 the backup files in a custom directory relative to the root of the
6128 repository by setting the ``ui.origbackuppath`` configuration
6133 repository by setting the ``ui.origbackuppath`` configuration
6129 option.
6134 option.
6130
6135
6131 See :hg:`help dates` for a list of formats valid for -d/--date.
6136 See :hg:`help dates` for a list of formats valid for -d/--date.
6132
6137
6133 See :hg:`help backout` for a way to reverse the effect of an
6138 See :hg:`help backout` for a way to reverse the effect of an
6134 earlier changeset.
6139 earlier changeset.
6135
6140
6136 Returns 0 on success.
6141 Returns 0 on success.
6137 """
6142 """
6138
6143
6139 opts = pycompat.byteskwargs(opts)
6144 opts = pycompat.byteskwargs(opts)
6140 if opts.get(b"date"):
6145 if opts.get(b"date"):
6141 cmdutil.check_incompatible_arguments(opts, b'date', [b'rev'])
6146 cmdutil.check_incompatible_arguments(opts, b'date', [b'rev'])
6142 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6147 opts[b"rev"] = cmdutil.finddate(ui, repo, opts[b"date"])
6143
6148
6144 parent, p2 = repo.dirstate.parents()
6149 parent, p2 = repo.dirstate.parents()
6145 if not opts.get(b'rev') and p2 != nullid:
6150 if not opts.get(b'rev') and p2 != nullid:
6146 # revert after merge is a trap for new users (issue2915)
6151 # revert after merge is a trap for new users (issue2915)
6147 raise error.InputError(
6152 raise error.InputError(
6148 _(b'uncommitted merge with no revision specified'),
6153 _(b'uncommitted merge with no revision specified'),
6149 hint=_(b"use 'hg update' or see 'hg help revert'"),
6154 hint=_(b"use 'hg update' or see 'hg help revert'"),
6150 )
6155 )
6151
6156
6152 rev = opts.get(b'rev')
6157 rev = opts.get(b'rev')
6153 if rev:
6158 if rev:
6154 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6159 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
6155 ctx = scmutil.revsingle(repo, rev)
6160 ctx = scmutil.revsingle(repo, rev)
6156
6161
6157 if not (
6162 if not (
6158 pats
6163 pats
6159 or opts.get(b'include')
6164 or opts.get(b'include')
6160 or opts.get(b'exclude')
6165 or opts.get(b'exclude')
6161 or opts.get(b'all')
6166 or opts.get(b'all')
6162 or opts.get(b'interactive')
6167 or opts.get(b'interactive')
6163 ):
6168 ):
6164 msg = _(b"no files or directories specified")
6169 msg = _(b"no files or directories specified")
6165 if p2 != nullid:
6170 if p2 != nullid:
6166 hint = _(
6171 hint = _(
6167 b"uncommitted merge, use --all to discard all changes,"
6172 b"uncommitted merge, use --all to discard all changes,"
6168 b" or 'hg update -C .' to abort the merge"
6173 b" or 'hg update -C .' to abort the merge"
6169 )
6174 )
6170 raise error.InputError(msg, hint=hint)
6175 raise error.InputError(msg, hint=hint)
6171 dirty = any(repo.status())
6176 dirty = any(repo.status())
6172 node = ctx.node()
6177 node = ctx.node()
6173 if node != parent:
6178 if node != parent:
6174 if dirty:
6179 if dirty:
6175 hint = (
6180 hint = (
6176 _(
6181 _(
6177 b"uncommitted changes, use --all to discard all"
6182 b"uncommitted changes, use --all to discard all"
6178 b" changes, or 'hg update %d' to update"
6183 b" changes, or 'hg update %d' to update"
6179 )
6184 )
6180 % ctx.rev()
6185 % ctx.rev()
6181 )
6186 )
6182 else:
6187 else:
6183 hint = (
6188 hint = (
6184 _(
6189 _(
6185 b"use --all to revert all files,"
6190 b"use --all to revert all files,"
6186 b" or 'hg update %d' to update"
6191 b" or 'hg update %d' to update"
6187 )
6192 )
6188 % ctx.rev()
6193 % ctx.rev()
6189 )
6194 )
6190 elif dirty:
6195 elif dirty:
6191 hint = _(b"uncommitted changes, use --all to discard all changes")
6196 hint = _(b"uncommitted changes, use --all to discard all changes")
6192 else:
6197 else:
6193 hint = _(b"use --all to revert all files")
6198 hint = _(b"use --all to revert all files")
6194 raise error.InputError(msg, hint=hint)
6199 raise error.InputError(msg, hint=hint)
6195
6200
6196 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6201 return cmdutil.revert(ui, repo, ctx, *pats, **pycompat.strkwargs(opts))
6197
6202
6198
6203
6199 @command(
6204 @command(
6200 b'rollback',
6205 b'rollback',
6201 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6206 dryrunopts + [(b'f', b'force', False, _(b'ignore safety measures'))],
6202 helpcategory=command.CATEGORY_MAINTENANCE,
6207 helpcategory=command.CATEGORY_MAINTENANCE,
6203 )
6208 )
6204 def rollback(ui, repo, **opts):
6209 def rollback(ui, repo, **opts):
6205 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6210 """roll back the last transaction (DANGEROUS) (DEPRECATED)
6206
6211
6207 Please use :hg:`commit --amend` instead of rollback to correct
6212 Please use :hg:`commit --amend` instead of rollback to correct
6208 mistakes in the last commit.
6213 mistakes in the last commit.
6209
6214
6210 This command should be used with care. There is only one level of
6215 This command should be used with care. There is only one level of
6211 rollback, and there is no way to undo a rollback. It will also
6216 rollback, and there is no way to undo a rollback. It will also
6212 restore the dirstate at the time of the last transaction, losing
6217 restore the dirstate at the time of the last transaction, losing
6213 any dirstate changes since that time. This command does not alter
6218 any dirstate changes since that time. This command does not alter
6214 the working directory.
6219 the working directory.
6215
6220
6216 Transactions are used to encapsulate the effects of all commands
6221 Transactions are used to encapsulate the effects of all commands
6217 that create new changesets or propagate existing changesets into a
6222 that create new changesets or propagate existing changesets into a
6218 repository.
6223 repository.
6219
6224
6220 .. container:: verbose
6225 .. container:: verbose
6221
6226
6222 For example, the following commands are transactional, and their
6227 For example, the following commands are transactional, and their
6223 effects can be rolled back:
6228 effects can be rolled back:
6224
6229
6225 - commit
6230 - commit
6226 - import
6231 - import
6227 - pull
6232 - pull
6228 - push (with this repository as the destination)
6233 - push (with this repository as the destination)
6229 - unbundle
6234 - unbundle
6230
6235
6231 To avoid permanent data loss, rollback will refuse to rollback a
6236 To avoid permanent data loss, rollback will refuse to rollback a
6232 commit transaction if it isn't checked out. Use --force to
6237 commit transaction if it isn't checked out. Use --force to
6233 override this protection.
6238 override this protection.
6234
6239
6235 The rollback command can be entirely disabled by setting the
6240 The rollback command can be entirely disabled by setting the
6236 ``ui.rollback`` configuration setting to false. If you're here
6241 ``ui.rollback`` configuration setting to false. If you're here
6237 because you want to use rollback and it's disabled, you can
6242 because you want to use rollback and it's disabled, you can
6238 re-enable the command by setting ``ui.rollback`` to true.
6243 re-enable the command by setting ``ui.rollback`` to true.
6239
6244
6240 This command is not intended for use on public repositories. Once
6245 This command is not intended for use on public repositories. Once
6241 changes are visible for pull by other users, rolling a transaction
6246 changes are visible for pull by other users, rolling a transaction
6242 back locally is ineffective (someone else may already have pulled
6247 back locally is ineffective (someone else may already have pulled
6243 the changes). Furthermore, a race is possible with readers of the
6248 the changes). Furthermore, a race is possible with readers of the
6244 repository; for example an in-progress pull from the repository
6249 repository; for example an in-progress pull from the repository
6245 may fail if a rollback is performed.
6250 may fail if a rollback is performed.
6246
6251
6247 Returns 0 on success, 1 if no rollback data is available.
6252 Returns 0 on success, 1 if no rollback data is available.
6248 """
6253 """
6249 if not ui.configbool(b'ui', b'rollback'):
6254 if not ui.configbool(b'ui', b'rollback'):
6250 raise error.Abort(
6255 raise error.Abort(
6251 _(b'rollback is disabled because it is unsafe'),
6256 _(b'rollback is disabled because it is unsafe'),
6252 hint=b'see `hg help -v rollback` for information',
6257 hint=b'see `hg help -v rollback` for information',
6253 )
6258 )
6254 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6259 return repo.rollback(dryrun=opts.get('dry_run'), force=opts.get('force'))
6255
6260
6256
6261
6257 @command(
6262 @command(
6258 b'root',
6263 b'root',
6259 [] + formatteropts,
6264 [] + formatteropts,
6260 intents={INTENT_READONLY},
6265 intents={INTENT_READONLY},
6261 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6266 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6262 )
6267 )
6263 def root(ui, repo, **opts):
6268 def root(ui, repo, **opts):
6264 """print the root (top) of the current working directory
6269 """print the root (top) of the current working directory
6265
6270
6266 Print the root directory of the current repository.
6271 Print the root directory of the current repository.
6267
6272
6268 .. container:: verbose
6273 .. container:: verbose
6269
6274
6270 Template:
6275 Template:
6271
6276
6272 The following keywords are supported in addition to the common template
6277 The following keywords are supported in addition to the common template
6273 keywords and functions. See also :hg:`help templates`.
6278 keywords and functions. See also :hg:`help templates`.
6274
6279
6275 :hgpath: String. Path to the .hg directory.
6280 :hgpath: String. Path to the .hg directory.
6276 :storepath: String. Path to the directory holding versioned data.
6281 :storepath: String. Path to the directory holding versioned data.
6277
6282
6278 Returns 0 on success.
6283 Returns 0 on success.
6279 """
6284 """
6280 opts = pycompat.byteskwargs(opts)
6285 opts = pycompat.byteskwargs(opts)
6281 with ui.formatter(b'root', opts) as fm:
6286 with ui.formatter(b'root', opts) as fm:
6282 fm.startitem()
6287 fm.startitem()
6283 fm.write(b'reporoot', b'%s\n', repo.root)
6288 fm.write(b'reporoot', b'%s\n', repo.root)
6284 fm.data(hgpath=repo.path, storepath=repo.spath)
6289 fm.data(hgpath=repo.path, storepath=repo.spath)
6285
6290
6286
6291
6287 @command(
6292 @command(
6288 b'serve',
6293 b'serve',
6289 [
6294 [
6290 (
6295 (
6291 b'A',
6296 b'A',
6292 b'accesslog',
6297 b'accesslog',
6293 b'',
6298 b'',
6294 _(b'name of access log file to write to'),
6299 _(b'name of access log file to write to'),
6295 _(b'FILE'),
6300 _(b'FILE'),
6296 ),
6301 ),
6297 (b'd', b'daemon', None, _(b'run server in background')),
6302 (b'd', b'daemon', None, _(b'run server in background')),
6298 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6303 (b'', b'daemon-postexec', [], _(b'used internally by daemon mode')),
6299 (
6304 (
6300 b'E',
6305 b'E',
6301 b'errorlog',
6306 b'errorlog',
6302 b'',
6307 b'',
6303 _(b'name of error log file to write to'),
6308 _(b'name of error log file to write to'),
6304 _(b'FILE'),
6309 _(b'FILE'),
6305 ),
6310 ),
6306 # use string type, then we can check if something was passed
6311 # use string type, then we can check if something was passed
6307 (
6312 (
6308 b'p',
6313 b'p',
6309 b'port',
6314 b'port',
6310 b'',
6315 b'',
6311 _(b'port to listen on (default: 8000)'),
6316 _(b'port to listen on (default: 8000)'),
6312 _(b'PORT'),
6317 _(b'PORT'),
6313 ),
6318 ),
6314 (
6319 (
6315 b'a',
6320 b'a',
6316 b'address',
6321 b'address',
6317 b'',
6322 b'',
6318 _(b'address to listen on (default: all interfaces)'),
6323 _(b'address to listen on (default: all interfaces)'),
6319 _(b'ADDR'),
6324 _(b'ADDR'),
6320 ),
6325 ),
6321 (
6326 (
6322 b'',
6327 b'',
6323 b'prefix',
6328 b'prefix',
6324 b'',
6329 b'',
6325 _(b'prefix path to serve from (default: server root)'),
6330 _(b'prefix path to serve from (default: server root)'),
6326 _(b'PREFIX'),
6331 _(b'PREFIX'),
6327 ),
6332 ),
6328 (
6333 (
6329 b'n',
6334 b'n',
6330 b'name',
6335 b'name',
6331 b'',
6336 b'',
6332 _(b'name to show in web pages (default: working directory)'),
6337 _(b'name to show in web pages (default: working directory)'),
6333 _(b'NAME'),
6338 _(b'NAME'),
6334 ),
6339 ),
6335 (
6340 (
6336 b'',
6341 b'',
6337 b'web-conf',
6342 b'web-conf',
6338 b'',
6343 b'',
6339 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6344 _(b"name of the hgweb config file (see 'hg help hgweb')"),
6340 _(b'FILE'),
6345 _(b'FILE'),
6341 ),
6346 ),
6342 (
6347 (
6343 b'',
6348 b'',
6344 b'webdir-conf',
6349 b'webdir-conf',
6345 b'',
6350 b'',
6346 _(b'name of the hgweb config file (DEPRECATED)'),
6351 _(b'name of the hgweb config file (DEPRECATED)'),
6347 _(b'FILE'),
6352 _(b'FILE'),
6348 ),
6353 ),
6349 (
6354 (
6350 b'',
6355 b'',
6351 b'pid-file',
6356 b'pid-file',
6352 b'',
6357 b'',
6353 _(b'name of file to write process ID to'),
6358 _(b'name of file to write process ID to'),
6354 _(b'FILE'),
6359 _(b'FILE'),
6355 ),
6360 ),
6356 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6361 (b'', b'stdio', None, _(b'for remote clients (ADVANCED)')),
6357 (
6362 (
6358 b'',
6363 b'',
6359 b'cmdserver',
6364 b'cmdserver',
6360 b'',
6365 b'',
6361 _(b'for remote clients (ADVANCED)'),
6366 _(b'for remote clients (ADVANCED)'),
6362 _(b'MODE'),
6367 _(b'MODE'),
6363 ),
6368 ),
6364 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6369 (b't', b'templates', b'', _(b'web templates to use'), _(b'TEMPLATE')),
6365 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6370 (b'', b'style', b'', _(b'template style to use'), _(b'STYLE')),
6366 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6371 (b'6', b'ipv6', None, _(b'use IPv6 in addition to IPv4')),
6367 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6372 (b'', b'certificate', b'', _(b'SSL certificate file'), _(b'FILE')),
6368 (b'', b'print-url', None, _(b'start and print only the URL')),
6373 (b'', b'print-url', None, _(b'start and print only the URL')),
6369 ]
6374 ]
6370 + subrepoopts,
6375 + subrepoopts,
6371 _(b'[OPTION]...'),
6376 _(b'[OPTION]...'),
6372 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6377 helpcategory=command.CATEGORY_REMOTE_REPO_MANAGEMENT,
6373 helpbasic=True,
6378 helpbasic=True,
6374 optionalrepo=True,
6379 optionalrepo=True,
6375 )
6380 )
6376 def serve(ui, repo, **opts):
6381 def serve(ui, repo, **opts):
6377 """start stand-alone webserver
6382 """start stand-alone webserver
6378
6383
6379 Start a local HTTP repository browser and pull server. You can use
6384 Start a local HTTP repository browser and pull server. You can use
6380 this for ad-hoc sharing and browsing of repositories. It is
6385 this for ad-hoc sharing and browsing of repositories. It is
6381 recommended to use a real web server to serve a repository for
6386 recommended to use a real web server to serve a repository for
6382 longer periods of time.
6387 longer periods of time.
6383
6388
6384 Please note that the server does not implement access control.
6389 Please note that the server does not implement access control.
6385 This means that, by default, anybody can read from the server and
6390 This means that, by default, anybody can read from the server and
6386 nobody can write to it by default. Set the ``web.allow-push``
6391 nobody can write to it by default. Set the ``web.allow-push``
6387 option to ``*`` to allow everybody to push to the server. You
6392 option to ``*`` to allow everybody to push to the server. You
6388 should use a real web server if you need to authenticate users.
6393 should use a real web server if you need to authenticate users.
6389
6394
6390 By default, the server logs accesses to stdout and errors to
6395 By default, the server logs accesses to stdout and errors to
6391 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6396 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
6392 files.
6397 files.
6393
6398
6394 To have the server choose a free port number to listen on, specify
6399 To have the server choose a free port number to listen on, specify
6395 a port number of 0; in this case, the server will print the port
6400 a port number of 0; in this case, the server will print the port
6396 number it uses.
6401 number it uses.
6397
6402
6398 Returns 0 on success.
6403 Returns 0 on success.
6399 """
6404 """
6400
6405
6401 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6406 cmdutil.check_incompatible_arguments(opts, 'stdio', ['cmdserver'])
6402 opts = pycompat.byteskwargs(opts)
6407 opts = pycompat.byteskwargs(opts)
6403 if opts[b"print_url"] and ui.verbose:
6408 if opts[b"print_url"] and ui.verbose:
6404 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6409 raise error.InputError(_(b"cannot use --print-url with --verbose"))
6405
6410
6406 if opts[b"stdio"]:
6411 if opts[b"stdio"]:
6407 if repo is None:
6412 if repo is None:
6408 raise error.RepoError(
6413 raise error.RepoError(
6409 _(b"there is no Mercurial repository here (.hg not found)")
6414 _(b"there is no Mercurial repository here (.hg not found)")
6410 )
6415 )
6411 s = wireprotoserver.sshserver(ui, repo)
6416 s = wireprotoserver.sshserver(ui, repo)
6412 s.serve_forever()
6417 s.serve_forever()
6413 return
6418 return
6414
6419
6415 service = server.createservice(ui, repo, opts)
6420 service = server.createservice(ui, repo, opts)
6416 return server.runservice(opts, initfn=service.init, runfn=service.run)
6421 return server.runservice(opts, initfn=service.init, runfn=service.run)
6417
6422
6418
6423
6419 @command(
6424 @command(
6420 b'shelve',
6425 b'shelve',
6421 [
6426 [
6422 (
6427 (
6423 b'A',
6428 b'A',
6424 b'addremove',
6429 b'addremove',
6425 None,
6430 None,
6426 _(b'mark new/missing files as added/removed before shelving'),
6431 _(b'mark new/missing files as added/removed before shelving'),
6427 ),
6432 ),
6428 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6433 (b'u', b'unknown', None, _(b'store unknown files in the shelve')),
6429 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6434 (b'', b'cleanup', None, _(b'delete all shelved changes')),
6430 (
6435 (
6431 b'',
6436 b'',
6432 b'date',
6437 b'date',
6433 b'',
6438 b'',
6434 _(b'shelve with the specified commit date'),
6439 _(b'shelve with the specified commit date'),
6435 _(b'DATE'),
6440 _(b'DATE'),
6436 ),
6441 ),
6437 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6442 (b'd', b'delete', None, _(b'delete the named shelved change(s)')),
6438 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6443 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
6439 (
6444 (
6440 b'k',
6445 b'k',
6441 b'keep',
6446 b'keep',
6442 False,
6447 False,
6443 _(b'shelve, but keep changes in the working directory'),
6448 _(b'shelve, but keep changes in the working directory'),
6444 ),
6449 ),
6445 (b'l', b'list', None, _(b'list current shelves')),
6450 (b'l', b'list', None, _(b'list current shelves')),
6446 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6451 (b'm', b'message', b'', _(b'use text as shelve message'), _(b'TEXT')),
6447 (
6452 (
6448 b'n',
6453 b'n',
6449 b'name',
6454 b'name',
6450 b'',
6455 b'',
6451 _(b'use the given name for the shelved commit'),
6456 _(b'use the given name for the shelved commit'),
6452 _(b'NAME'),
6457 _(b'NAME'),
6453 ),
6458 ),
6454 (
6459 (
6455 b'p',
6460 b'p',
6456 b'patch',
6461 b'patch',
6457 None,
6462 None,
6458 _(
6463 _(
6459 b'output patches for changes (provide the names of the shelved '
6464 b'output patches for changes (provide the names of the shelved '
6460 b'changes as positional arguments)'
6465 b'changes as positional arguments)'
6461 ),
6466 ),
6462 ),
6467 ),
6463 (b'i', b'interactive', None, _(b'interactive mode')),
6468 (b'i', b'interactive', None, _(b'interactive mode')),
6464 (
6469 (
6465 b'',
6470 b'',
6466 b'stat',
6471 b'stat',
6467 None,
6472 None,
6468 _(
6473 _(
6469 b'output diffstat-style summary of changes (provide the names of '
6474 b'output diffstat-style summary of changes (provide the names of '
6470 b'the shelved changes as positional arguments)'
6475 b'the shelved changes as positional arguments)'
6471 ),
6476 ),
6472 ),
6477 ),
6473 ]
6478 ]
6474 + cmdutil.walkopts,
6479 + cmdutil.walkopts,
6475 _(b'hg shelve [OPTION]... [FILE]...'),
6480 _(b'hg shelve [OPTION]... [FILE]...'),
6476 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6481 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6477 )
6482 )
6478 def shelve(ui, repo, *pats, **opts):
6483 def shelve(ui, repo, *pats, **opts):
6479 """save and set aside changes from the working directory
6484 """save and set aside changes from the working directory
6480
6485
6481 Shelving takes files that "hg status" reports as not clean, saves
6486 Shelving takes files that "hg status" reports as not clean, saves
6482 the modifications to a bundle (a shelved change), and reverts the
6487 the modifications to a bundle (a shelved change), and reverts the
6483 files so that their state in the working directory becomes clean.
6488 files so that their state in the working directory becomes clean.
6484
6489
6485 To restore these changes to the working directory, using "hg
6490 To restore these changes to the working directory, using "hg
6486 unshelve"; this will work even if you switch to a different
6491 unshelve"; this will work even if you switch to a different
6487 commit.
6492 commit.
6488
6493
6489 When no files are specified, "hg shelve" saves all not-clean
6494 When no files are specified, "hg shelve" saves all not-clean
6490 files. If specific files or directories are named, only changes to
6495 files. If specific files or directories are named, only changes to
6491 those files are shelved.
6496 those files are shelved.
6492
6497
6493 In bare shelve (when no files are specified, without interactive,
6498 In bare shelve (when no files are specified, without interactive,
6494 include and exclude option), shelving remembers information if the
6499 include and exclude option), shelving remembers information if the
6495 working directory was on newly created branch, in other words working
6500 working directory was on newly created branch, in other words working
6496 directory was on different branch than its first parent. In this
6501 directory was on different branch than its first parent. In this
6497 situation unshelving restores branch information to the working directory.
6502 situation unshelving restores branch information to the working directory.
6498
6503
6499 Each shelved change has a name that makes it easier to find later.
6504 Each shelved change has a name that makes it easier to find later.
6500 The name of a shelved change defaults to being based on the active
6505 The name of a shelved change defaults to being based on the active
6501 bookmark, or if there is no active bookmark, the current named
6506 bookmark, or if there is no active bookmark, the current named
6502 branch. To specify a different name, use ``--name``.
6507 branch. To specify a different name, use ``--name``.
6503
6508
6504 To see a list of existing shelved changes, use the ``--list``
6509 To see a list of existing shelved changes, use the ``--list``
6505 option. For each shelved change, this will print its name, age,
6510 option. For each shelved change, this will print its name, age,
6506 and description; use ``--patch`` or ``--stat`` for more details.
6511 and description; use ``--patch`` or ``--stat`` for more details.
6507
6512
6508 To delete specific shelved changes, use ``--delete``. To delete
6513 To delete specific shelved changes, use ``--delete``. To delete
6509 all shelved changes, use ``--cleanup``.
6514 all shelved changes, use ``--cleanup``.
6510 """
6515 """
6511 opts = pycompat.byteskwargs(opts)
6516 opts = pycompat.byteskwargs(opts)
6512 allowables = [
6517 allowables = [
6513 (b'addremove', {b'create'}), # 'create' is pseudo action
6518 (b'addremove', {b'create'}), # 'create' is pseudo action
6514 (b'unknown', {b'create'}),
6519 (b'unknown', {b'create'}),
6515 (b'cleanup', {b'cleanup'}),
6520 (b'cleanup', {b'cleanup'}),
6516 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6521 # ('date', {'create'}), # ignored for passing '--date "0 0"' in tests
6517 (b'delete', {b'delete'}),
6522 (b'delete', {b'delete'}),
6518 (b'edit', {b'create'}),
6523 (b'edit', {b'create'}),
6519 (b'keep', {b'create'}),
6524 (b'keep', {b'create'}),
6520 (b'list', {b'list'}),
6525 (b'list', {b'list'}),
6521 (b'message', {b'create'}),
6526 (b'message', {b'create'}),
6522 (b'name', {b'create'}),
6527 (b'name', {b'create'}),
6523 (b'patch', {b'patch', b'list'}),
6528 (b'patch', {b'patch', b'list'}),
6524 (b'stat', {b'stat', b'list'}),
6529 (b'stat', {b'stat', b'list'}),
6525 ]
6530 ]
6526
6531
6527 def checkopt(opt):
6532 def checkopt(opt):
6528 if opts.get(opt):
6533 if opts.get(opt):
6529 for i, allowable in allowables:
6534 for i, allowable in allowables:
6530 if opts[i] and opt not in allowable:
6535 if opts[i] and opt not in allowable:
6531 raise error.InputError(
6536 raise error.InputError(
6532 _(
6537 _(
6533 b"options '--%s' and '--%s' may not be "
6538 b"options '--%s' and '--%s' may not be "
6534 b"used together"
6539 b"used together"
6535 )
6540 )
6536 % (opt, i)
6541 % (opt, i)
6537 )
6542 )
6538 return True
6543 return True
6539
6544
6540 if checkopt(b'cleanup'):
6545 if checkopt(b'cleanup'):
6541 if pats:
6546 if pats:
6542 raise error.InputError(
6547 raise error.InputError(
6543 _(b"cannot specify names when using '--cleanup'")
6548 _(b"cannot specify names when using '--cleanup'")
6544 )
6549 )
6545 return shelvemod.cleanupcmd(ui, repo)
6550 return shelvemod.cleanupcmd(ui, repo)
6546 elif checkopt(b'delete'):
6551 elif checkopt(b'delete'):
6547 return shelvemod.deletecmd(ui, repo, pats)
6552 return shelvemod.deletecmd(ui, repo, pats)
6548 elif checkopt(b'list'):
6553 elif checkopt(b'list'):
6549 return shelvemod.listcmd(ui, repo, pats, opts)
6554 return shelvemod.listcmd(ui, repo, pats, opts)
6550 elif checkopt(b'patch') or checkopt(b'stat'):
6555 elif checkopt(b'patch') or checkopt(b'stat'):
6551 return shelvemod.patchcmds(ui, repo, pats, opts)
6556 return shelvemod.patchcmds(ui, repo, pats, opts)
6552 else:
6557 else:
6553 return shelvemod.createcmd(ui, repo, pats, opts)
6558 return shelvemod.createcmd(ui, repo, pats, opts)
6554
6559
6555
6560
6556 _NOTTERSE = b'nothing'
6561 _NOTTERSE = b'nothing'
6557
6562
6558
6563
6559 @command(
6564 @command(
6560 b'status|st',
6565 b'status|st',
6561 [
6566 [
6562 (b'A', b'all', None, _(b'show status of all files')),
6567 (b'A', b'all', None, _(b'show status of all files')),
6563 (b'm', b'modified', None, _(b'show only modified files')),
6568 (b'm', b'modified', None, _(b'show only modified files')),
6564 (b'a', b'added', None, _(b'show only added files')),
6569 (b'a', b'added', None, _(b'show only added files')),
6565 (b'r', b'removed', None, _(b'show only removed files')),
6570 (b'r', b'removed', None, _(b'show only removed files')),
6566 (b'd', b'deleted', None, _(b'show only missing files')),
6571 (b'd', b'deleted', None, _(b'show only missing files')),
6567 (b'c', b'clean', None, _(b'show only files without changes')),
6572 (b'c', b'clean', None, _(b'show only files without changes')),
6568 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6573 (b'u', b'unknown', None, _(b'show only unknown (not tracked) files')),
6569 (b'i', b'ignored', None, _(b'show only ignored files')),
6574 (b'i', b'ignored', None, _(b'show only ignored files')),
6570 (b'n', b'no-status', None, _(b'hide status prefix')),
6575 (b'n', b'no-status', None, _(b'hide status prefix')),
6571 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6576 (b't', b'terse', _NOTTERSE, _(b'show the terse output (EXPERIMENTAL)')),
6572 (
6577 (
6573 b'C',
6578 b'C',
6574 b'copies',
6579 b'copies',
6575 None,
6580 None,
6576 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6581 _(b'show source of copied files (DEFAULT: ui.statuscopies)'),
6577 ),
6582 ),
6578 (
6583 (
6579 b'0',
6584 b'0',
6580 b'print0',
6585 b'print0',
6581 None,
6586 None,
6582 _(b'end filenames with NUL, for use with xargs'),
6587 _(b'end filenames with NUL, for use with xargs'),
6583 ),
6588 ),
6584 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6589 (b'', b'rev', [], _(b'show difference from revision'), _(b'REV')),
6585 (
6590 (
6586 b'',
6591 b'',
6587 b'change',
6592 b'change',
6588 b'',
6593 b'',
6589 _(b'list the changed files of a revision'),
6594 _(b'list the changed files of a revision'),
6590 _(b'REV'),
6595 _(b'REV'),
6591 ),
6596 ),
6592 ]
6597 ]
6593 + walkopts
6598 + walkopts
6594 + subrepoopts
6599 + subrepoopts
6595 + formatteropts,
6600 + formatteropts,
6596 _(b'[OPTION]... [FILE]...'),
6601 _(b'[OPTION]... [FILE]...'),
6597 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6602 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6598 helpbasic=True,
6603 helpbasic=True,
6599 inferrepo=True,
6604 inferrepo=True,
6600 intents={INTENT_READONLY},
6605 intents={INTENT_READONLY},
6601 )
6606 )
6602 def status(ui, repo, *pats, **opts):
6607 def status(ui, repo, *pats, **opts):
6603 """show changed files in the working directory
6608 """show changed files in the working directory
6604
6609
6605 Show status of files in the repository. If names are given, only
6610 Show status of files in the repository. If names are given, only
6606 files that match are shown. Files that are clean or ignored or
6611 files that match are shown. Files that are clean or ignored or
6607 the source of a copy/move operation, are not listed unless
6612 the source of a copy/move operation, are not listed unless
6608 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6613 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
6609 Unless options described with "show only ..." are given, the
6614 Unless options described with "show only ..." are given, the
6610 options -mardu are used.
6615 options -mardu are used.
6611
6616
6612 Option -q/--quiet hides untracked (unknown and ignored) files
6617 Option -q/--quiet hides untracked (unknown and ignored) files
6613 unless explicitly requested with -u/--unknown or -i/--ignored.
6618 unless explicitly requested with -u/--unknown or -i/--ignored.
6614
6619
6615 .. note::
6620 .. note::
6616
6621
6617 :hg:`status` may appear to disagree with diff if permissions have
6622 :hg:`status` may appear to disagree with diff if permissions have
6618 changed or a merge has occurred. The standard diff format does
6623 changed or a merge has occurred. The standard diff format does
6619 not report permission changes and diff only reports changes
6624 not report permission changes and diff only reports changes
6620 relative to one merge parent.
6625 relative to one merge parent.
6621
6626
6622 If one revision is given, it is used as the base revision.
6627 If one revision is given, it is used as the base revision.
6623 If two revisions are given, the differences between them are
6628 If two revisions are given, the differences between them are
6624 shown. The --change option can also be used as a shortcut to list
6629 shown. The --change option can also be used as a shortcut to list
6625 the changed files of a revision from its first parent.
6630 the changed files of a revision from its first parent.
6626
6631
6627 The codes used to show the status of files are::
6632 The codes used to show the status of files are::
6628
6633
6629 M = modified
6634 M = modified
6630 A = added
6635 A = added
6631 R = removed
6636 R = removed
6632 C = clean
6637 C = clean
6633 ! = missing (deleted by non-hg command, but still tracked)
6638 ! = missing (deleted by non-hg command, but still tracked)
6634 ? = not tracked
6639 ? = not tracked
6635 I = ignored
6640 I = ignored
6636 = origin of the previous file (with --copies)
6641 = origin of the previous file (with --copies)
6637
6642
6638 .. container:: verbose
6643 .. container:: verbose
6639
6644
6640 The -t/--terse option abbreviates the output by showing only the directory
6645 The -t/--terse option abbreviates the output by showing only the directory
6641 name if all the files in it share the same status. The option takes an
6646 name if all the files in it share the same status. The option takes an
6642 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6647 argument indicating the statuses to abbreviate: 'm' for 'modified', 'a'
6643 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6648 for 'added', 'r' for 'removed', 'd' for 'deleted', 'u' for 'unknown', 'i'
6644 for 'ignored' and 'c' for clean.
6649 for 'ignored' and 'c' for clean.
6645
6650
6646 It abbreviates only those statuses which are passed. Note that clean and
6651 It abbreviates only those statuses which are passed. Note that clean and
6647 ignored files are not displayed with '--terse ic' unless the -c/--clean
6652 ignored files are not displayed with '--terse ic' unless the -c/--clean
6648 and -i/--ignored options are also used.
6653 and -i/--ignored options are also used.
6649
6654
6650 The -v/--verbose option shows information when the repository is in an
6655 The -v/--verbose option shows information when the repository is in an
6651 unfinished merge, shelve, rebase state etc. You can have this behavior
6656 unfinished merge, shelve, rebase state etc. You can have this behavior
6652 turned on by default by enabling the ``commands.status.verbose`` option.
6657 turned on by default by enabling the ``commands.status.verbose`` option.
6653
6658
6654 You can skip displaying some of these states by setting
6659 You can skip displaying some of these states by setting
6655 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6660 ``commands.status.skipstates`` to one or more of: 'bisect', 'graft',
6656 'histedit', 'merge', 'rebase', or 'unshelve'.
6661 'histedit', 'merge', 'rebase', or 'unshelve'.
6657
6662
6658 Template:
6663 Template:
6659
6664
6660 The following keywords are supported in addition to the common template
6665 The following keywords are supported in addition to the common template
6661 keywords and functions. See also :hg:`help templates`.
6666 keywords and functions. See also :hg:`help templates`.
6662
6667
6663 :path: String. Repository-absolute path of the file.
6668 :path: String. Repository-absolute path of the file.
6664 :source: String. Repository-absolute path of the file originated from.
6669 :source: String. Repository-absolute path of the file originated from.
6665 Available if ``--copies`` is specified.
6670 Available if ``--copies`` is specified.
6666 :status: String. Character denoting file's status.
6671 :status: String. Character denoting file's status.
6667
6672
6668 Examples:
6673 Examples:
6669
6674
6670 - show changes in the working directory relative to a
6675 - show changes in the working directory relative to a
6671 changeset::
6676 changeset::
6672
6677
6673 hg status --rev 9353
6678 hg status --rev 9353
6674
6679
6675 - show changes in the working directory relative to the
6680 - show changes in the working directory relative to the
6676 current directory (see :hg:`help patterns` for more information)::
6681 current directory (see :hg:`help patterns` for more information)::
6677
6682
6678 hg status re:
6683 hg status re:
6679
6684
6680 - show all changes including copies in an existing changeset::
6685 - show all changes including copies in an existing changeset::
6681
6686
6682 hg status --copies --change 9353
6687 hg status --copies --change 9353
6683
6688
6684 - get a NUL separated list of added files, suitable for xargs::
6689 - get a NUL separated list of added files, suitable for xargs::
6685
6690
6686 hg status -an0
6691 hg status -an0
6687
6692
6688 - show more information about the repository status, abbreviating
6693 - show more information about the repository status, abbreviating
6689 added, removed, modified, deleted, and untracked paths::
6694 added, removed, modified, deleted, and untracked paths::
6690
6695
6691 hg status -v -t mardu
6696 hg status -v -t mardu
6692
6697
6693 Returns 0 on success.
6698 Returns 0 on success.
6694
6699
6695 """
6700 """
6696
6701
6697 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6702 cmdutil.check_at_most_one_arg(opts, 'rev', 'change')
6698 opts = pycompat.byteskwargs(opts)
6703 opts = pycompat.byteskwargs(opts)
6699 revs = opts.get(b'rev')
6704 revs = opts.get(b'rev')
6700 change = opts.get(b'change')
6705 change = opts.get(b'change')
6701 terse = opts.get(b'terse')
6706 terse = opts.get(b'terse')
6702 if terse is _NOTTERSE:
6707 if terse is _NOTTERSE:
6703 if revs:
6708 if revs:
6704 terse = b''
6709 terse = b''
6705 else:
6710 else:
6706 terse = ui.config(b'commands', b'status.terse')
6711 terse = ui.config(b'commands', b'status.terse')
6707
6712
6708 if revs and terse:
6713 if revs and terse:
6709 msg = _(b'cannot use --terse with --rev')
6714 msg = _(b'cannot use --terse with --rev')
6710 raise error.InputError(msg)
6715 raise error.InputError(msg)
6711 elif change:
6716 elif change:
6712 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6717 repo = scmutil.unhidehashlikerevs(repo, [change], b'nowarn')
6713 ctx2 = scmutil.revsingle(repo, change, None)
6718 ctx2 = scmutil.revsingle(repo, change, None)
6714 ctx1 = ctx2.p1()
6719 ctx1 = ctx2.p1()
6715 else:
6720 else:
6716 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6721 repo = scmutil.unhidehashlikerevs(repo, revs, b'nowarn')
6717 ctx1, ctx2 = scmutil.revpair(repo, revs)
6722 ctx1, ctx2 = scmutil.revpair(repo, revs)
6718
6723
6719 forcerelativevalue = None
6724 forcerelativevalue = None
6720 if ui.hasconfig(b'commands', b'status.relative'):
6725 if ui.hasconfig(b'commands', b'status.relative'):
6721 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6726 forcerelativevalue = ui.configbool(b'commands', b'status.relative')
6722 uipathfn = scmutil.getuipathfn(
6727 uipathfn = scmutil.getuipathfn(
6723 repo,
6728 repo,
6724 legacyrelativevalue=bool(pats),
6729 legacyrelativevalue=bool(pats),
6725 forcerelativevalue=forcerelativevalue,
6730 forcerelativevalue=forcerelativevalue,
6726 )
6731 )
6727
6732
6728 if opts.get(b'print0'):
6733 if opts.get(b'print0'):
6729 end = b'\0'
6734 end = b'\0'
6730 else:
6735 else:
6731 end = b'\n'
6736 end = b'\n'
6732 states = b'modified added removed deleted unknown ignored clean'.split()
6737 states = b'modified added removed deleted unknown ignored clean'.split()
6733 show = [k for k in states if opts.get(k)]
6738 show = [k for k in states if opts.get(k)]
6734 if opts.get(b'all'):
6739 if opts.get(b'all'):
6735 show += ui.quiet and (states[:4] + [b'clean']) or states
6740 show += ui.quiet and (states[:4] + [b'clean']) or states
6736
6741
6737 if not show:
6742 if not show:
6738 if ui.quiet:
6743 if ui.quiet:
6739 show = states[:4]
6744 show = states[:4]
6740 else:
6745 else:
6741 show = states[:5]
6746 show = states[:5]
6742
6747
6743 m = scmutil.match(ctx2, pats, opts)
6748 m = scmutil.match(ctx2, pats, opts)
6744 if terse:
6749 if terse:
6745 # we need to compute clean and unknown to terse
6750 # we need to compute clean and unknown to terse
6746 stat = repo.status(
6751 stat = repo.status(
6747 ctx1.node(),
6752 ctx1.node(),
6748 ctx2.node(),
6753 ctx2.node(),
6749 m,
6754 m,
6750 b'ignored' in show or b'i' in terse,
6755 b'ignored' in show or b'i' in terse,
6751 clean=True,
6756 clean=True,
6752 unknown=True,
6757 unknown=True,
6753 listsubrepos=opts.get(b'subrepos'),
6758 listsubrepos=opts.get(b'subrepos'),
6754 )
6759 )
6755
6760
6756 stat = cmdutil.tersedir(stat, terse)
6761 stat = cmdutil.tersedir(stat, terse)
6757 else:
6762 else:
6758 stat = repo.status(
6763 stat = repo.status(
6759 ctx1.node(),
6764 ctx1.node(),
6760 ctx2.node(),
6765 ctx2.node(),
6761 m,
6766 m,
6762 b'ignored' in show,
6767 b'ignored' in show,
6763 b'clean' in show,
6768 b'clean' in show,
6764 b'unknown' in show,
6769 b'unknown' in show,
6765 opts.get(b'subrepos'),
6770 opts.get(b'subrepos'),
6766 )
6771 )
6767
6772
6768 changestates = zip(
6773 changestates = zip(
6769 states,
6774 states,
6770 pycompat.iterbytestr(b'MAR!?IC'),
6775 pycompat.iterbytestr(b'MAR!?IC'),
6771 [getattr(stat, s.decode('utf8')) for s in states],
6776 [getattr(stat, s.decode('utf8')) for s in states],
6772 )
6777 )
6773
6778
6774 copy = {}
6779 copy = {}
6775 if (
6780 if (
6776 opts.get(b'all')
6781 opts.get(b'all')
6777 or opts.get(b'copies')
6782 or opts.get(b'copies')
6778 or ui.configbool(b'ui', b'statuscopies')
6783 or ui.configbool(b'ui', b'statuscopies')
6779 ) and not opts.get(b'no_status'):
6784 ) and not opts.get(b'no_status'):
6780 copy = copies.pathcopies(ctx1, ctx2, m)
6785 copy = copies.pathcopies(ctx1, ctx2, m)
6781
6786
6782 morestatus = None
6787 morestatus = None
6783 if (
6788 if (
6784 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6789 (ui.verbose or ui.configbool(b'commands', b'status.verbose'))
6785 and not ui.plain()
6790 and not ui.plain()
6786 and not opts.get(b'print0')
6791 and not opts.get(b'print0')
6787 ):
6792 ):
6788 morestatus = cmdutil.readmorestatus(repo)
6793 morestatus = cmdutil.readmorestatus(repo)
6789
6794
6790 ui.pager(b'status')
6795 ui.pager(b'status')
6791 fm = ui.formatter(b'status', opts)
6796 fm = ui.formatter(b'status', opts)
6792 fmt = b'%s' + end
6797 fmt = b'%s' + end
6793 showchar = not opts.get(b'no_status')
6798 showchar = not opts.get(b'no_status')
6794
6799
6795 for state, char, files in changestates:
6800 for state, char, files in changestates:
6796 if state in show:
6801 if state in show:
6797 label = b'status.' + state
6802 label = b'status.' + state
6798 for f in files:
6803 for f in files:
6799 fm.startitem()
6804 fm.startitem()
6800 fm.context(ctx=ctx2)
6805 fm.context(ctx=ctx2)
6801 fm.data(itemtype=b'file', path=f)
6806 fm.data(itemtype=b'file', path=f)
6802 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6807 fm.condwrite(showchar, b'status', b'%s ', char, label=label)
6803 fm.plain(fmt % uipathfn(f), label=label)
6808 fm.plain(fmt % uipathfn(f), label=label)
6804 if f in copy:
6809 if f in copy:
6805 fm.data(source=copy[f])
6810 fm.data(source=copy[f])
6806 fm.plain(
6811 fm.plain(
6807 (b' %s' + end) % uipathfn(copy[f]),
6812 (b' %s' + end) % uipathfn(copy[f]),
6808 label=b'status.copied',
6813 label=b'status.copied',
6809 )
6814 )
6810 if morestatus:
6815 if morestatus:
6811 morestatus.formatfile(f, fm)
6816 morestatus.formatfile(f, fm)
6812
6817
6813 if morestatus:
6818 if morestatus:
6814 morestatus.formatfooter(fm)
6819 morestatus.formatfooter(fm)
6815 fm.end()
6820 fm.end()
6816
6821
6817
6822
6818 @command(
6823 @command(
6819 b'summary|sum',
6824 b'summary|sum',
6820 [(b'', b'remote', None, _(b'check for push and pull'))],
6825 [(b'', b'remote', None, _(b'check for push and pull'))],
6821 b'[--remote]',
6826 b'[--remote]',
6822 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6827 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
6823 helpbasic=True,
6828 helpbasic=True,
6824 intents={INTENT_READONLY},
6829 intents={INTENT_READONLY},
6825 )
6830 )
6826 def summary(ui, repo, **opts):
6831 def summary(ui, repo, **opts):
6827 """summarize working directory state
6832 """summarize working directory state
6828
6833
6829 This generates a brief summary of the working directory state,
6834 This generates a brief summary of the working directory state,
6830 including parents, branch, commit status, phase and available updates.
6835 including parents, branch, commit status, phase and available updates.
6831
6836
6832 With the --remote option, this will check the default paths for
6837 With the --remote option, this will check the default paths for
6833 incoming and outgoing changes. This can be time-consuming.
6838 incoming and outgoing changes. This can be time-consuming.
6834
6839
6835 Returns 0 on success.
6840 Returns 0 on success.
6836 """
6841 """
6837
6842
6838 opts = pycompat.byteskwargs(opts)
6843 opts = pycompat.byteskwargs(opts)
6839 ui.pager(b'summary')
6844 ui.pager(b'summary')
6840 ctx = repo[None]
6845 ctx = repo[None]
6841 parents = ctx.parents()
6846 parents = ctx.parents()
6842 pnode = parents[0].node()
6847 pnode = parents[0].node()
6843 marks = []
6848 marks = []
6844
6849
6845 try:
6850 try:
6846 ms = mergestatemod.mergestate.read(repo)
6851 ms = mergestatemod.mergestate.read(repo)
6847 except error.UnsupportedMergeRecords as e:
6852 except error.UnsupportedMergeRecords as e:
6848 s = b' '.join(e.recordtypes)
6853 s = b' '.join(e.recordtypes)
6849 ui.warn(
6854 ui.warn(
6850 _(b'warning: merge state has unsupported record types: %s\n') % s
6855 _(b'warning: merge state has unsupported record types: %s\n') % s
6851 )
6856 )
6852 unresolved = []
6857 unresolved = []
6853 else:
6858 else:
6854 unresolved = list(ms.unresolved())
6859 unresolved = list(ms.unresolved())
6855
6860
6856 for p in parents:
6861 for p in parents:
6857 # label with log.changeset (instead of log.parent) since this
6862 # label with log.changeset (instead of log.parent) since this
6858 # shows a working directory parent *changeset*:
6863 # shows a working directory parent *changeset*:
6859 # i18n: column positioning for "hg summary"
6864 # i18n: column positioning for "hg summary"
6860 ui.write(
6865 ui.write(
6861 _(b'parent: %d:%s ') % (p.rev(), p),
6866 _(b'parent: %d:%s ') % (p.rev(), p),
6862 label=logcmdutil.changesetlabels(p),
6867 label=logcmdutil.changesetlabels(p),
6863 )
6868 )
6864 ui.write(b' '.join(p.tags()), label=b'log.tag')
6869 ui.write(b' '.join(p.tags()), label=b'log.tag')
6865 if p.bookmarks():
6870 if p.bookmarks():
6866 marks.extend(p.bookmarks())
6871 marks.extend(p.bookmarks())
6867 if p.rev() == -1:
6872 if p.rev() == -1:
6868 if not len(repo):
6873 if not len(repo):
6869 ui.write(_(b' (empty repository)'))
6874 ui.write(_(b' (empty repository)'))
6870 else:
6875 else:
6871 ui.write(_(b' (no revision checked out)'))
6876 ui.write(_(b' (no revision checked out)'))
6872 if p.obsolete():
6877 if p.obsolete():
6873 ui.write(_(b' (obsolete)'))
6878 ui.write(_(b' (obsolete)'))
6874 if p.isunstable():
6879 if p.isunstable():
6875 instabilities = (
6880 instabilities = (
6876 ui.label(instability, b'trouble.%s' % instability)
6881 ui.label(instability, b'trouble.%s' % instability)
6877 for instability in p.instabilities()
6882 for instability in p.instabilities()
6878 )
6883 )
6879 ui.write(b' (' + b', '.join(instabilities) + b')')
6884 ui.write(b' (' + b', '.join(instabilities) + b')')
6880 ui.write(b'\n')
6885 ui.write(b'\n')
6881 if p.description():
6886 if p.description():
6882 ui.status(
6887 ui.status(
6883 b' ' + p.description().splitlines()[0].strip() + b'\n',
6888 b' ' + p.description().splitlines()[0].strip() + b'\n',
6884 label=b'log.summary',
6889 label=b'log.summary',
6885 )
6890 )
6886
6891
6887 branch = ctx.branch()
6892 branch = ctx.branch()
6888 bheads = repo.branchheads(branch)
6893 bheads = repo.branchheads(branch)
6889 # i18n: column positioning for "hg summary"
6894 # i18n: column positioning for "hg summary"
6890 m = _(b'branch: %s\n') % branch
6895 m = _(b'branch: %s\n') % branch
6891 if branch != b'default':
6896 if branch != b'default':
6892 ui.write(m, label=b'log.branch')
6897 ui.write(m, label=b'log.branch')
6893 else:
6898 else:
6894 ui.status(m, label=b'log.branch')
6899 ui.status(m, label=b'log.branch')
6895
6900
6896 if marks:
6901 if marks:
6897 active = repo._activebookmark
6902 active = repo._activebookmark
6898 # i18n: column positioning for "hg summary"
6903 # i18n: column positioning for "hg summary"
6899 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6904 ui.write(_(b'bookmarks:'), label=b'log.bookmark')
6900 if active is not None:
6905 if active is not None:
6901 if active in marks:
6906 if active in marks:
6902 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6907 ui.write(b' *' + active, label=bookmarks.activebookmarklabel)
6903 marks.remove(active)
6908 marks.remove(active)
6904 else:
6909 else:
6905 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6910 ui.write(b' [%s]' % active, label=bookmarks.activebookmarklabel)
6906 for m in marks:
6911 for m in marks:
6907 ui.write(b' ' + m, label=b'log.bookmark')
6912 ui.write(b' ' + m, label=b'log.bookmark')
6908 ui.write(b'\n', label=b'log.bookmark')
6913 ui.write(b'\n', label=b'log.bookmark')
6909
6914
6910 status = repo.status(unknown=True)
6915 status = repo.status(unknown=True)
6911
6916
6912 c = repo.dirstate.copies()
6917 c = repo.dirstate.copies()
6913 copied, renamed = [], []
6918 copied, renamed = [], []
6914 for d, s in pycompat.iteritems(c):
6919 for d, s in pycompat.iteritems(c):
6915 if s in status.removed:
6920 if s in status.removed:
6916 status.removed.remove(s)
6921 status.removed.remove(s)
6917 renamed.append(d)
6922 renamed.append(d)
6918 else:
6923 else:
6919 copied.append(d)
6924 copied.append(d)
6920 if d in status.added:
6925 if d in status.added:
6921 status.added.remove(d)
6926 status.added.remove(d)
6922
6927
6923 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6928 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
6924
6929
6925 labels = [
6930 labels = [
6926 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6931 (ui.label(_(b'%d modified'), b'status.modified'), status.modified),
6927 (ui.label(_(b'%d added'), b'status.added'), status.added),
6932 (ui.label(_(b'%d added'), b'status.added'), status.added),
6928 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6933 (ui.label(_(b'%d removed'), b'status.removed'), status.removed),
6929 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6934 (ui.label(_(b'%d renamed'), b'status.copied'), renamed),
6930 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6935 (ui.label(_(b'%d copied'), b'status.copied'), copied),
6931 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6936 (ui.label(_(b'%d deleted'), b'status.deleted'), status.deleted),
6932 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6937 (ui.label(_(b'%d unknown'), b'status.unknown'), status.unknown),
6933 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6938 (ui.label(_(b'%d unresolved'), b'resolve.unresolved'), unresolved),
6934 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6939 (ui.label(_(b'%d subrepos'), b'status.modified'), subs),
6935 ]
6940 ]
6936 t = []
6941 t = []
6937 for l, s in labels:
6942 for l, s in labels:
6938 if s:
6943 if s:
6939 t.append(l % len(s))
6944 t.append(l % len(s))
6940
6945
6941 t = b', '.join(t)
6946 t = b', '.join(t)
6942 cleanworkdir = False
6947 cleanworkdir = False
6943
6948
6944 if repo.vfs.exists(b'graftstate'):
6949 if repo.vfs.exists(b'graftstate'):
6945 t += _(b' (graft in progress)')
6950 t += _(b' (graft in progress)')
6946 if repo.vfs.exists(b'updatestate'):
6951 if repo.vfs.exists(b'updatestate'):
6947 t += _(b' (interrupted update)')
6952 t += _(b' (interrupted update)')
6948 elif len(parents) > 1:
6953 elif len(parents) > 1:
6949 t += _(b' (merge)')
6954 t += _(b' (merge)')
6950 elif branch != parents[0].branch():
6955 elif branch != parents[0].branch():
6951 t += _(b' (new branch)')
6956 t += _(b' (new branch)')
6952 elif parents[0].closesbranch() and pnode in repo.branchheads(
6957 elif parents[0].closesbranch() and pnode in repo.branchheads(
6953 branch, closed=True
6958 branch, closed=True
6954 ):
6959 ):
6955 t += _(b' (head closed)')
6960 t += _(b' (head closed)')
6956 elif not (
6961 elif not (
6957 status.modified
6962 status.modified
6958 or status.added
6963 or status.added
6959 or status.removed
6964 or status.removed
6960 or renamed
6965 or renamed
6961 or copied
6966 or copied
6962 or subs
6967 or subs
6963 ):
6968 ):
6964 t += _(b' (clean)')
6969 t += _(b' (clean)')
6965 cleanworkdir = True
6970 cleanworkdir = True
6966 elif pnode not in bheads:
6971 elif pnode not in bheads:
6967 t += _(b' (new branch head)')
6972 t += _(b' (new branch head)')
6968
6973
6969 if parents:
6974 if parents:
6970 pendingphase = max(p.phase() for p in parents)
6975 pendingphase = max(p.phase() for p in parents)
6971 else:
6976 else:
6972 pendingphase = phases.public
6977 pendingphase = phases.public
6973
6978
6974 if pendingphase > phases.newcommitphase(ui):
6979 if pendingphase > phases.newcommitphase(ui):
6975 t += b' (%s)' % phases.phasenames[pendingphase]
6980 t += b' (%s)' % phases.phasenames[pendingphase]
6976
6981
6977 if cleanworkdir:
6982 if cleanworkdir:
6978 # i18n: column positioning for "hg summary"
6983 # i18n: column positioning for "hg summary"
6979 ui.status(_(b'commit: %s\n') % t.strip())
6984 ui.status(_(b'commit: %s\n') % t.strip())
6980 else:
6985 else:
6981 # i18n: column positioning for "hg summary"
6986 # i18n: column positioning for "hg summary"
6982 ui.write(_(b'commit: %s\n') % t.strip())
6987 ui.write(_(b'commit: %s\n') % t.strip())
6983
6988
6984 # all ancestors of branch heads - all ancestors of parent = new csets
6989 # all ancestors of branch heads - all ancestors of parent = new csets
6985 new = len(
6990 new = len(
6986 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
6991 repo.changelog.findmissing([pctx.node() for pctx in parents], bheads)
6987 )
6992 )
6988
6993
6989 if new == 0:
6994 if new == 0:
6990 # i18n: column positioning for "hg summary"
6995 # i18n: column positioning for "hg summary"
6991 ui.status(_(b'update: (current)\n'))
6996 ui.status(_(b'update: (current)\n'))
6992 elif pnode not in bheads:
6997 elif pnode not in bheads:
6993 # i18n: column positioning for "hg summary"
6998 # i18n: column positioning for "hg summary"
6994 ui.write(_(b'update: %d new changesets (update)\n') % new)
6999 ui.write(_(b'update: %d new changesets (update)\n') % new)
6995 else:
7000 else:
6996 # i18n: column positioning for "hg summary"
7001 # i18n: column positioning for "hg summary"
6997 ui.write(
7002 ui.write(
6998 _(b'update: %d new changesets, %d branch heads (merge)\n')
7003 _(b'update: %d new changesets, %d branch heads (merge)\n')
6999 % (new, len(bheads))
7004 % (new, len(bheads))
7000 )
7005 )
7001
7006
7002 t = []
7007 t = []
7003 draft = len(repo.revs(b'draft()'))
7008 draft = len(repo.revs(b'draft()'))
7004 if draft:
7009 if draft:
7005 t.append(_(b'%d draft') % draft)
7010 t.append(_(b'%d draft') % draft)
7006 secret = len(repo.revs(b'secret()'))
7011 secret = len(repo.revs(b'secret()'))
7007 if secret:
7012 if secret:
7008 t.append(_(b'%d secret') % secret)
7013 t.append(_(b'%d secret') % secret)
7009
7014
7010 if draft or secret:
7015 if draft or secret:
7011 ui.status(_(b'phases: %s\n') % b', '.join(t))
7016 ui.status(_(b'phases: %s\n') % b', '.join(t))
7012
7017
7013 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7018 if obsolete.isenabled(repo, obsolete.createmarkersopt):
7014 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7019 for trouble in (b"orphan", b"contentdivergent", b"phasedivergent"):
7015 numtrouble = len(repo.revs(trouble + b"()"))
7020 numtrouble = len(repo.revs(trouble + b"()"))
7016 # We write all the possibilities to ease translation
7021 # We write all the possibilities to ease translation
7017 troublemsg = {
7022 troublemsg = {
7018 b"orphan": _(b"orphan: %d changesets"),
7023 b"orphan": _(b"orphan: %d changesets"),
7019 b"contentdivergent": _(b"content-divergent: %d changesets"),
7024 b"contentdivergent": _(b"content-divergent: %d changesets"),
7020 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7025 b"phasedivergent": _(b"phase-divergent: %d changesets"),
7021 }
7026 }
7022 if numtrouble > 0:
7027 if numtrouble > 0:
7023 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7028 ui.status(troublemsg[trouble] % numtrouble + b"\n")
7024
7029
7025 cmdutil.summaryhooks(ui, repo)
7030 cmdutil.summaryhooks(ui, repo)
7026
7031
7027 if opts.get(b'remote'):
7032 if opts.get(b'remote'):
7028 needsincoming, needsoutgoing = True, True
7033 needsincoming, needsoutgoing = True, True
7029 else:
7034 else:
7030 needsincoming, needsoutgoing = False, False
7035 needsincoming, needsoutgoing = False, False
7031 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7036 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
7032 if i:
7037 if i:
7033 needsincoming = True
7038 needsincoming = True
7034 if o:
7039 if o:
7035 needsoutgoing = True
7040 needsoutgoing = True
7036 if not needsincoming and not needsoutgoing:
7041 if not needsincoming and not needsoutgoing:
7037 return
7042 return
7038
7043
7039 def getincoming():
7044 def getincoming():
7040 source, branches = hg.parseurl(ui.expandpath(b'default'))
7045 source, branches = hg.parseurl(ui.expandpath(b'default'))
7041 sbranch = branches[0]
7046 sbranch = branches[0]
7042 try:
7047 try:
7043 other = hg.peer(repo, {}, source)
7048 other = hg.peer(repo, {}, source)
7044 except error.RepoError:
7049 except error.RepoError:
7045 if opts.get(b'remote'):
7050 if opts.get(b'remote'):
7046 raise
7051 raise
7047 return source, sbranch, None, None, None
7052 return source, sbranch, None, None, None
7048 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7053 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
7049 if revs:
7054 if revs:
7050 revs = [other.lookup(rev) for rev in revs]
7055 revs = [other.lookup(rev) for rev in revs]
7051 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7056 ui.debug(b'comparing with %s\n' % util.hidepassword(source))
7052 repo.ui.pushbuffer()
7057 repo.ui.pushbuffer()
7053 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7058 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
7054 repo.ui.popbuffer()
7059 repo.ui.popbuffer()
7055 return source, sbranch, other, commoninc, commoninc[1]
7060 return source, sbranch, other, commoninc, commoninc[1]
7056
7061
7057 if needsincoming:
7062 if needsincoming:
7058 source, sbranch, sother, commoninc, incoming = getincoming()
7063 source, sbranch, sother, commoninc, incoming = getincoming()
7059 else:
7064 else:
7060 source = sbranch = sother = commoninc = incoming = None
7065 source = sbranch = sother = commoninc = incoming = None
7061
7066
7062 def getoutgoing():
7067 def getoutgoing():
7063 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7068 dest, branches = hg.parseurl(ui.expandpath(b'default-push', b'default'))
7064 dbranch = branches[0]
7069 dbranch = branches[0]
7065 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7070 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
7066 if source != dest:
7071 if source != dest:
7067 try:
7072 try:
7068 dother = hg.peer(repo, {}, dest)
7073 dother = hg.peer(repo, {}, dest)
7069 except error.RepoError:
7074 except error.RepoError:
7070 if opts.get(b'remote'):
7075 if opts.get(b'remote'):
7071 raise
7076 raise
7072 return dest, dbranch, None, None
7077 return dest, dbranch, None, None
7073 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7078 ui.debug(b'comparing with %s\n' % util.hidepassword(dest))
7074 elif sother is None:
7079 elif sother is None:
7075 # there is no explicit destination peer, but source one is invalid
7080 # there is no explicit destination peer, but source one is invalid
7076 return dest, dbranch, None, None
7081 return dest, dbranch, None, None
7077 else:
7082 else:
7078 dother = sother
7083 dother = sother
7079 if source != dest or (sbranch is not None and sbranch != dbranch):
7084 if source != dest or (sbranch is not None and sbranch != dbranch):
7080 common = None
7085 common = None
7081 else:
7086 else:
7082 common = commoninc
7087 common = commoninc
7083 if revs:
7088 if revs:
7084 revs = [repo.lookup(rev) for rev in revs]
7089 revs = [repo.lookup(rev) for rev in revs]
7085 repo.ui.pushbuffer()
7090 repo.ui.pushbuffer()
7086 outgoing = discovery.findcommonoutgoing(
7091 outgoing = discovery.findcommonoutgoing(
7087 repo, dother, onlyheads=revs, commoninc=common
7092 repo, dother, onlyheads=revs, commoninc=common
7088 )
7093 )
7089 repo.ui.popbuffer()
7094 repo.ui.popbuffer()
7090 return dest, dbranch, dother, outgoing
7095 return dest, dbranch, dother, outgoing
7091
7096
7092 if needsoutgoing:
7097 if needsoutgoing:
7093 dest, dbranch, dother, outgoing = getoutgoing()
7098 dest, dbranch, dother, outgoing = getoutgoing()
7094 else:
7099 else:
7095 dest = dbranch = dother = outgoing = None
7100 dest = dbranch = dother = outgoing = None
7096
7101
7097 if opts.get(b'remote'):
7102 if opts.get(b'remote'):
7098 t = []
7103 t = []
7099 if incoming:
7104 if incoming:
7100 t.append(_(b'1 or more incoming'))
7105 t.append(_(b'1 or more incoming'))
7101 o = outgoing.missing
7106 o = outgoing.missing
7102 if o:
7107 if o:
7103 t.append(_(b'%d outgoing') % len(o))
7108 t.append(_(b'%d outgoing') % len(o))
7104 other = dother or sother
7109 other = dother or sother
7105 if b'bookmarks' in other.listkeys(b'namespaces'):
7110 if b'bookmarks' in other.listkeys(b'namespaces'):
7106 counts = bookmarks.summary(repo, other)
7111 counts = bookmarks.summary(repo, other)
7107 if counts[0] > 0:
7112 if counts[0] > 0:
7108 t.append(_(b'%d incoming bookmarks') % counts[0])
7113 t.append(_(b'%d incoming bookmarks') % counts[0])
7109 if counts[1] > 0:
7114 if counts[1] > 0:
7110 t.append(_(b'%d outgoing bookmarks') % counts[1])
7115 t.append(_(b'%d outgoing bookmarks') % counts[1])
7111
7116
7112 if t:
7117 if t:
7113 # i18n: column positioning for "hg summary"
7118 # i18n: column positioning for "hg summary"
7114 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7119 ui.write(_(b'remote: %s\n') % (b', '.join(t)))
7115 else:
7120 else:
7116 # i18n: column positioning for "hg summary"
7121 # i18n: column positioning for "hg summary"
7117 ui.status(_(b'remote: (synced)\n'))
7122 ui.status(_(b'remote: (synced)\n'))
7118
7123
7119 cmdutil.summaryremotehooks(
7124 cmdutil.summaryremotehooks(
7120 ui,
7125 ui,
7121 repo,
7126 repo,
7122 opts,
7127 opts,
7123 (
7128 (
7124 (source, sbranch, sother, commoninc),
7129 (source, sbranch, sother, commoninc),
7125 (dest, dbranch, dother, outgoing),
7130 (dest, dbranch, dother, outgoing),
7126 ),
7131 ),
7127 )
7132 )
7128
7133
7129
7134
7130 @command(
7135 @command(
7131 b'tag',
7136 b'tag',
7132 [
7137 [
7133 (b'f', b'force', None, _(b'force tag')),
7138 (b'f', b'force', None, _(b'force tag')),
7134 (b'l', b'local', None, _(b'make the tag local')),
7139 (b'l', b'local', None, _(b'make the tag local')),
7135 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7140 (b'r', b'rev', b'', _(b'revision to tag'), _(b'REV')),
7136 (b'', b'remove', None, _(b'remove a tag')),
7141 (b'', b'remove', None, _(b'remove a tag')),
7137 # -l/--local is already there, commitopts cannot be used
7142 # -l/--local is already there, commitopts cannot be used
7138 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7143 (b'e', b'edit', None, _(b'invoke editor on commit messages')),
7139 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7144 (b'm', b'message', b'', _(b'use text as commit message'), _(b'TEXT')),
7140 ]
7145 ]
7141 + commitopts2,
7146 + commitopts2,
7142 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7147 _(b'[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'),
7143 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7148 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7144 )
7149 )
7145 def tag(ui, repo, name1, *names, **opts):
7150 def tag(ui, repo, name1, *names, **opts):
7146 """add one or more tags for the current or given revision
7151 """add one or more tags for the current or given revision
7147
7152
7148 Name a particular revision using <name>.
7153 Name a particular revision using <name>.
7149
7154
7150 Tags are used to name particular revisions of the repository and are
7155 Tags are used to name particular revisions of the repository and are
7151 very useful to compare different revisions, to go back to significant
7156 very useful to compare different revisions, to go back to significant
7152 earlier versions or to mark branch points as releases, etc. Changing
7157 earlier versions or to mark branch points as releases, etc. Changing
7153 an existing tag is normally disallowed; use -f/--force to override.
7158 an existing tag is normally disallowed; use -f/--force to override.
7154
7159
7155 If no revision is given, the parent of the working directory is
7160 If no revision is given, the parent of the working directory is
7156 used.
7161 used.
7157
7162
7158 To facilitate version control, distribution, and merging of tags,
7163 To facilitate version control, distribution, and merging of tags,
7159 they are stored as a file named ".hgtags" which is managed similarly
7164 they are stored as a file named ".hgtags" which is managed similarly
7160 to other project files and can be hand-edited if necessary. This
7165 to other project files and can be hand-edited if necessary. This
7161 also means that tagging creates a new commit. The file
7166 also means that tagging creates a new commit. The file
7162 ".hg/localtags" is used for local tags (not shared among
7167 ".hg/localtags" is used for local tags (not shared among
7163 repositories).
7168 repositories).
7164
7169
7165 Tag commits are usually made at the head of a branch. If the parent
7170 Tag commits are usually made at the head of a branch. If the parent
7166 of the working directory is not a branch head, :hg:`tag` aborts; use
7171 of the working directory is not a branch head, :hg:`tag` aborts; use
7167 -f/--force to force the tag commit to be based on a non-head
7172 -f/--force to force the tag commit to be based on a non-head
7168 changeset.
7173 changeset.
7169
7174
7170 See :hg:`help dates` for a list of formats valid for -d/--date.
7175 See :hg:`help dates` for a list of formats valid for -d/--date.
7171
7176
7172 Since tag names have priority over branch names during revision
7177 Since tag names have priority over branch names during revision
7173 lookup, using an existing branch name as a tag name is discouraged.
7178 lookup, using an existing branch name as a tag name is discouraged.
7174
7179
7175 Returns 0 on success.
7180 Returns 0 on success.
7176 """
7181 """
7177 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7182 cmdutil.check_incompatible_arguments(opts, 'remove', ['rev'])
7178 opts = pycompat.byteskwargs(opts)
7183 opts = pycompat.byteskwargs(opts)
7179 with repo.wlock(), repo.lock():
7184 with repo.wlock(), repo.lock():
7180 rev_ = b"."
7185 rev_ = b"."
7181 names = [t.strip() for t in (name1,) + names]
7186 names = [t.strip() for t in (name1,) + names]
7182 if len(names) != len(set(names)):
7187 if len(names) != len(set(names)):
7183 raise error.InputError(_(b'tag names must be unique'))
7188 raise error.InputError(_(b'tag names must be unique'))
7184 for n in names:
7189 for n in names:
7185 scmutil.checknewlabel(repo, n, b'tag')
7190 scmutil.checknewlabel(repo, n, b'tag')
7186 if not n:
7191 if not n:
7187 raise error.InputError(
7192 raise error.InputError(
7188 _(b'tag names cannot consist entirely of whitespace')
7193 _(b'tag names cannot consist entirely of whitespace')
7189 )
7194 )
7190 if opts.get(b'rev'):
7195 if opts.get(b'rev'):
7191 rev_ = opts[b'rev']
7196 rev_ = opts[b'rev']
7192 message = opts.get(b'message')
7197 message = opts.get(b'message')
7193 if opts.get(b'remove'):
7198 if opts.get(b'remove'):
7194 if opts.get(b'local'):
7199 if opts.get(b'local'):
7195 expectedtype = b'local'
7200 expectedtype = b'local'
7196 else:
7201 else:
7197 expectedtype = b'global'
7202 expectedtype = b'global'
7198
7203
7199 for n in names:
7204 for n in names:
7200 if repo.tagtype(n) == b'global':
7205 if repo.tagtype(n) == b'global':
7201 alltags = tagsmod.findglobaltags(ui, repo)
7206 alltags = tagsmod.findglobaltags(ui, repo)
7202 if alltags[n][0] == nullid:
7207 if alltags[n][0] == nullid:
7203 raise error.InputError(
7208 raise error.InputError(
7204 _(b"tag '%s' is already removed") % n
7209 _(b"tag '%s' is already removed") % n
7205 )
7210 )
7206 if not repo.tagtype(n):
7211 if not repo.tagtype(n):
7207 raise error.InputError(_(b"tag '%s' does not exist") % n)
7212 raise error.InputError(_(b"tag '%s' does not exist") % n)
7208 if repo.tagtype(n) != expectedtype:
7213 if repo.tagtype(n) != expectedtype:
7209 if expectedtype == b'global':
7214 if expectedtype == b'global':
7210 raise error.InputError(
7215 raise error.InputError(
7211 _(b"tag '%s' is not a global tag") % n
7216 _(b"tag '%s' is not a global tag") % n
7212 )
7217 )
7213 else:
7218 else:
7214 raise error.InputError(
7219 raise error.InputError(
7215 _(b"tag '%s' is not a local tag") % n
7220 _(b"tag '%s' is not a local tag") % n
7216 )
7221 )
7217 rev_ = b'null'
7222 rev_ = b'null'
7218 if not message:
7223 if not message:
7219 # we don't translate commit messages
7224 # we don't translate commit messages
7220 message = b'Removed tag %s' % b', '.join(names)
7225 message = b'Removed tag %s' % b', '.join(names)
7221 elif not opts.get(b'force'):
7226 elif not opts.get(b'force'):
7222 for n in names:
7227 for n in names:
7223 if n in repo.tags():
7228 if n in repo.tags():
7224 raise error.InputError(
7229 raise error.InputError(
7225 _(b"tag '%s' already exists (use -f to force)") % n
7230 _(b"tag '%s' already exists (use -f to force)") % n
7226 )
7231 )
7227 if not opts.get(b'local'):
7232 if not opts.get(b'local'):
7228 p1, p2 = repo.dirstate.parents()
7233 p1, p2 = repo.dirstate.parents()
7229 if p2 != nullid:
7234 if p2 != nullid:
7230 raise error.StateError(_(b'uncommitted merge'))
7235 raise error.StateError(_(b'uncommitted merge'))
7231 bheads = repo.branchheads()
7236 bheads = repo.branchheads()
7232 if not opts.get(b'force') and bheads and p1 not in bheads:
7237 if not opts.get(b'force') and bheads and p1 not in bheads:
7233 raise error.InputError(
7238 raise error.InputError(
7234 _(
7239 _(
7235 b'working directory is not at a branch head '
7240 b'working directory is not at a branch head '
7236 b'(use -f to force)'
7241 b'(use -f to force)'
7237 )
7242 )
7238 )
7243 )
7239 node = scmutil.revsingle(repo, rev_).node()
7244 node = scmutil.revsingle(repo, rev_).node()
7240
7245
7241 if not message:
7246 if not message:
7242 # we don't translate commit messages
7247 # we don't translate commit messages
7243 message = b'Added tag %s for changeset %s' % (
7248 message = b'Added tag %s for changeset %s' % (
7244 b', '.join(names),
7249 b', '.join(names),
7245 short(node),
7250 short(node),
7246 )
7251 )
7247
7252
7248 date = opts.get(b'date')
7253 date = opts.get(b'date')
7249 if date:
7254 if date:
7250 date = dateutil.parsedate(date)
7255 date = dateutil.parsedate(date)
7251
7256
7252 if opts.get(b'remove'):
7257 if opts.get(b'remove'):
7253 editform = b'tag.remove'
7258 editform = b'tag.remove'
7254 else:
7259 else:
7255 editform = b'tag.add'
7260 editform = b'tag.add'
7256 editor = cmdutil.getcommiteditor(
7261 editor = cmdutil.getcommiteditor(
7257 editform=editform, **pycompat.strkwargs(opts)
7262 editform=editform, **pycompat.strkwargs(opts)
7258 )
7263 )
7259
7264
7260 # don't allow tagging the null rev
7265 # don't allow tagging the null rev
7261 if (
7266 if (
7262 not opts.get(b'remove')
7267 not opts.get(b'remove')
7263 and scmutil.revsingle(repo, rev_).rev() == nullrev
7268 and scmutil.revsingle(repo, rev_).rev() == nullrev
7264 ):
7269 ):
7265 raise error.InputError(_(b"cannot tag null revision"))
7270 raise error.InputError(_(b"cannot tag null revision"))
7266
7271
7267 tagsmod.tag(
7272 tagsmod.tag(
7268 repo,
7273 repo,
7269 names,
7274 names,
7270 node,
7275 node,
7271 message,
7276 message,
7272 opts.get(b'local'),
7277 opts.get(b'local'),
7273 opts.get(b'user'),
7278 opts.get(b'user'),
7274 date,
7279 date,
7275 editor=editor,
7280 editor=editor,
7276 )
7281 )
7277
7282
7278
7283
7279 @command(
7284 @command(
7280 b'tags',
7285 b'tags',
7281 formatteropts,
7286 formatteropts,
7282 b'',
7287 b'',
7283 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7288 helpcategory=command.CATEGORY_CHANGE_ORGANIZATION,
7284 intents={INTENT_READONLY},
7289 intents={INTENT_READONLY},
7285 )
7290 )
7286 def tags(ui, repo, **opts):
7291 def tags(ui, repo, **opts):
7287 """list repository tags
7292 """list repository tags
7288
7293
7289 This lists both regular and local tags. When the -v/--verbose
7294 This lists both regular and local tags. When the -v/--verbose
7290 switch is used, a third column "local" is printed for local tags.
7295 switch is used, a third column "local" is printed for local tags.
7291 When the -q/--quiet switch is used, only the tag name is printed.
7296 When the -q/--quiet switch is used, only the tag name is printed.
7292
7297
7293 .. container:: verbose
7298 .. container:: verbose
7294
7299
7295 Template:
7300 Template:
7296
7301
7297 The following keywords are supported in addition to the common template
7302 The following keywords are supported in addition to the common template
7298 keywords and functions such as ``{tag}``. See also
7303 keywords and functions such as ``{tag}``. See also
7299 :hg:`help templates`.
7304 :hg:`help templates`.
7300
7305
7301 :type: String. ``local`` for local tags.
7306 :type: String. ``local`` for local tags.
7302
7307
7303 Returns 0 on success.
7308 Returns 0 on success.
7304 """
7309 """
7305
7310
7306 opts = pycompat.byteskwargs(opts)
7311 opts = pycompat.byteskwargs(opts)
7307 ui.pager(b'tags')
7312 ui.pager(b'tags')
7308 fm = ui.formatter(b'tags', opts)
7313 fm = ui.formatter(b'tags', opts)
7309 hexfunc = fm.hexfunc
7314 hexfunc = fm.hexfunc
7310
7315
7311 for t, n in reversed(repo.tagslist()):
7316 for t, n in reversed(repo.tagslist()):
7312 hn = hexfunc(n)
7317 hn = hexfunc(n)
7313 label = b'tags.normal'
7318 label = b'tags.normal'
7314 tagtype = b''
7319 tagtype = b''
7315 if repo.tagtype(t) == b'local':
7320 if repo.tagtype(t) == b'local':
7316 label = b'tags.local'
7321 label = b'tags.local'
7317 tagtype = b'local'
7322 tagtype = b'local'
7318
7323
7319 fm.startitem()
7324 fm.startitem()
7320 fm.context(repo=repo)
7325 fm.context(repo=repo)
7321 fm.write(b'tag', b'%s', t, label=label)
7326 fm.write(b'tag', b'%s', t, label=label)
7322 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7327 fmt = b" " * (30 - encoding.colwidth(t)) + b' %5d:%s'
7323 fm.condwrite(
7328 fm.condwrite(
7324 not ui.quiet,
7329 not ui.quiet,
7325 b'rev node',
7330 b'rev node',
7326 fmt,
7331 fmt,
7327 repo.changelog.rev(n),
7332 repo.changelog.rev(n),
7328 hn,
7333 hn,
7329 label=label,
7334 label=label,
7330 )
7335 )
7331 fm.condwrite(
7336 fm.condwrite(
7332 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7337 ui.verbose and tagtype, b'type', b' %s', tagtype, label=label
7333 )
7338 )
7334 fm.plain(b'\n')
7339 fm.plain(b'\n')
7335 fm.end()
7340 fm.end()
7336
7341
7337
7342
7338 @command(
7343 @command(
7339 b'tip',
7344 b'tip',
7340 [
7345 [
7341 (b'p', b'patch', None, _(b'show patch')),
7346 (b'p', b'patch', None, _(b'show patch')),
7342 (b'g', b'git', None, _(b'use git extended diff format')),
7347 (b'g', b'git', None, _(b'use git extended diff format')),
7343 ]
7348 ]
7344 + templateopts,
7349 + templateopts,
7345 _(b'[-p] [-g]'),
7350 _(b'[-p] [-g]'),
7346 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7351 helpcategory=command.CATEGORY_CHANGE_NAVIGATION,
7347 )
7352 )
7348 def tip(ui, repo, **opts):
7353 def tip(ui, repo, **opts):
7349 """show the tip revision (DEPRECATED)
7354 """show the tip revision (DEPRECATED)
7350
7355
7351 The tip revision (usually just called the tip) is the changeset
7356 The tip revision (usually just called the tip) is the changeset
7352 most recently added to the repository (and therefore the most
7357 most recently added to the repository (and therefore the most
7353 recently changed head).
7358 recently changed head).
7354
7359
7355 If you have just made a commit, that commit will be the tip. If
7360 If you have just made a commit, that commit will be the tip. If
7356 you have just pulled changes from another repository, the tip of
7361 you have just pulled changes from another repository, the tip of
7357 that repository becomes the current tip. The "tip" tag is special
7362 that repository becomes the current tip. The "tip" tag is special
7358 and cannot be renamed or assigned to a different changeset.
7363 and cannot be renamed or assigned to a different changeset.
7359
7364
7360 This command is deprecated, please use :hg:`heads` instead.
7365 This command is deprecated, please use :hg:`heads` instead.
7361
7366
7362 Returns 0 on success.
7367 Returns 0 on success.
7363 """
7368 """
7364 opts = pycompat.byteskwargs(opts)
7369 opts = pycompat.byteskwargs(opts)
7365 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7370 displayer = logcmdutil.changesetdisplayer(ui, repo, opts)
7366 displayer.show(repo[b'tip'])
7371 displayer.show(repo[b'tip'])
7367 displayer.close()
7372 displayer.close()
7368
7373
7369
7374
7370 @command(
7375 @command(
7371 b'unbundle',
7376 b'unbundle',
7372 [
7377 [
7373 (
7378 (
7374 b'u',
7379 b'u',
7375 b'update',
7380 b'update',
7376 None,
7381 None,
7377 _(b'update to new branch head if changesets were unbundled'),
7382 _(b'update to new branch head if changesets were unbundled'),
7378 )
7383 )
7379 ],
7384 ],
7380 _(b'[-u] FILE...'),
7385 _(b'[-u] FILE...'),
7381 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7386 helpcategory=command.CATEGORY_IMPORT_EXPORT,
7382 )
7387 )
7383 def unbundle(ui, repo, fname1, *fnames, **opts):
7388 def unbundle(ui, repo, fname1, *fnames, **opts):
7384 """apply one or more bundle files
7389 """apply one or more bundle files
7385
7390
7386 Apply one or more bundle files generated by :hg:`bundle`.
7391 Apply one or more bundle files generated by :hg:`bundle`.
7387
7392
7388 Returns 0 on success, 1 if an update has unresolved files.
7393 Returns 0 on success, 1 if an update has unresolved files.
7389 """
7394 """
7390 fnames = (fname1,) + fnames
7395 fnames = (fname1,) + fnames
7391
7396
7392 with repo.lock():
7397 with repo.lock():
7393 for fname in fnames:
7398 for fname in fnames:
7394 f = hg.openpath(ui, fname)
7399 f = hg.openpath(ui, fname)
7395 gen = exchange.readbundle(ui, f, fname)
7400 gen = exchange.readbundle(ui, f, fname)
7396 if isinstance(gen, streamclone.streamcloneapplier):
7401 if isinstance(gen, streamclone.streamcloneapplier):
7397 raise error.InputError(
7402 raise error.InputError(
7398 _(
7403 _(
7399 b'packed bundles cannot be applied with '
7404 b'packed bundles cannot be applied with '
7400 b'"hg unbundle"'
7405 b'"hg unbundle"'
7401 ),
7406 ),
7402 hint=_(b'use "hg debugapplystreamclonebundle"'),
7407 hint=_(b'use "hg debugapplystreamclonebundle"'),
7403 )
7408 )
7404 url = b'bundle:' + fname
7409 url = b'bundle:' + fname
7405 try:
7410 try:
7406 txnname = b'unbundle'
7411 txnname = b'unbundle'
7407 if not isinstance(gen, bundle2.unbundle20):
7412 if not isinstance(gen, bundle2.unbundle20):
7408 txnname = b'unbundle\n%s' % util.hidepassword(url)
7413 txnname = b'unbundle\n%s' % util.hidepassword(url)
7409 with repo.transaction(txnname) as tr:
7414 with repo.transaction(txnname) as tr:
7410 op = bundle2.applybundle(
7415 op = bundle2.applybundle(
7411 repo, gen, tr, source=b'unbundle', url=url
7416 repo, gen, tr, source=b'unbundle', url=url
7412 )
7417 )
7413 except error.BundleUnknownFeatureError as exc:
7418 except error.BundleUnknownFeatureError as exc:
7414 raise error.Abort(
7419 raise error.Abort(
7415 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7420 _(b'%s: unknown bundle feature, %s') % (fname, exc),
7416 hint=_(
7421 hint=_(
7417 b"see https://mercurial-scm.org/"
7422 b"see https://mercurial-scm.org/"
7418 b"wiki/BundleFeature for more "
7423 b"wiki/BundleFeature for more "
7419 b"information"
7424 b"information"
7420 ),
7425 ),
7421 )
7426 )
7422 modheads = bundle2.combinechangegroupresults(op)
7427 modheads = bundle2.combinechangegroupresults(op)
7423
7428
7424 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7429 return postincoming(ui, repo, modheads, opts.get('update'), None, None)
7425
7430
7426
7431
7427 @command(
7432 @command(
7428 b'unshelve',
7433 b'unshelve',
7429 [
7434 [
7430 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7435 (b'a', b'abort', None, _(b'abort an incomplete unshelve operation')),
7431 (
7436 (
7432 b'c',
7437 b'c',
7433 b'continue',
7438 b'continue',
7434 None,
7439 None,
7435 _(b'continue an incomplete unshelve operation'),
7440 _(b'continue an incomplete unshelve operation'),
7436 ),
7441 ),
7437 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7442 (b'i', b'interactive', None, _(b'use interactive mode (EXPERIMENTAL)')),
7438 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7443 (b'k', b'keep', None, _(b'keep shelve after unshelving')),
7439 (
7444 (
7440 b'n',
7445 b'n',
7441 b'name',
7446 b'name',
7442 b'',
7447 b'',
7443 _(b'restore shelved change with given name'),
7448 _(b'restore shelved change with given name'),
7444 _(b'NAME'),
7449 _(b'NAME'),
7445 ),
7450 ),
7446 (b't', b'tool', b'', _(b'specify merge tool')),
7451 (b't', b'tool', b'', _(b'specify merge tool')),
7447 (
7452 (
7448 b'',
7453 b'',
7449 b'date',
7454 b'date',
7450 b'',
7455 b'',
7451 _(b'set date for temporary commits (DEPRECATED)'),
7456 _(b'set date for temporary commits (DEPRECATED)'),
7452 _(b'DATE'),
7457 _(b'DATE'),
7453 ),
7458 ),
7454 ],
7459 ],
7455 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7460 _(b'hg unshelve [OPTION]... [[-n] SHELVED]'),
7456 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7461 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7457 )
7462 )
7458 def unshelve(ui, repo, *shelved, **opts):
7463 def unshelve(ui, repo, *shelved, **opts):
7459 """restore a shelved change to the working directory
7464 """restore a shelved change to the working directory
7460
7465
7461 This command accepts an optional name of a shelved change to
7466 This command accepts an optional name of a shelved change to
7462 restore. If none is given, the most recent shelved change is used.
7467 restore. If none is given, the most recent shelved change is used.
7463
7468
7464 If a shelved change is applied successfully, the bundle that
7469 If a shelved change is applied successfully, the bundle that
7465 contains the shelved changes is moved to a backup location
7470 contains the shelved changes is moved to a backup location
7466 (.hg/shelve-backup).
7471 (.hg/shelve-backup).
7467
7472
7468 Since you can restore a shelved change on top of an arbitrary
7473 Since you can restore a shelved change on top of an arbitrary
7469 commit, it is possible that unshelving will result in a conflict
7474 commit, it is possible that unshelving will result in a conflict
7470 between your changes and the commits you are unshelving onto. If
7475 between your changes and the commits you are unshelving onto. If
7471 this occurs, you must resolve the conflict, then use
7476 this occurs, you must resolve the conflict, then use
7472 ``--continue`` to complete the unshelve operation. (The bundle
7477 ``--continue`` to complete the unshelve operation. (The bundle
7473 will not be moved until you successfully complete the unshelve.)
7478 will not be moved until you successfully complete the unshelve.)
7474
7479
7475 (Alternatively, you can use ``--abort`` to abandon an unshelve
7480 (Alternatively, you can use ``--abort`` to abandon an unshelve
7476 that causes a conflict. This reverts the unshelved changes, and
7481 that causes a conflict. This reverts the unshelved changes, and
7477 leaves the bundle in place.)
7482 leaves the bundle in place.)
7478
7483
7479 If bare shelved change (without interactive, include and exclude
7484 If bare shelved change (without interactive, include and exclude
7480 option) was done on newly created branch it would restore branch
7485 option) was done on newly created branch it would restore branch
7481 information to the working directory.
7486 information to the working directory.
7482
7487
7483 After a successful unshelve, the shelved changes are stored in a
7488 After a successful unshelve, the shelved changes are stored in a
7484 backup directory. Only the N most recent backups are kept. N
7489 backup directory. Only the N most recent backups are kept. N
7485 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7490 defaults to 10 but can be overridden using the ``shelve.maxbackups``
7486 configuration option.
7491 configuration option.
7487
7492
7488 .. container:: verbose
7493 .. container:: verbose
7489
7494
7490 Timestamp in seconds is used to decide order of backups. More
7495 Timestamp in seconds is used to decide order of backups. More
7491 than ``maxbackups`` backups are kept, if same timestamp
7496 than ``maxbackups`` backups are kept, if same timestamp
7492 prevents from deciding exact order of them, for safety.
7497 prevents from deciding exact order of them, for safety.
7493
7498
7494 Selected changes can be unshelved with ``--interactive`` flag.
7499 Selected changes can be unshelved with ``--interactive`` flag.
7495 The working directory is updated with the selected changes, and
7500 The working directory is updated with the selected changes, and
7496 only the unselected changes remain shelved.
7501 only the unselected changes remain shelved.
7497 Note: The whole shelve is applied to working directory first before
7502 Note: The whole shelve is applied to working directory first before
7498 running interactively. So, this will bring up all the conflicts between
7503 running interactively. So, this will bring up all the conflicts between
7499 working directory and the shelve, irrespective of which changes will be
7504 working directory and the shelve, irrespective of which changes will be
7500 unshelved.
7505 unshelved.
7501 """
7506 """
7502 with repo.wlock():
7507 with repo.wlock():
7503 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7508 return shelvemod.unshelvecmd(ui, repo, *shelved, **opts)
7504
7509
7505
7510
7506 statemod.addunfinished(
7511 statemod.addunfinished(
7507 b'unshelve',
7512 b'unshelve',
7508 fname=b'shelvedstate',
7513 fname=b'shelvedstate',
7509 continueflag=True,
7514 continueflag=True,
7510 abortfunc=shelvemod.hgabortunshelve,
7515 abortfunc=shelvemod.hgabortunshelve,
7511 continuefunc=shelvemod.hgcontinueunshelve,
7516 continuefunc=shelvemod.hgcontinueunshelve,
7512 cmdmsg=_(b'unshelve already in progress'),
7517 cmdmsg=_(b'unshelve already in progress'),
7513 )
7518 )
7514
7519
7515
7520
7516 @command(
7521 @command(
7517 b'update|up|checkout|co',
7522 b'update|up|checkout|co',
7518 [
7523 [
7519 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7524 (b'C', b'clean', None, _(b'discard uncommitted changes (no backup)')),
7520 (b'c', b'check', None, _(b'require clean working directory')),
7525 (b'c', b'check', None, _(b'require clean working directory')),
7521 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7526 (b'm', b'merge', None, _(b'merge uncommitted changes')),
7522 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7527 (b'd', b'date', b'', _(b'tipmost revision matching date'), _(b'DATE')),
7523 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7528 (b'r', b'rev', b'', _(b'revision'), _(b'REV')),
7524 ]
7529 ]
7525 + mergetoolopts,
7530 + mergetoolopts,
7526 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7531 _(b'[-C|-c|-m] [-d DATE] [[-r] REV]'),
7527 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7532 helpcategory=command.CATEGORY_WORKING_DIRECTORY,
7528 helpbasic=True,
7533 helpbasic=True,
7529 )
7534 )
7530 def update(ui, repo, node=None, **opts):
7535 def update(ui, repo, node=None, **opts):
7531 """update working directory (or switch revisions)
7536 """update working directory (or switch revisions)
7532
7537
7533 Update the repository's working directory to the specified
7538 Update the repository's working directory to the specified
7534 changeset. If no changeset is specified, update to the tip of the
7539 changeset. If no changeset is specified, update to the tip of the
7535 current named branch and move the active bookmark (see :hg:`help
7540 current named branch and move the active bookmark (see :hg:`help
7536 bookmarks`).
7541 bookmarks`).
7537
7542
7538 Update sets the working directory's parent revision to the specified
7543 Update sets the working directory's parent revision to the specified
7539 changeset (see :hg:`help parents`).
7544 changeset (see :hg:`help parents`).
7540
7545
7541 If the changeset is not a descendant or ancestor of the working
7546 If the changeset is not a descendant or ancestor of the working
7542 directory's parent and there are uncommitted changes, the update is
7547 directory's parent and there are uncommitted changes, the update is
7543 aborted. With the -c/--check option, the working directory is checked
7548 aborted. With the -c/--check option, the working directory is checked
7544 for uncommitted changes; if none are found, the working directory is
7549 for uncommitted changes; if none are found, the working directory is
7545 updated to the specified changeset.
7550 updated to the specified changeset.
7546
7551
7547 .. container:: verbose
7552 .. container:: verbose
7548
7553
7549 The -C/--clean, -c/--check, and -m/--merge options control what
7554 The -C/--clean, -c/--check, and -m/--merge options control what
7550 happens if the working directory contains uncommitted changes.
7555 happens if the working directory contains uncommitted changes.
7551 At most of one of them can be specified.
7556 At most of one of them can be specified.
7552
7557
7553 1. If no option is specified, and if
7558 1. If no option is specified, and if
7554 the requested changeset is an ancestor or descendant of
7559 the requested changeset is an ancestor or descendant of
7555 the working directory's parent, the uncommitted changes
7560 the working directory's parent, the uncommitted changes
7556 are merged into the requested changeset and the merged
7561 are merged into the requested changeset and the merged
7557 result is left uncommitted. If the requested changeset is
7562 result is left uncommitted. If the requested changeset is
7558 not an ancestor or descendant (that is, it is on another
7563 not an ancestor or descendant (that is, it is on another
7559 branch), the update is aborted and the uncommitted changes
7564 branch), the update is aborted and the uncommitted changes
7560 are preserved.
7565 are preserved.
7561
7566
7562 2. With the -m/--merge option, the update is allowed even if the
7567 2. With the -m/--merge option, the update is allowed even if the
7563 requested changeset is not an ancestor or descendant of
7568 requested changeset is not an ancestor or descendant of
7564 the working directory's parent.
7569 the working directory's parent.
7565
7570
7566 3. With the -c/--check option, the update is aborted and the
7571 3. With the -c/--check option, the update is aborted and the
7567 uncommitted changes are preserved.
7572 uncommitted changes are preserved.
7568
7573
7569 4. With the -C/--clean option, uncommitted changes are discarded and
7574 4. With the -C/--clean option, uncommitted changes are discarded and
7570 the working directory is updated to the requested changeset.
7575 the working directory is updated to the requested changeset.
7571
7576
7572 To cancel an uncommitted merge (and lose your changes), use
7577 To cancel an uncommitted merge (and lose your changes), use
7573 :hg:`merge --abort`.
7578 :hg:`merge --abort`.
7574
7579
7575 Use null as the changeset to remove the working directory (like
7580 Use null as the changeset to remove the working directory (like
7576 :hg:`clone -U`).
7581 :hg:`clone -U`).
7577
7582
7578 If you want to revert just one file to an older revision, use
7583 If you want to revert just one file to an older revision, use
7579 :hg:`revert [-r REV] NAME`.
7584 :hg:`revert [-r REV] NAME`.
7580
7585
7581 See :hg:`help dates` for a list of formats valid for -d/--date.
7586 See :hg:`help dates` for a list of formats valid for -d/--date.
7582
7587
7583 Returns 0 on success, 1 if there are unresolved files.
7588 Returns 0 on success, 1 if there are unresolved files.
7584 """
7589 """
7585 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7590 cmdutil.check_at_most_one_arg(opts, 'clean', 'check', 'merge')
7586 rev = opts.get('rev')
7591 rev = opts.get('rev')
7587 date = opts.get('date')
7592 date = opts.get('date')
7588 clean = opts.get('clean')
7593 clean = opts.get('clean')
7589 check = opts.get('check')
7594 check = opts.get('check')
7590 merge = opts.get('merge')
7595 merge = opts.get('merge')
7591 if rev and node:
7596 if rev and node:
7592 raise error.InputError(_(b"please specify just one revision"))
7597 raise error.InputError(_(b"please specify just one revision"))
7593
7598
7594 if ui.configbool(b'commands', b'update.requiredest'):
7599 if ui.configbool(b'commands', b'update.requiredest'):
7595 if not node and not rev and not date:
7600 if not node and not rev and not date:
7596 raise error.InputError(
7601 raise error.InputError(
7597 _(b'you must specify a destination'),
7602 _(b'you must specify a destination'),
7598 hint=_(b'for example: hg update ".::"'),
7603 hint=_(b'for example: hg update ".::"'),
7599 )
7604 )
7600
7605
7601 if rev is None or rev == b'':
7606 if rev is None or rev == b'':
7602 rev = node
7607 rev = node
7603
7608
7604 if date and rev is not None:
7609 if date and rev is not None:
7605 raise error.InputError(_(b"you can't specify a revision and a date"))
7610 raise error.InputError(_(b"you can't specify a revision and a date"))
7606
7611
7607 updatecheck = None
7612 updatecheck = None
7608 if check:
7613 if check:
7609 updatecheck = b'abort'
7614 updatecheck = b'abort'
7610 elif merge:
7615 elif merge:
7611 updatecheck = b'none'
7616 updatecheck = b'none'
7612
7617
7613 with repo.wlock():
7618 with repo.wlock():
7614 cmdutil.clearunfinished(repo)
7619 cmdutil.clearunfinished(repo)
7615 if date:
7620 if date:
7616 rev = cmdutil.finddate(ui, repo, date)
7621 rev = cmdutil.finddate(ui, repo, date)
7617
7622
7618 # if we defined a bookmark, we have to remember the original name
7623 # if we defined a bookmark, we have to remember the original name
7619 brev = rev
7624 brev = rev
7620 if rev:
7625 if rev:
7621 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7626 repo = scmutil.unhidehashlikerevs(repo, [rev], b'nowarn')
7622 ctx = scmutil.revsingle(repo, rev, default=None)
7627 ctx = scmutil.revsingle(repo, rev, default=None)
7623 rev = ctx.rev()
7628 rev = ctx.rev()
7624 hidden = ctx.hidden()
7629 hidden = ctx.hidden()
7625 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7630 overrides = {(b'ui', b'forcemerge'): opts.get('tool', b'')}
7626 with ui.configoverride(overrides, b'update'):
7631 with ui.configoverride(overrides, b'update'):
7627 ret = hg.updatetotally(
7632 ret = hg.updatetotally(
7628 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7633 ui, repo, rev, brev, clean=clean, updatecheck=updatecheck
7629 )
7634 )
7630 if hidden:
7635 if hidden:
7631 ctxstr = ctx.hex()[:12]
7636 ctxstr = ctx.hex()[:12]
7632 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7637 ui.warn(_(b"updated to hidden changeset %s\n") % ctxstr)
7633
7638
7634 if ctx.obsolete():
7639 if ctx.obsolete():
7635 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7640 obsfatemsg = obsutil._getfilteredreason(repo, ctxstr, ctx)
7636 ui.warn(b"(%s)\n" % obsfatemsg)
7641 ui.warn(b"(%s)\n" % obsfatemsg)
7637 return ret
7642 return ret
7638
7643
7639
7644
7640 @command(
7645 @command(
7641 b'verify',
7646 b'verify',
7642 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7647 [(b'', b'full', False, b'perform more checks (EXPERIMENTAL)')],
7643 helpcategory=command.CATEGORY_MAINTENANCE,
7648 helpcategory=command.CATEGORY_MAINTENANCE,
7644 )
7649 )
7645 def verify(ui, repo, **opts):
7650 def verify(ui, repo, **opts):
7646 """verify the integrity of the repository
7651 """verify the integrity of the repository
7647
7652
7648 Verify the integrity of the current repository.
7653 Verify the integrity of the current repository.
7649
7654
7650 This will perform an extensive check of the repository's
7655 This will perform an extensive check of the repository's
7651 integrity, validating the hashes and checksums of each entry in
7656 integrity, validating the hashes and checksums of each entry in
7652 the changelog, manifest, and tracked files, as well as the
7657 the changelog, manifest, and tracked files, as well as the
7653 integrity of their crosslinks and indices.
7658 integrity of their crosslinks and indices.
7654
7659
7655 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7660 Please see https://mercurial-scm.org/wiki/RepositoryCorruption
7656 for more information about recovery from corruption of the
7661 for more information about recovery from corruption of the
7657 repository.
7662 repository.
7658
7663
7659 Returns 0 on success, 1 if errors are encountered.
7664 Returns 0 on success, 1 if errors are encountered.
7660 """
7665 """
7661 opts = pycompat.byteskwargs(opts)
7666 opts = pycompat.byteskwargs(opts)
7662
7667
7663 level = None
7668 level = None
7664 if opts[b'full']:
7669 if opts[b'full']:
7665 level = verifymod.VERIFY_FULL
7670 level = verifymod.VERIFY_FULL
7666 return hg.verify(repo, level)
7671 return hg.verify(repo, level)
7667
7672
7668
7673
7669 @command(
7674 @command(
7670 b'version',
7675 b'version',
7671 [] + formatteropts,
7676 [] + formatteropts,
7672 helpcategory=command.CATEGORY_HELP,
7677 helpcategory=command.CATEGORY_HELP,
7673 norepo=True,
7678 norepo=True,
7674 intents={INTENT_READONLY},
7679 intents={INTENT_READONLY},
7675 )
7680 )
7676 def version_(ui, **opts):
7681 def version_(ui, **opts):
7677 """output version and copyright information
7682 """output version and copyright information
7678
7683
7679 .. container:: verbose
7684 .. container:: verbose
7680
7685
7681 Template:
7686 Template:
7682
7687
7683 The following keywords are supported. See also :hg:`help templates`.
7688 The following keywords are supported. See also :hg:`help templates`.
7684
7689
7685 :extensions: List of extensions.
7690 :extensions: List of extensions.
7686 :ver: String. Version number.
7691 :ver: String. Version number.
7687
7692
7688 And each entry of ``{extensions}`` provides the following sub-keywords
7693 And each entry of ``{extensions}`` provides the following sub-keywords
7689 in addition to ``{ver}``.
7694 in addition to ``{ver}``.
7690
7695
7691 :bundled: Boolean. True if included in the release.
7696 :bundled: Boolean. True if included in the release.
7692 :name: String. Extension name.
7697 :name: String. Extension name.
7693 """
7698 """
7694 opts = pycompat.byteskwargs(opts)
7699 opts = pycompat.byteskwargs(opts)
7695 if ui.verbose:
7700 if ui.verbose:
7696 ui.pager(b'version')
7701 ui.pager(b'version')
7697 fm = ui.formatter(b"version", opts)
7702 fm = ui.formatter(b"version", opts)
7698 fm.startitem()
7703 fm.startitem()
7699 fm.write(
7704 fm.write(
7700 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7705 b"ver", _(b"Mercurial Distributed SCM (version %s)\n"), util.version()
7701 )
7706 )
7702 license = _(
7707 license = _(
7703 b"(see https://mercurial-scm.org for more information)\n"
7708 b"(see https://mercurial-scm.org for more information)\n"
7704 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7709 b"\nCopyright (C) 2005-2020 Matt Mackall and others\n"
7705 b"This is free software; see the source for copying conditions. "
7710 b"This is free software; see the source for copying conditions. "
7706 b"There is NO\nwarranty; "
7711 b"There is NO\nwarranty; "
7707 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7712 b"not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
7708 )
7713 )
7709 if not ui.quiet:
7714 if not ui.quiet:
7710 fm.plain(license)
7715 fm.plain(license)
7711
7716
7712 if ui.verbose:
7717 if ui.verbose:
7713 fm.plain(_(b"\nEnabled extensions:\n\n"))
7718 fm.plain(_(b"\nEnabled extensions:\n\n"))
7714 # format names and versions into columns
7719 # format names and versions into columns
7715 names = []
7720 names = []
7716 vers = []
7721 vers = []
7717 isinternals = []
7722 isinternals = []
7718 for name, module in sorted(extensions.extensions()):
7723 for name, module in sorted(extensions.extensions()):
7719 names.append(name)
7724 names.append(name)
7720 vers.append(extensions.moduleversion(module) or None)
7725 vers.append(extensions.moduleversion(module) or None)
7721 isinternals.append(extensions.ismoduleinternal(module))
7726 isinternals.append(extensions.ismoduleinternal(module))
7722 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7727 fn = fm.nested(b"extensions", tmpl=b'{name}\n')
7723 if names:
7728 if names:
7724 namefmt = b" %%-%ds " % max(len(n) for n in names)
7729 namefmt = b" %%-%ds " % max(len(n) for n in names)
7725 places = [_(b"external"), _(b"internal")]
7730 places = [_(b"external"), _(b"internal")]
7726 for n, v, p in zip(names, vers, isinternals):
7731 for n, v, p in zip(names, vers, isinternals):
7727 fn.startitem()
7732 fn.startitem()
7728 fn.condwrite(ui.verbose, b"name", namefmt, n)
7733 fn.condwrite(ui.verbose, b"name", namefmt, n)
7729 if ui.verbose:
7734 if ui.verbose:
7730 fn.plain(b"%s " % places[p])
7735 fn.plain(b"%s " % places[p])
7731 fn.data(bundled=p)
7736 fn.data(bundled=p)
7732 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7737 fn.condwrite(ui.verbose and v, b"ver", b"%s", v)
7733 if ui.verbose:
7738 if ui.verbose:
7734 fn.plain(b"\n")
7739 fn.plain(b"\n")
7735 fn.end()
7740 fn.end()
7736 fm.end()
7741 fm.end()
7737
7742
7738
7743
7739 def loadcmdtable(ui, name, cmdtable):
7744 def loadcmdtable(ui, name, cmdtable):
7740 """Load command functions from specified cmdtable"""
7745 """Load command functions from specified cmdtable"""
7741 overrides = [cmd for cmd in cmdtable if cmd in table]
7746 overrides = [cmd for cmd in cmdtable if cmd in table]
7742 if overrides:
7747 if overrides:
7743 ui.warn(
7748 ui.warn(
7744 _(b"extension '%s' overrides commands: %s\n")
7749 _(b"extension '%s' overrides commands: %s\n")
7745 % (name, b" ".join(overrides))
7750 % (name, b" ".join(overrides))
7746 )
7751 )
7747 table.update(cmdtable)
7752 table.update(cmdtable)
@@ -1,2530 +1,2535
1 # configitems.py - centralized declaration of configuration option
1 # configitems.py - centralized declaration of configuration option
2 #
2 #
3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
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 __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import functools
10 import functools
11 import re
11 import re
12
12
13 from . import (
13 from . import (
14 encoding,
14 encoding,
15 error,
15 error,
16 )
16 )
17
17
18
18
19 def loadconfigtable(ui, extname, configtable):
19 def loadconfigtable(ui, extname, configtable):
20 """update config item known to the ui with the extension ones"""
20 """update config item known to the ui with the extension ones"""
21 for section, items in sorted(configtable.items()):
21 for section, items in sorted(configtable.items()):
22 knownitems = ui._knownconfig.setdefault(section, itemregister())
22 knownitems = ui._knownconfig.setdefault(section, itemregister())
23 knownkeys = set(knownitems)
23 knownkeys = set(knownitems)
24 newkeys = set(items)
24 newkeys = set(items)
25 for key in sorted(knownkeys & newkeys):
25 for key in sorted(knownkeys & newkeys):
26 msg = b"extension '%s' overwrite config item '%s.%s'"
26 msg = b"extension '%s' overwrite config item '%s.%s'"
27 msg %= (extname, section, key)
27 msg %= (extname, section, key)
28 ui.develwarn(msg, config=b'warn-config')
28 ui.develwarn(msg, config=b'warn-config')
29
29
30 knownitems.update(items)
30 knownitems.update(items)
31
31
32
32
33 class configitem(object):
33 class configitem(object):
34 """represent a known config item
34 """represent a known config item
35
35
36 :section: the official config section where to find this item,
36 :section: the official config section where to find this item,
37 :name: the official name within the section,
37 :name: the official name within the section,
38 :default: default value for this item,
38 :default: default value for this item,
39 :alias: optional list of tuples as alternatives,
39 :alias: optional list of tuples as alternatives,
40 :generic: this is a generic definition, match name using regular expression.
40 :generic: this is a generic definition, match name using regular expression.
41 """
41 """
42
42
43 def __init__(
43 def __init__(
44 self,
44 self,
45 section,
45 section,
46 name,
46 name,
47 default=None,
47 default=None,
48 alias=(),
48 alias=(),
49 generic=False,
49 generic=False,
50 priority=0,
50 priority=0,
51 experimental=False,
51 experimental=False,
52 ):
52 ):
53 self.section = section
53 self.section = section
54 self.name = name
54 self.name = name
55 self.default = default
55 self.default = default
56 self.alias = list(alias)
56 self.alias = list(alias)
57 self.generic = generic
57 self.generic = generic
58 self.priority = priority
58 self.priority = priority
59 self.experimental = experimental
59 self.experimental = experimental
60 self._re = None
60 self._re = None
61 if generic:
61 if generic:
62 self._re = re.compile(self.name)
62 self._re = re.compile(self.name)
63
63
64
64
65 class itemregister(dict):
65 class itemregister(dict):
66 """A specialized dictionary that can handle wild-card selection"""
66 """A specialized dictionary that can handle wild-card selection"""
67
67
68 def __init__(self):
68 def __init__(self):
69 super(itemregister, self).__init__()
69 super(itemregister, self).__init__()
70 self._generics = set()
70 self._generics = set()
71
71
72 def update(self, other):
72 def update(self, other):
73 super(itemregister, self).update(other)
73 super(itemregister, self).update(other)
74 self._generics.update(other._generics)
74 self._generics.update(other._generics)
75
75
76 def __setitem__(self, key, item):
76 def __setitem__(self, key, item):
77 super(itemregister, self).__setitem__(key, item)
77 super(itemregister, self).__setitem__(key, item)
78 if item.generic:
78 if item.generic:
79 self._generics.add(item)
79 self._generics.add(item)
80
80
81 def get(self, key):
81 def get(self, key):
82 baseitem = super(itemregister, self).get(key)
82 baseitem = super(itemregister, self).get(key)
83 if baseitem is not None and not baseitem.generic:
83 if baseitem is not None and not baseitem.generic:
84 return baseitem
84 return baseitem
85
85
86 # search for a matching generic item
86 # search for a matching generic item
87 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
87 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
88 for item in generics:
88 for item in generics:
89 # we use 'match' instead of 'search' to make the matching simpler
89 # we use 'match' instead of 'search' to make the matching simpler
90 # for people unfamiliar with regular expression. Having the match
90 # for people unfamiliar with regular expression. Having the match
91 # rooted to the start of the string will produce less surprising
91 # rooted to the start of the string will produce less surprising
92 # result for user writing simple regex for sub-attribute.
92 # result for user writing simple regex for sub-attribute.
93 #
93 #
94 # For example using "color\..*" match produces an unsurprising
94 # For example using "color\..*" match produces an unsurprising
95 # result, while using search could suddenly match apparently
95 # result, while using search could suddenly match apparently
96 # unrelated configuration that happens to contains "color."
96 # unrelated configuration that happens to contains "color."
97 # anywhere. This is a tradeoff where we favor requiring ".*" on
97 # anywhere. This is a tradeoff where we favor requiring ".*" on
98 # some match to avoid the need to prefix most pattern with "^".
98 # some match to avoid the need to prefix most pattern with "^".
99 # The "^" seems more error prone.
99 # The "^" seems more error prone.
100 if item._re.match(key):
100 if item._re.match(key):
101 return item
101 return item
102
102
103 return None
103 return None
104
104
105
105
106 coreitems = {}
106 coreitems = {}
107
107
108
108
109 def _register(configtable, *args, **kwargs):
109 def _register(configtable, *args, **kwargs):
110 item = configitem(*args, **kwargs)
110 item = configitem(*args, **kwargs)
111 section = configtable.setdefault(item.section, itemregister())
111 section = configtable.setdefault(item.section, itemregister())
112 if item.name in section:
112 if item.name in section:
113 msg = b"duplicated config item registration for '%s.%s'"
113 msg = b"duplicated config item registration for '%s.%s'"
114 raise error.ProgrammingError(msg % (item.section, item.name))
114 raise error.ProgrammingError(msg % (item.section, item.name))
115 section[item.name] = item
115 section[item.name] = item
116
116
117
117
118 # special value for case where the default is derived from other values
118 # special value for case where the default is derived from other values
119 dynamicdefault = object()
119 dynamicdefault = object()
120
120
121 # Registering actual config items
121 # Registering actual config items
122
122
123
123
124 def getitemregister(configtable):
124 def getitemregister(configtable):
125 f = functools.partial(_register, configtable)
125 f = functools.partial(_register, configtable)
126 # export pseudo enum as configitem.*
126 # export pseudo enum as configitem.*
127 f.dynamicdefault = dynamicdefault
127 f.dynamicdefault = dynamicdefault
128 return f
128 return f
129
129
130
130
131 coreconfigitem = getitemregister(coreitems)
131 coreconfigitem = getitemregister(coreitems)
132
132
133
133
134 def _registerdiffopts(section, configprefix=b''):
134 def _registerdiffopts(section, configprefix=b''):
135 coreconfigitem(
135 coreconfigitem(
136 section,
136 section,
137 configprefix + b'nodates',
137 configprefix + b'nodates',
138 default=False,
138 default=False,
139 )
139 )
140 coreconfigitem(
140 coreconfigitem(
141 section,
141 section,
142 configprefix + b'showfunc',
142 configprefix + b'showfunc',
143 default=False,
143 default=False,
144 )
144 )
145 coreconfigitem(
145 coreconfigitem(
146 section,
146 section,
147 configprefix + b'unified',
147 configprefix + b'unified',
148 default=None,
148 default=None,
149 )
149 )
150 coreconfigitem(
150 coreconfigitem(
151 section,
151 section,
152 configprefix + b'git',
152 configprefix + b'git',
153 default=False,
153 default=False,
154 )
154 )
155 coreconfigitem(
155 coreconfigitem(
156 section,
156 section,
157 configprefix + b'ignorews',
157 configprefix + b'ignorews',
158 default=False,
158 default=False,
159 )
159 )
160 coreconfigitem(
160 coreconfigitem(
161 section,
161 section,
162 configprefix + b'ignorewsamount',
162 configprefix + b'ignorewsamount',
163 default=False,
163 default=False,
164 )
164 )
165 coreconfigitem(
165 coreconfigitem(
166 section,
166 section,
167 configprefix + b'ignoreblanklines',
167 configprefix + b'ignoreblanklines',
168 default=False,
168 default=False,
169 )
169 )
170 coreconfigitem(
170 coreconfigitem(
171 section,
171 section,
172 configprefix + b'ignorewseol',
172 configprefix + b'ignorewseol',
173 default=False,
173 default=False,
174 )
174 )
175 coreconfigitem(
175 coreconfigitem(
176 section,
176 section,
177 configprefix + b'nobinary',
177 configprefix + b'nobinary',
178 default=False,
178 default=False,
179 )
179 )
180 coreconfigitem(
180 coreconfigitem(
181 section,
181 section,
182 configprefix + b'noprefix',
182 configprefix + b'noprefix',
183 default=False,
183 default=False,
184 )
184 )
185 coreconfigitem(
185 coreconfigitem(
186 section,
186 section,
187 configprefix + b'word-diff',
187 configprefix + b'word-diff',
188 default=False,
188 default=False,
189 )
189 )
190
190
191
191
192 coreconfigitem(
192 coreconfigitem(
193 b'alias',
193 b'alias',
194 b'.*',
194 b'.*',
195 default=dynamicdefault,
195 default=dynamicdefault,
196 generic=True,
196 generic=True,
197 )
197 )
198 coreconfigitem(
198 coreconfigitem(
199 b'auth',
199 b'auth',
200 b'cookiefile',
200 b'cookiefile',
201 default=None,
201 default=None,
202 )
202 )
203 _registerdiffopts(section=b'annotate')
203 _registerdiffopts(section=b'annotate')
204 # bookmarks.pushing: internal hack for discovery
204 # bookmarks.pushing: internal hack for discovery
205 coreconfigitem(
205 coreconfigitem(
206 b'bookmarks',
206 b'bookmarks',
207 b'pushing',
207 b'pushing',
208 default=list,
208 default=list,
209 )
209 )
210 # bundle.mainreporoot: internal hack for bundlerepo
210 # bundle.mainreporoot: internal hack for bundlerepo
211 coreconfigitem(
211 coreconfigitem(
212 b'bundle',
212 b'bundle',
213 b'mainreporoot',
213 b'mainreporoot',
214 default=b'',
214 default=b'',
215 )
215 )
216 coreconfigitem(
216 coreconfigitem(
217 b'censor',
217 b'censor',
218 b'policy',
218 b'policy',
219 default=b'abort',
219 default=b'abort',
220 experimental=True,
220 experimental=True,
221 )
221 )
222 coreconfigitem(
222 coreconfigitem(
223 b'chgserver',
223 b'chgserver',
224 b'idletimeout',
224 b'idletimeout',
225 default=3600,
225 default=3600,
226 )
226 )
227 coreconfigitem(
227 coreconfigitem(
228 b'chgserver',
228 b'chgserver',
229 b'skiphash',
229 b'skiphash',
230 default=False,
230 default=False,
231 )
231 )
232 coreconfigitem(
232 coreconfigitem(
233 b'cmdserver',
233 b'cmdserver',
234 b'log',
234 b'log',
235 default=None,
235 default=None,
236 )
236 )
237 coreconfigitem(
237 coreconfigitem(
238 b'cmdserver',
238 b'cmdserver',
239 b'max-log-files',
239 b'max-log-files',
240 default=7,
240 default=7,
241 )
241 )
242 coreconfigitem(
242 coreconfigitem(
243 b'cmdserver',
243 b'cmdserver',
244 b'max-log-size',
244 b'max-log-size',
245 default=b'1 MB',
245 default=b'1 MB',
246 )
246 )
247 coreconfigitem(
247 coreconfigitem(
248 b'cmdserver',
248 b'cmdserver',
249 b'max-repo-cache',
249 b'max-repo-cache',
250 default=0,
250 default=0,
251 experimental=True,
251 experimental=True,
252 )
252 )
253 coreconfigitem(
253 coreconfigitem(
254 b'cmdserver',
254 b'cmdserver',
255 b'message-encodings',
255 b'message-encodings',
256 default=list,
256 default=list,
257 )
257 )
258 coreconfigitem(
258 coreconfigitem(
259 b'cmdserver',
259 b'cmdserver',
260 b'track-log',
260 b'track-log',
261 default=lambda: [b'chgserver', b'cmdserver', b'repocache'],
261 default=lambda: [b'chgserver', b'cmdserver', b'repocache'],
262 )
262 )
263 coreconfigitem(
263 coreconfigitem(
264 b'cmdserver',
264 b'cmdserver',
265 b'shutdown-on-interrupt',
265 b'shutdown-on-interrupt',
266 default=True,
266 default=True,
267 )
267 )
268 coreconfigitem(
268 coreconfigitem(
269 b'color',
269 b'color',
270 b'.*',
270 b'.*',
271 default=None,
271 default=None,
272 generic=True,
272 generic=True,
273 )
273 )
274 coreconfigitem(
274 coreconfigitem(
275 b'color',
275 b'color',
276 b'mode',
276 b'mode',
277 default=b'auto',
277 default=b'auto',
278 )
278 )
279 coreconfigitem(
279 coreconfigitem(
280 b'color',
280 b'color',
281 b'pagermode',
281 b'pagermode',
282 default=dynamicdefault,
282 default=dynamicdefault,
283 )
283 )
284 coreconfigitem(
284 coreconfigitem(
285 b'command-templates',
285 b'command-templates',
286 b'graphnode',
286 b'graphnode',
287 default=None,
287 default=None,
288 alias=[(b'ui', b'graphnodetemplate')],
288 alias=[(b'ui', b'graphnodetemplate')],
289 )
289 )
290 coreconfigitem(
290 coreconfigitem(
291 b'command-templates',
291 b'command-templates',
292 b'log',
292 b'log',
293 default=None,
293 default=None,
294 alias=[(b'ui', b'logtemplate')],
294 alias=[(b'ui', b'logtemplate')],
295 )
295 )
296 coreconfigitem(
296 coreconfigitem(
297 b'command-templates',
297 b'command-templates',
298 b'mergemarker',
298 b'mergemarker',
299 default=(
299 default=(
300 b'{node|short} '
300 b'{node|short} '
301 b'{ifeq(tags, "tip", "", '
301 b'{ifeq(tags, "tip", "", '
302 b'ifeq(tags, "", "", "{tags} "))}'
302 b'ifeq(tags, "", "", "{tags} "))}'
303 b'{if(bookmarks, "{bookmarks} ")}'
303 b'{if(bookmarks, "{bookmarks} ")}'
304 b'{ifeq(branch, "default", "", "{branch} ")}'
304 b'{ifeq(branch, "default", "", "{branch} ")}'
305 b'- {author|user}: {desc|firstline}'
305 b'- {author|user}: {desc|firstline}'
306 ),
306 ),
307 alias=[(b'ui', b'mergemarkertemplate')],
307 alias=[(b'ui', b'mergemarkertemplate')],
308 )
308 )
309 coreconfigitem(
309 coreconfigitem(
310 b'command-templates',
310 b'command-templates',
311 b'pre-merge-tool-output',
311 b'pre-merge-tool-output',
312 default=None,
312 default=None,
313 alias=[(b'ui', b'pre-merge-tool-output-template')],
313 alias=[(b'ui', b'pre-merge-tool-output-template')],
314 )
314 )
315 coreconfigitem(
315 coreconfigitem(
316 b'command-templates',
316 b'command-templates',
317 b'oneline-summary',
317 b'oneline-summary',
318 default=None,
318 default=None,
319 )
319 )
320 coreconfigitem(
320 coreconfigitem(
321 b'command-templates',
321 b'command-templates',
322 b'oneline-summary.*',
322 b'oneline-summary.*',
323 default=dynamicdefault,
323 default=dynamicdefault,
324 generic=True,
324 generic=True,
325 )
325 )
326 _registerdiffopts(section=b'commands', configprefix=b'commit.interactive.')
326 _registerdiffopts(section=b'commands', configprefix=b'commit.interactive.')
327 coreconfigitem(
327 coreconfigitem(
328 b'commands',
328 b'commands',
329 b'commit.post-status',
329 b'commit.post-status',
330 default=False,
330 default=False,
331 )
331 )
332 coreconfigitem(
332 coreconfigitem(
333 b'commands',
333 b'commands',
334 b'grep.all-files',
334 b'grep.all-files',
335 default=False,
335 default=False,
336 experimental=True,
336 experimental=True,
337 )
337 )
338 coreconfigitem(
338 coreconfigitem(
339 b'commands',
339 b'commands',
340 b'merge.require-rev',
340 b'merge.require-rev',
341 default=False,
341 default=False,
342 )
342 )
343 coreconfigitem(
343 coreconfigitem(
344 b'commands',
344 b'commands',
345 b'push.require-revs',
345 b'push.require-revs',
346 default=False,
346 default=False,
347 )
347 )
348 coreconfigitem(
348 coreconfigitem(
349 b'commands',
349 b'commands',
350 b'resolve.confirm',
350 b'resolve.confirm',
351 default=False,
351 default=False,
352 )
352 )
353 coreconfigitem(
353 coreconfigitem(
354 b'commands',
354 b'commands',
355 b'resolve.explicit-re-merge',
355 b'resolve.explicit-re-merge',
356 default=False,
356 default=False,
357 )
357 )
358 coreconfigitem(
358 coreconfigitem(
359 b'commands',
359 b'commands',
360 b'resolve.mark-check',
360 b'resolve.mark-check',
361 default=b'none',
361 default=b'none',
362 )
362 )
363 _registerdiffopts(section=b'commands', configprefix=b'revert.interactive.')
363 _registerdiffopts(section=b'commands', configprefix=b'revert.interactive.')
364 coreconfigitem(
364 coreconfigitem(
365 b'commands',
365 b'commands',
366 b'show.aliasprefix',
366 b'show.aliasprefix',
367 default=list,
367 default=list,
368 )
368 )
369 coreconfigitem(
369 coreconfigitem(
370 b'commands',
370 b'commands',
371 b'status.relative',
371 b'status.relative',
372 default=False,
372 default=False,
373 )
373 )
374 coreconfigitem(
374 coreconfigitem(
375 b'commands',
375 b'commands',
376 b'status.skipstates',
376 b'status.skipstates',
377 default=[],
377 default=[],
378 experimental=True,
378 experimental=True,
379 )
379 )
380 coreconfigitem(
380 coreconfigitem(
381 b'commands',
381 b'commands',
382 b'status.terse',
382 b'status.terse',
383 default=b'',
383 default=b'',
384 )
384 )
385 coreconfigitem(
385 coreconfigitem(
386 b'commands',
386 b'commands',
387 b'status.verbose',
387 b'status.verbose',
388 default=False,
388 default=False,
389 )
389 )
390 coreconfigitem(
390 coreconfigitem(
391 b'commands',
391 b'commands',
392 b'update.check',
392 b'update.check',
393 default=None,
393 default=None,
394 )
394 )
395 coreconfigitem(
395 coreconfigitem(
396 b'commands',
396 b'commands',
397 b'update.requiredest',
397 b'update.requiredest',
398 default=False,
398 default=False,
399 )
399 )
400 coreconfigitem(
400 coreconfigitem(
401 b'committemplate',
401 b'committemplate',
402 b'.*',
402 b'.*',
403 default=None,
403 default=None,
404 generic=True,
404 generic=True,
405 )
405 )
406 coreconfigitem(
406 coreconfigitem(
407 b'convert',
407 b'convert',
408 b'bzr.saverev',
408 b'bzr.saverev',
409 default=True,
409 default=True,
410 )
410 )
411 coreconfigitem(
411 coreconfigitem(
412 b'convert',
412 b'convert',
413 b'cvsps.cache',
413 b'cvsps.cache',
414 default=True,
414 default=True,
415 )
415 )
416 coreconfigitem(
416 coreconfigitem(
417 b'convert',
417 b'convert',
418 b'cvsps.fuzz',
418 b'cvsps.fuzz',
419 default=60,
419 default=60,
420 )
420 )
421 coreconfigitem(
421 coreconfigitem(
422 b'convert',
422 b'convert',
423 b'cvsps.logencoding',
423 b'cvsps.logencoding',
424 default=None,
424 default=None,
425 )
425 )
426 coreconfigitem(
426 coreconfigitem(
427 b'convert',
427 b'convert',
428 b'cvsps.mergefrom',
428 b'cvsps.mergefrom',
429 default=None,
429 default=None,
430 )
430 )
431 coreconfigitem(
431 coreconfigitem(
432 b'convert',
432 b'convert',
433 b'cvsps.mergeto',
433 b'cvsps.mergeto',
434 default=None,
434 default=None,
435 )
435 )
436 coreconfigitem(
436 coreconfigitem(
437 b'convert',
437 b'convert',
438 b'git.committeractions',
438 b'git.committeractions',
439 default=lambda: [b'messagedifferent'],
439 default=lambda: [b'messagedifferent'],
440 )
440 )
441 coreconfigitem(
441 coreconfigitem(
442 b'convert',
442 b'convert',
443 b'git.extrakeys',
443 b'git.extrakeys',
444 default=list,
444 default=list,
445 )
445 )
446 coreconfigitem(
446 coreconfigitem(
447 b'convert',
447 b'convert',
448 b'git.findcopiesharder',
448 b'git.findcopiesharder',
449 default=False,
449 default=False,
450 )
450 )
451 coreconfigitem(
451 coreconfigitem(
452 b'convert',
452 b'convert',
453 b'git.remoteprefix',
453 b'git.remoteprefix',
454 default=b'remote',
454 default=b'remote',
455 )
455 )
456 coreconfigitem(
456 coreconfigitem(
457 b'convert',
457 b'convert',
458 b'git.renamelimit',
458 b'git.renamelimit',
459 default=400,
459 default=400,
460 )
460 )
461 coreconfigitem(
461 coreconfigitem(
462 b'convert',
462 b'convert',
463 b'git.saverev',
463 b'git.saverev',
464 default=True,
464 default=True,
465 )
465 )
466 coreconfigitem(
466 coreconfigitem(
467 b'convert',
467 b'convert',
468 b'git.similarity',
468 b'git.similarity',
469 default=50,
469 default=50,
470 )
470 )
471 coreconfigitem(
471 coreconfigitem(
472 b'convert',
472 b'convert',
473 b'git.skipsubmodules',
473 b'git.skipsubmodules',
474 default=False,
474 default=False,
475 )
475 )
476 coreconfigitem(
476 coreconfigitem(
477 b'convert',
477 b'convert',
478 b'hg.clonebranches',
478 b'hg.clonebranches',
479 default=False,
479 default=False,
480 )
480 )
481 coreconfigitem(
481 coreconfigitem(
482 b'convert',
482 b'convert',
483 b'hg.ignoreerrors',
483 b'hg.ignoreerrors',
484 default=False,
484 default=False,
485 )
485 )
486 coreconfigitem(
486 coreconfigitem(
487 b'convert',
487 b'convert',
488 b'hg.preserve-hash',
488 b'hg.preserve-hash',
489 default=False,
489 default=False,
490 )
490 )
491 coreconfigitem(
491 coreconfigitem(
492 b'convert',
492 b'convert',
493 b'hg.revs',
493 b'hg.revs',
494 default=None,
494 default=None,
495 )
495 )
496 coreconfigitem(
496 coreconfigitem(
497 b'convert',
497 b'convert',
498 b'hg.saverev',
498 b'hg.saverev',
499 default=False,
499 default=False,
500 )
500 )
501 coreconfigitem(
501 coreconfigitem(
502 b'convert',
502 b'convert',
503 b'hg.sourcename',
503 b'hg.sourcename',
504 default=None,
504 default=None,
505 )
505 )
506 coreconfigitem(
506 coreconfigitem(
507 b'convert',
507 b'convert',
508 b'hg.startrev',
508 b'hg.startrev',
509 default=None,
509 default=None,
510 )
510 )
511 coreconfigitem(
511 coreconfigitem(
512 b'convert',
512 b'convert',
513 b'hg.tagsbranch',
513 b'hg.tagsbranch',
514 default=b'default',
514 default=b'default',
515 )
515 )
516 coreconfigitem(
516 coreconfigitem(
517 b'convert',
517 b'convert',
518 b'hg.usebranchnames',
518 b'hg.usebranchnames',
519 default=True,
519 default=True,
520 )
520 )
521 coreconfigitem(
521 coreconfigitem(
522 b'convert',
522 b'convert',
523 b'ignoreancestorcheck',
523 b'ignoreancestorcheck',
524 default=False,
524 default=False,
525 experimental=True,
525 experimental=True,
526 )
526 )
527 coreconfigitem(
527 coreconfigitem(
528 b'convert',
528 b'convert',
529 b'localtimezone',
529 b'localtimezone',
530 default=False,
530 default=False,
531 )
531 )
532 coreconfigitem(
532 coreconfigitem(
533 b'convert',
533 b'convert',
534 b'p4.encoding',
534 b'p4.encoding',
535 default=dynamicdefault,
535 default=dynamicdefault,
536 )
536 )
537 coreconfigitem(
537 coreconfigitem(
538 b'convert',
538 b'convert',
539 b'p4.startrev',
539 b'p4.startrev',
540 default=0,
540 default=0,
541 )
541 )
542 coreconfigitem(
542 coreconfigitem(
543 b'convert',
543 b'convert',
544 b'skiptags',
544 b'skiptags',
545 default=False,
545 default=False,
546 )
546 )
547 coreconfigitem(
547 coreconfigitem(
548 b'convert',
548 b'convert',
549 b'svn.debugsvnlog',
549 b'svn.debugsvnlog',
550 default=True,
550 default=True,
551 )
551 )
552 coreconfigitem(
552 coreconfigitem(
553 b'convert',
553 b'convert',
554 b'svn.trunk',
554 b'svn.trunk',
555 default=None,
555 default=None,
556 )
556 )
557 coreconfigitem(
557 coreconfigitem(
558 b'convert',
558 b'convert',
559 b'svn.tags',
559 b'svn.tags',
560 default=None,
560 default=None,
561 )
561 )
562 coreconfigitem(
562 coreconfigitem(
563 b'convert',
563 b'convert',
564 b'svn.branches',
564 b'svn.branches',
565 default=None,
565 default=None,
566 )
566 )
567 coreconfigitem(
567 coreconfigitem(
568 b'convert',
568 b'convert',
569 b'svn.startrev',
569 b'svn.startrev',
570 default=0,
570 default=0,
571 )
571 )
572 coreconfigitem(
572 coreconfigitem(
573 b'debug',
573 b'debug',
574 b'dirstate.delaywrite',
574 b'dirstate.delaywrite',
575 default=0,
575 default=0,
576 )
576 )
577 coreconfigitem(
577 coreconfigitem(
578 b'defaults',
578 b'defaults',
579 b'.*',
579 b'.*',
580 default=None,
580 default=None,
581 generic=True,
581 generic=True,
582 )
582 )
583 coreconfigitem(
583 coreconfigitem(
584 b'devel',
584 b'devel',
585 b'all-warnings',
585 b'all-warnings',
586 default=False,
586 default=False,
587 )
587 )
588 coreconfigitem(
588 coreconfigitem(
589 b'devel',
589 b'devel',
590 b'bundle2.debug',
590 b'bundle2.debug',
591 default=False,
591 default=False,
592 )
592 )
593 coreconfigitem(
593 coreconfigitem(
594 b'devel',
594 b'devel',
595 b'bundle.delta',
595 b'bundle.delta',
596 default=b'',
596 default=b'',
597 )
597 )
598 coreconfigitem(
598 coreconfigitem(
599 b'devel',
599 b'devel',
600 b'cache-vfs',
600 b'cache-vfs',
601 default=None,
601 default=None,
602 )
602 )
603 coreconfigitem(
603 coreconfigitem(
604 b'devel',
604 b'devel',
605 b'check-locks',
605 b'check-locks',
606 default=False,
606 default=False,
607 )
607 )
608 coreconfigitem(
608 coreconfigitem(
609 b'devel',
609 b'devel',
610 b'check-relroot',
610 b'check-relroot',
611 default=False,
611 default=False,
612 )
612 )
613 coreconfigitem(
613 coreconfigitem(
614 b'devel',
614 b'devel',
615 b'default-date',
615 b'default-date',
616 default=None,
616 default=None,
617 )
617 )
618 coreconfigitem(
618 coreconfigitem(
619 b'devel',
619 b'devel',
620 b'deprec-warn',
620 b'deprec-warn',
621 default=False,
621 default=False,
622 )
622 )
623 coreconfigitem(
623 coreconfigitem(
624 b'devel',
624 b'devel',
625 b'disableloaddefaultcerts',
625 b'disableloaddefaultcerts',
626 default=False,
626 default=False,
627 )
627 )
628 coreconfigitem(
628 coreconfigitem(
629 b'devel',
629 b'devel',
630 b'warn-empty-changegroup',
630 b'warn-empty-changegroup',
631 default=False,
631 default=False,
632 )
632 )
633 coreconfigitem(
633 coreconfigitem(
634 b'devel',
634 b'devel',
635 b'legacy.exchange',
635 b'legacy.exchange',
636 default=list,
636 default=list,
637 )
637 )
638 coreconfigitem(
638 coreconfigitem(
639 b'devel',
639 b'devel',
640 b'persistent-nodemap',
640 b'persistent-nodemap',
641 default=False,
641 default=False,
642 )
642 )
643 coreconfigitem(
643 coreconfigitem(
644 b'devel',
644 b'devel',
645 b'servercafile',
645 b'servercafile',
646 default=b'',
646 default=b'',
647 )
647 )
648 coreconfigitem(
648 coreconfigitem(
649 b'devel',
649 b'devel',
650 b'serverexactprotocol',
650 b'serverexactprotocol',
651 default=b'',
651 default=b'',
652 )
652 )
653 coreconfigitem(
653 coreconfigitem(
654 b'devel',
654 b'devel',
655 b'serverrequirecert',
655 b'serverrequirecert',
656 default=False,
656 default=False,
657 )
657 )
658 coreconfigitem(
658 coreconfigitem(
659 b'devel',
659 b'devel',
660 b'strip-obsmarkers',
660 b'strip-obsmarkers',
661 default=True,
661 default=True,
662 )
662 )
663 coreconfigitem(
663 coreconfigitem(
664 b'devel',
664 b'devel',
665 b'warn-config',
665 b'warn-config',
666 default=None,
666 default=None,
667 )
667 )
668 coreconfigitem(
668 coreconfigitem(
669 b'devel',
669 b'devel',
670 b'warn-config-default',
670 b'warn-config-default',
671 default=None,
671 default=None,
672 )
672 )
673 coreconfigitem(
673 coreconfigitem(
674 b'devel',
674 b'devel',
675 b'user.obsmarker',
675 b'user.obsmarker',
676 default=None,
676 default=None,
677 )
677 )
678 coreconfigitem(
678 coreconfigitem(
679 b'devel',
679 b'devel',
680 b'warn-config-unknown',
680 b'warn-config-unknown',
681 default=None,
681 default=None,
682 )
682 )
683 coreconfigitem(
683 coreconfigitem(
684 b'devel',
684 b'devel',
685 b'debug.copies',
685 b'debug.copies',
686 default=False,
686 default=False,
687 )
687 )
688 coreconfigitem(
688 coreconfigitem(
689 b'devel',
689 b'devel',
690 b'debug.extensions',
690 b'debug.extensions',
691 default=False,
691 default=False,
692 )
692 )
693 coreconfigitem(
693 coreconfigitem(
694 b'devel',
694 b'devel',
695 b'debug.repo-filters',
695 b'debug.repo-filters',
696 default=False,
696 default=False,
697 )
697 )
698 coreconfigitem(
698 coreconfigitem(
699 b'devel',
699 b'devel',
700 b'debug.peer-request',
700 b'debug.peer-request',
701 default=False,
701 default=False,
702 )
702 )
703 coreconfigitem(
703 coreconfigitem(
704 b'devel',
704 b'devel',
705 b'discovery.randomize',
705 b'discovery.randomize',
706 default=True,
706 default=True,
707 )
707 )
708 _registerdiffopts(section=b'diff')
708 _registerdiffopts(section=b'diff')
709 coreconfigitem(
709 coreconfigitem(
710 b'email',
710 b'email',
711 b'bcc',
711 b'bcc',
712 default=None,
712 default=None,
713 )
713 )
714 coreconfigitem(
714 coreconfigitem(
715 b'email',
715 b'email',
716 b'cc',
716 b'cc',
717 default=None,
717 default=None,
718 )
718 )
719 coreconfigitem(
719 coreconfigitem(
720 b'email',
720 b'email',
721 b'charsets',
721 b'charsets',
722 default=list,
722 default=list,
723 )
723 )
724 coreconfigitem(
724 coreconfigitem(
725 b'email',
725 b'email',
726 b'from',
726 b'from',
727 default=None,
727 default=None,
728 )
728 )
729 coreconfigitem(
729 coreconfigitem(
730 b'email',
730 b'email',
731 b'method',
731 b'method',
732 default=b'smtp',
732 default=b'smtp',
733 )
733 )
734 coreconfigitem(
734 coreconfigitem(
735 b'email',
735 b'email',
736 b'reply-to',
736 b'reply-to',
737 default=None,
737 default=None,
738 )
738 )
739 coreconfigitem(
739 coreconfigitem(
740 b'email',
740 b'email',
741 b'to',
741 b'to',
742 default=None,
742 default=None,
743 )
743 )
744 coreconfigitem(
744 coreconfigitem(
745 b'experimental',
745 b'experimental',
746 b'archivemetatemplate',
746 b'archivemetatemplate',
747 default=dynamicdefault,
747 default=dynamicdefault,
748 )
748 )
749 coreconfigitem(
749 coreconfigitem(
750 b'experimental',
750 b'experimental',
751 b'auto-publish',
751 b'auto-publish',
752 default=b'publish',
752 default=b'publish',
753 )
753 )
754 coreconfigitem(
754 coreconfigitem(
755 b'experimental',
755 b'experimental',
756 b'bundle-phases',
756 b'bundle-phases',
757 default=False,
757 default=False,
758 )
758 )
759 coreconfigitem(
759 coreconfigitem(
760 b'experimental',
760 b'experimental',
761 b'bundle2-advertise',
761 b'bundle2-advertise',
762 default=True,
762 default=True,
763 )
763 )
764 coreconfigitem(
764 coreconfigitem(
765 b'experimental',
765 b'experimental',
766 b'bundle2-output-capture',
766 b'bundle2-output-capture',
767 default=False,
767 default=False,
768 )
768 )
769 coreconfigitem(
769 coreconfigitem(
770 b'experimental',
770 b'experimental',
771 b'bundle2.pushback',
771 b'bundle2.pushback',
772 default=False,
772 default=False,
773 )
773 )
774 coreconfigitem(
774 coreconfigitem(
775 b'experimental',
775 b'experimental',
776 b'bundle2lazylocking',
776 b'bundle2lazylocking',
777 default=False,
777 default=False,
778 )
778 )
779 coreconfigitem(
779 coreconfigitem(
780 b'experimental',
780 b'experimental',
781 b'bundlecomplevel',
781 b'bundlecomplevel',
782 default=None,
782 default=None,
783 )
783 )
784 coreconfigitem(
784 coreconfigitem(
785 b'experimental',
785 b'experimental',
786 b'bundlecomplevel.bzip2',
786 b'bundlecomplevel.bzip2',
787 default=None,
787 default=None,
788 )
788 )
789 coreconfigitem(
789 coreconfigitem(
790 b'experimental',
790 b'experimental',
791 b'bundlecomplevel.gzip',
791 b'bundlecomplevel.gzip',
792 default=None,
792 default=None,
793 )
793 )
794 coreconfigitem(
794 coreconfigitem(
795 b'experimental',
795 b'experimental',
796 b'bundlecomplevel.none',
796 b'bundlecomplevel.none',
797 default=None,
797 default=None,
798 )
798 )
799 coreconfigitem(
799 coreconfigitem(
800 b'experimental',
800 b'experimental',
801 b'bundlecomplevel.zstd',
801 b'bundlecomplevel.zstd',
802 default=None,
802 default=None,
803 )
803 )
804 coreconfigitem(
804 coreconfigitem(
805 b'experimental',
805 b'experimental',
806 b'changegroup3',
806 b'changegroup3',
807 default=False,
807 default=False,
808 )
808 )
809 coreconfigitem(
809 coreconfigitem(
810 b'experimental',
810 b'experimental',
811 b'cleanup-as-archived',
811 b'cleanup-as-archived',
812 default=False,
812 default=False,
813 )
813 )
814 coreconfigitem(
814 coreconfigitem(
815 b'experimental',
815 b'experimental',
816 b'clientcompressionengines',
816 b'clientcompressionengines',
817 default=list,
817 default=list,
818 )
818 )
819 coreconfigitem(
819 coreconfigitem(
820 b'experimental',
820 b'experimental',
821 b'copytrace',
821 b'copytrace',
822 default=b'on',
822 default=b'on',
823 )
823 )
824 coreconfigitem(
824 coreconfigitem(
825 b'experimental',
825 b'experimental',
826 b'copytrace.movecandidateslimit',
826 b'copytrace.movecandidateslimit',
827 default=100,
827 default=100,
828 )
828 )
829 coreconfigitem(
829 coreconfigitem(
830 b'experimental',
830 b'experimental',
831 b'copytrace.sourcecommitlimit',
831 b'copytrace.sourcecommitlimit',
832 default=100,
832 default=100,
833 )
833 )
834 coreconfigitem(
834 coreconfigitem(
835 b'experimental',
835 b'experimental',
836 b'copies.read-from',
836 b'copies.read-from',
837 default=b"filelog-only",
837 default=b"filelog-only",
838 )
838 )
839 coreconfigitem(
839 coreconfigitem(
840 b'experimental',
840 b'experimental',
841 b'copies.write-to',
841 b'copies.write-to',
842 default=b'filelog-only',
842 default=b'filelog-only',
843 )
843 )
844 coreconfigitem(
844 coreconfigitem(
845 b'experimental',
845 b'experimental',
846 b'crecordtest',
846 b'crecordtest',
847 default=None,
847 default=None,
848 )
848 )
849 coreconfigitem(
849 coreconfigitem(
850 b'experimental',
850 b'experimental',
851 b'directaccess',
851 b'directaccess',
852 default=False,
852 default=False,
853 )
853 )
854 coreconfigitem(
854 coreconfigitem(
855 b'experimental',
855 b'experimental',
856 b'directaccess.revnums',
856 b'directaccess.revnums',
857 default=False,
857 default=False,
858 )
858 )
859 coreconfigitem(
859 coreconfigitem(
860 b'experimental',
860 b'experimental',
861 b'editortmpinhg',
861 b'editortmpinhg',
862 default=False,
862 default=False,
863 )
863 )
864 coreconfigitem(
864 coreconfigitem(
865 b'experimental',
865 b'experimental',
866 b'evolution',
866 b'evolution',
867 default=list,
867 default=list,
868 )
868 )
869 coreconfigitem(
869 coreconfigitem(
870 b'experimental',
870 b'experimental',
871 b'evolution.allowdivergence',
871 b'evolution.allowdivergence',
872 default=False,
872 default=False,
873 alias=[(b'experimental', b'allowdivergence')],
873 alias=[(b'experimental', b'allowdivergence')],
874 )
874 )
875 coreconfigitem(
875 coreconfigitem(
876 b'experimental',
876 b'experimental',
877 b'evolution.allowunstable',
877 b'evolution.allowunstable',
878 default=None,
878 default=None,
879 )
879 )
880 coreconfigitem(
880 coreconfigitem(
881 b'experimental',
881 b'experimental',
882 b'evolution.createmarkers',
882 b'evolution.createmarkers',
883 default=None,
883 default=None,
884 )
884 )
885 coreconfigitem(
885 coreconfigitem(
886 b'experimental',
886 b'experimental',
887 b'evolution.effect-flags',
887 b'evolution.effect-flags',
888 default=True,
888 default=True,
889 alias=[(b'experimental', b'effect-flags')],
889 alias=[(b'experimental', b'effect-flags')],
890 )
890 )
891 coreconfigitem(
891 coreconfigitem(
892 b'experimental',
892 b'experimental',
893 b'evolution.exchange',
893 b'evolution.exchange',
894 default=None,
894 default=None,
895 )
895 )
896 coreconfigitem(
896 coreconfigitem(
897 b'experimental',
897 b'experimental',
898 b'evolution.bundle-obsmarker',
898 b'evolution.bundle-obsmarker',
899 default=False,
899 default=False,
900 )
900 )
901 coreconfigitem(
901 coreconfigitem(
902 b'experimental',
902 b'experimental',
903 b'evolution.bundle-obsmarker:mandatory',
904 default=True,
905 )
906 coreconfigitem(
907 b'experimental',
903 b'log.topo',
908 b'log.topo',
904 default=False,
909 default=False,
905 )
910 )
906 coreconfigitem(
911 coreconfigitem(
907 b'experimental',
912 b'experimental',
908 b'evolution.report-instabilities',
913 b'evolution.report-instabilities',
909 default=True,
914 default=True,
910 )
915 )
911 coreconfigitem(
916 coreconfigitem(
912 b'experimental',
917 b'experimental',
913 b'evolution.track-operation',
918 b'evolution.track-operation',
914 default=True,
919 default=True,
915 )
920 )
916 # repo-level config to exclude a revset visibility
921 # repo-level config to exclude a revset visibility
917 #
922 #
918 # The target use case is to use `share` to expose different subset of the same
923 # The target use case is to use `share` to expose different subset of the same
919 # repository, especially server side. See also `server.view`.
924 # repository, especially server side. See also `server.view`.
920 coreconfigitem(
925 coreconfigitem(
921 b'experimental',
926 b'experimental',
922 b'extra-filter-revs',
927 b'extra-filter-revs',
923 default=None,
928 default=None,
924 )
929 )
925 coreconfigitem(
930 coreconfigitem(
926 b'experimental',
931 b'experimental',
927 b'maxdeltachainspan',
932 b'maxdeltachainspan',
928 default=-1,
933 default=-1,
929 )
934 )
930 # tracks files which were undeleted (merge might delete them but we explicitly
935 # tracks files which were undeleted (merge might delete them but we explicitly
931 # kept/undeleted them) and creates new filenodes for them
936 # kept/undeleted them) and creates new filenodes for them
932 coreconfigitem(
937 coreconfigitem(
933 b'experimental',
938 b'experimental',
934 b'merge-track-salvaged',
939 b'merge-track-salvaged',
935 default=False,
940 default=False,
936 )
941 )
937 coreconfigitem(
942 coreconfigitem(
938 b'experimental',
943 b'experimental',
939 b'mergetempdirprefix',
944 b'mergetempdirprefix',
940 default=None,
945 default=None,
941 )
946 )
942 coreconfigitem(
947 coreconfigitem(
943 b'experimental',
948 b'experimental',
944 b'mmapindexthreshold',
949 b'mmapindexthreshold',
945 default=None,
950 default=None,
946 )
951 )
947 coreconfigitem(
952 coreconfigitem(
948 b'experimental',
953 b'experimental',
949 b'narrow',
954 b'narrow',
950 default=False,
955 default=False,
951 )
956 )
952 coreconfigitem(
957 coreconfigitem(
953 b'experimental',
958 b'experimental',
954 b'nonnormalparanoidcheck',
959 b'nonnormalparanoidcheck',
955 default=False,
960 default=False,
956 )
961 )
957 coreconfigitem(
962 coreconfigitem(
958 b'experimental',
963 b'experimental',
959 b'exportableenviron',
964 b'exportableenviron',
960 default=list,
965 default=list,
961 )
966 )
962 coreconfigitem(
967 coreconfigitem(
963 b'experimental',
968 b'experimental',
964 b'extendedheader.index',
969 b'extendedheader.index',
965 default=None,
970 default=None,
966 )
971 )
967 coreconfigitem(
972 coreconfigitem(
968 b'experimental',
973 b'experimental',
969 b'extendedheader.similarity',
974 b'extendedheader.similarity',
970 default=False,
975 default=False,
971 )
976 )
972 coreconfigitem(
977 coreconfigitem(
973 b'experimental',
978 b'experimental',
974 b'graphshorten',
979 b'graphshorten',
975 default=False,
980 default=False,
976 )
981 )
977 coreconfigitem(
982 coreconfigitem(
978 b'experimental',
983 b'experimental',
979 b'graphstyle.parent',
984 b'graphstyle.parent',
980 default=dynamicdefault,
985 default=dynamicdefault,
981 )
986 )
982 coreconfigitem(
987 coreconfigitem(
983 b'experimental',
988 b'experimental',
984 b'graphstyle.missing',
989 b'graphstyle.missing',
985 default=dynamicdefault,
990 default=dynamicdefault,
986 )
991 )
987 coreconfigitem(
992 coreconfigitem(
988 b'experimental',
993 b'experimental',
989 b'graphstyle.grandparent',
994 b'graphstyle.grandparent',
990 default=dynamicdefault,
995 default=dynamicdefault,
991 )
996 )
992 coreconfigitem(
997 coreconfigitem(
993 b'experimental',
998 b'experimental',
994 b'hook-track-tags',
999 b'hook-track-tags',
995 default=False,
1000 default=False,
996 )
1001 )
997 coreconfigitem(
1002 coreconfigitem(
998 b'experimental',
1003 b'experimental',
999 b'httppeer.advertise-v2',
1004 b'httppeer.advertise-v2',
1000 default=False,
1005 default=False,
1001 )
1006 )
1002 coreconfigitem(
1007 coreconfigitem(
1003 b'experimental',
1008 b'experimental',
1004 b'httppeer.v2-encoder-order',
1009 b'httppeer.v2-encoder-order',
1005 default=None,
1010 default=None,
1006 )
1011 )
1007 coreconfigitem(
1012 coreconfigitem(
1008 b'experimental',
1013 b'experimental',
1009 b'httppostargs',
1014 b'httppostargs',
1010 default=False,
1015 default=False,
1011 )
1016 )
1012 coreconfigitem(b'experimental', b'nointerrupt', default=False)
1017 coreconfigitem(b'experimental', b'nointerrupt', default=False)
1013 coreconfigitem(b'experimental', b'nointerrupt-interactiveonly', default=True)
1018 coreconfigitem(b'experimental', b'nointerrupt-interactiveonly', default=True)
1014
1019
1015 coreconfigitem(
1020 coreconfigitem(
1016 b'experimental',
1021 b'experimental',
1017 b'obsmarkers-exchange-debug',
1022 b'obsmarkers-exchange-debug',
1018 default=False,
1023 default=False,
1019 )
1024 )
1020 coreconfigitem(
1025 coreconfigitem(
1021 b'experimental',
1026 b'experimental',
1022 b'remotenames',
1027 b'remotenames',
1023 default=False,
1028 default=False,
1024 )
1029 )
1025 coreconfigitem(
1030 coreconfigitem(
1026 b'experimental',
1031 b'experimental',
1027 b'removeemptydirs',
1032 b'removeemptydirs',
1028 default=True,
1033 default=True,
1029 )
1034 )
1030 coreconfigitem(
1035 coreconfigitem(
1031 b'experimental',
1036 b'experimental',
1032 b'revert.interactive.select-to-keep',
1037 b'revert.interactive.select-to-keep',
1033 default=False,
1038 default=False,
1034 )
1039 )
1035 coreconfigitem(
1040 coreconfigitem(
1036 b'experimental',
1041 b'experimental',
1037 b'revisions.prefixhexnode',
1042 b'revisions.prefixhexnode',
1038 default=False,
1043 default=False,
1039 )
1044 )
1040 coreconfigitem(
1045 coreconfigitem(
1041 b'experimental',
1046 b'experimental',
1042 b'revlogv2',
1047 b'revlogv2',
1043 default=None,
1048 default=None,
1044 )
1049 )
1045 coreconfigitem(
1050 coreconfigitem(
1046 b'experimental',
1051 b'experimental',
1047 b'revisions.disambiguatewithin',
1052 b'revisions.disambiguatewithin',
1048 default=None,
1053 default=None,
1049 )
1054 )
1050 coreconfigitem(
1055 coreconfigitem(
1051 b'experimental',
1056 b'experimental',
1052 b'rust.index',
1057 b'rust.index',
1053 default=False,
1058 default=False,
1054 )
1059 )
1055 coreconfigitem(
1060 coreconfigitem(
1056 b'experimental',
1061 b'experimental',
1057 b'server.filesdata.recommended-batch-size',
1062 b'server.filesdata.recommended-batch-size',
1058 default=50000,
1063 default=50000,
1059 )
1064 )
1060 coreconfigitem(
1065 coreconfigitem(
1061 b'experimental',
1066 b'experimental',
1062 b'server.manifestdata.recommended-batch-size',
1067 b'server.manifestdata.recommended-batch-size',
1063 default=100000,
1068 default=100000,
1064 )
1069 )
1065 coreconfigitem(
1070 coreconfigitem(
1066 b'experimental',
1071 b'experimental',
1067 b'server.stream-narrow-clones',
1072 b'server.stream-narrow-clones',
1068 default=False,
1073 default=False,
1069 )
1074 )
1070 coreconfigitem(
1075 coreconfigitem(
1071 b'experimental',
1076 b'experimental',
1072 b'single-head-per-branch',
1077 b'single-head-per-branch',
1073 default=False,
1078 default=False,
1074 )
1079 )
1075 coreconfigitem(
1080 coreconfigitem(
1076 b'experimental',
1081 b'experimental',
1077 b'single-head-per-branch:account-closed-heads',
1082 b'single-head-per-branch:account-closed-heads',
1078 default=False,
1083 default=False,
1079 )
1084 )
1080 coreconfigitem(
1085 coreconfigitem(
1081 b'experimental',
1086 b'experimental',
1082 b'single-head-per-branch:public-changes-only',
1087 b'single-head-per-branch:public-changes-only',
1083 default=False,
1088 default=False,
1084 )
1089 )
1085 coreconfigitem(
1090 coreconfigitem(
1086 b'experimental',
1091 b'experimental',
1087 b'sshserver.support-v2',
1092 b'sshserver.support-v2',
1088 default=False,
1093 default=False,
1089 )
1094 )
1090 coreconfigitem(
1095 coreconfigitem(
1091 b'experimental',
1096 b'experimental',
1092 b'sparse-read',
1097 b'sparse-read',
1093 default=False,
1098 default=False,
1094 )
1099 )
1095 coreconfigitem(
1100 coreconfigitem(
1096 b'experimental',
1101 b'experimental',
1097 b'sparse-read.density-threshold',
1102 b'sparse-read.density-threshold',
1098 default=0.50,
1103 default=0.50,
1099 )
1104 )
1100 coreconfigitem(
1105 coreconfigitem(
1101 b'experimental',
1106 b'experimental',
1102 b'sparse-read.min-gap-size',
1107 b'sparse-read.min-gap-size',
1103 default=b'65K',
1108 default=b'65K',
1104 )
1109 )
1105 coreconfigitem(
1110 coreconfigitem(
1106 b'experimental',
1111 b'experimental',
1107 b'treemanifest',
1112 b'treemanifest',
1108 default=False,
1113 default=False,
1109 )
1114 )
1110 coreconfigitem(
1115 coreconfigitem(
1111 b'experimental',
1116 b'experimental',
1112 b'update.atomic-file',
1117 b'update.atomic-file',
1113 default=False,
1118 default=False,
1114 )
1119 )
1115 coreconfigitem(
1120 coreconfigitem(
1116 b'experimental',
1121 b'experimental',
1117 b'sshpeer.advertise-v2',
1122 b'sshpeer.advertise-v2',
1118 default=False,
1123 default=False,
1119 )
1124 )
1120 coreconfigitem(
1125 coreconfigitem(
1121 b'experimental',
1126 b'experimental',
1122 b'web.apiserver',
1127 b'web.apiserver',
1123 default=False,
1128 default=False,
1124 )
1129 )
1125 coreconfigitem(
1130 coreconfigitem(
1126 b'experimental',
1131 b'experimental',
1127 b'web.api.http-v2',
1132 b'web.api.http-v2',
1128 default=False,
1133 default=False,
1129 )
1134 )
1130 coreconfigitem(
1135 coreconfigitem(
1131 b'experimental',
1136 b'experimental',
1132 b'web.api.debugreflect',
1137 b'web.api.debugreflect',
1133 default=False,
1138 default=False,
1134 )
1139 )
1135 coreconfigitem(
1140 coreconfigitem(
1136 b'experimental',
1141 b'experimental',
1137 b'worker.wdir-get-thread-safe',
1142 b'worker.wdir-get-thread-safe',
1138 default=False,
1143 default=False,
1139 )
1144 )
1140 coreconfigitem(
1145 coreconfigitem(
1141 b'experimental',
1146 b'experimental',
1142 b'worker.repository-upgrade',
1147 b'worker.repository-upgrade',
1143 default=False,
1148 default=False,
1144 )
1149 )
1145 coreconfigitem(
1150 coreconfigitem(
1146 b'experimental',
1151 b'experimental',
1147 b'xdiff',
1152 b'xdiff',
1148 default=False,
1153 default=False,
1149 )
1154 )
1150 coreconfigitem(
1155 coreconfigitem(
1151 b'extensions',
1156 b'extensions',
1152 b'.*',
1157 b'.*',
1153 default=None,
1158 default=None,
1154 generic=True,
1159 generic=True,
1155 )
1160 )
1156 coreconfigitem(
1161 coreconfigitem(
1157 b'extdata',
1162 b'extdata',
1158 b'.*',
1163 b'.*',
1159 default=None,
1164 default=None,
1160 generic=True,
1165 generic=True,
1161 )
1166 )
1162 coreconfigitem(
1167 coreconfigitem(
1163 b'format',
1168 b'format',
1164 b'bookmarks-in-store',
1169 b'bookmarks-in-store',
1165 default=False,
1170 default=False,
1166 )
1171 )
1167 coreconfigitem(
1172 coreconfigitem(
1168 b'format',
1173 b'format',
1169 b'chunkcachesize',
1174 b'chunkcachesize',
1170 default=None,
1175 default=None,
1171 experimental=True,
1176 experimental=True,
1172 )
1177 )
1173 coreconfigitem(
1178 coreconfigitem(
1174 b'format',
1179 b'format',
1175 b'dotencode',
1180 b'dotencode',
1176 default=True,
1181 default=True,
1177 )
1182 )
1178 coreconfigitem(
1183 coreconfigitem(
1179 b'format',
1184 b'format',
1180 b'generaldelta',
1185 b'generaldelta',
1181 default=False,
1186 default=False,
1182 experimental=True,
1187 experimental=True,
1183 )
1188 )
1184 coreconfigitem(
1189 coreconfigitem(
1185 b'format',
1190 b'format',
1186 b'manifestcachesize',
1191 b'manifestcachesize',
1187 default=None,
1192 default=None,
1188 experimental=True,
1193 experimental=True,
1189 )
1194 )
1190 coreconfigitem(
1195 coreconfigitem(
1191 b'format',
1196 b'format',
1192 b'maxchainlen',
1197 b'maxchainlen',
1193 default=dynamicdefault,
1198 default=dynamicdefault,
1194 experimental=True,
1199 experimental=True,
1195 )
1200 )
1196 coreconfigitem(
1201 coreconfigitem(
1197 b'format',
1202 b'format',
1198 b'obsstore-version',
1203 b'obsstore-version',
1199 default=None,
1204 default=None,
1200 )
1205 )
1201 coreconfigitem(
1206 coreconfigitem(
1202 b'format',
1207 b'format',
1203 b'sparse-revlog',
1208 b'sparse-revlog',
1204 default=True,
1209 default=True,
1205 )
1210 )
1206 coreconfigitem(
1211 coreconfigitem(
1207 b'format',
1212 b'format',
1208 b'revlog-compression',
1213 b'revlog-compression',
1209 default=lambda: [b'zlib'],
1214 default=lambda: [b'zlib'],
1210 alias=[(b'experimental', b'format.compression')],
1215 alias=[(b'experimental', b'format.compression')],
1211 )
1216 )
1212 coreconfigitem(
1217 coreconfigitem(
1213 b'format',
1218 b'format',
1214 b'usefncache',
1219 b'usefncache',
1215 default=True,
1220 default=True,
1216 )
1221 )
1217 coreconfigitem(
1222 coreconfigitem(
1218 b'format',
1223 b'format',
1219 b'usegeneraldelta',
1224 b'usegeneraldelta',
1220 default=True,
1225 default=True,
1221 )
1226 )
1222 coreconfigitem(
1227 coreconfigitem(
1223 b'format',
1228 b'format',
1224 b'usestore',
1229 b'usestore',
1225 default=True,
1230 default=True,
1226 )
1231 )
1227 # Right now, the only efficient implement of the nodemap logic is in Rust, so
1232 # Right now, the only efficient implement of the nodemap logic is in Rust, so
1228 # the persistent nodemap feature needs to stay experimental as long as the Rust
1233 # the persistent nodemap feature needs to stay experimental as long as the Rust
1229 # extensions are an experimental feature.
1234 # extensions are an experimental feature.
1230 coreconfigitem(
1235 coreconfigitem(
1231 b'format', b'use-persistent-nodemap', default=False, experimental=True
1236 b'format', b'use-persistent-nodemap', default=False, experimental=True
1232 )
1237 )
1233 coreconfigitem(
1238 coreconfigitem(
1234 b'format',
1239 b'format',
1235 b'exp-use-copies-side-data-changeset',
1240 b'exp-use-copies-side-data-changeset',
1236 default=False,
1241 default=False,
1237 experimental=True,
1242 experimental=True,
1238 )
1243 )
1239 coreconfigitem(
1244 coreconfigitem(
1240 b'format',
1245 b'format',
1241 b'exp-use-side-data',
1246 b'exp-use-side-data',
1242 default=False,
1247 default=False,
1243 experimental=True,
1248 experimental=True,
1244 )
1249 )
1245 coreconfigitem(
1250 coreconfigitem(
1246 b'format',
1251 b'format',
1247 b'exp-share-safe',
1252 b'exp-share-safe',
1248 default=False,
1253 default=False,
1249 experimental=True,
1254 experimental=True,
1250 )
1255 )
1251 coreconfigitem(
1256 coreconfigitem(
1252 b'format',
1257 b'format',
1253 b'internal-phase',
1258 b'internal-phase',
1254 default=False,
1259 default=False,
1255 experimental=True,
1260 experimental=True,
1256 )
1261 )
1257 coreconfigitem(
1262 coreconfigitem(
1258 b'fsmonitor',
1263 b'fsmonitor',
1259 b'warn_when_unused',
1264 b'warn_when_unused',
1260 default=True,
1265 default=True,
1261 )
1266 )
1262 coreconfigitem(
1267 coreconfigitem(
1263 b'fsmonitor',
1268 b'fsmonitor',
1264 b'warn_update_file_count',
1269 b'warn_update_file_count',
1265 default=50000,
1270 default=50000,
1266 )
1271 )
1267 coreconfigitem(
1272 coreconfigitem(
1268 b'fsmonitor',
1273 b'fsmonitor',
1269 b'warn_update_file_count_rust',
1274 b'warn_update_file_count_rust',
1270 default=400000,
1275 default=400000,
1271 )
1276 )
1272 coreconfigitem(
1277 coreconfigitem(
1273 b'help',
1278 b'help',
1274 br'hidden-command\..*',
1279 br'hidden-command\..*',
1275 default=False,
1280 default=False,
1276 generic=True,
1281 generic=True,
1277 )
1282 )
1278 coreconfigitem(
1283 coreconfigitem(
1279 b'help',
1284 b'help',
1280 br'hidden-topic\..*',
1285 br'hidden-topic\..*',
1281 default=False,
1286 default=False,
1282 generic=True,
1287 generic=True,
1283 )
1288 )
1284 coreconfigitem(
1289 coreconfigitem(
1285 b'hooks',
1290 b'hooks',
1286 b'.*',
1291 b'.*',
1287 default=dynamicdefault,
1292 default=dynamicdefault,
1288 generic=True,
1293 generic=True,
1289 )
1294 )
1290 coreconfigitem(
1295 coreconfigitem(
1291 b'hgweb-paths',
1296 b'hgweb-paths',
1292 b'.*',
1297 b'.*',
1293 default=list,
1298 default=list,
1294 generic=True,
1299 generic=True,
1295 )
1300 )
1296 coreconfigitem(
1301 coreconfigitem(
1297 b'hostfingerprints',
1302 b'hostfingerprints',
1298 b'.*',
1303 b'.*',
1299 default=list,
1304 default=list,
1300 generic=True,
1305 generic=True,
1301 )
1306 )
1302 coreconfigitem(
1307 coreconfigitem(
1303 b'hostsecurity',
1308 b'hostsecurity',
1304 b'ciphers',
1309 b'ciphers',
1305 default=None,
1310 default=None,
1306 )
1311 )
1307 coreconfigitem(
1312 coreconfigitem(
1308 b'hostsecurity',
1313 b'hostsecurity',
1309 b'minimumprotocol',
1314 b'minimumprotocol',
1310 default=dynamicdefault,
1315 default=dynamicdefault,
1311 )
1316 )
1312 coreconfigitem(
1317 coreconfigitem(
1313 b'hostsecurity',
1318 b'hostsecurity',
1314 b'.*:minimumprotocol$',
1319 b'.*:minimumprotocol$',
1315 default=dynamicdefault,
1320 default=dynamicdefault,
1316 generic=True,
1321 generic=True,
1317 )
1322 )
1318 coreconfigitem(
1323 coreconfigitem(
1319 b'hostsecurity',
1324 b'hostsecurity',
1320 b'.*:ciphers$',
1325 b'.*:ciphers$',
1321 default=dynamicdefault,
1326 default=dynamicdefault,
1322 generic=True,
1327 generic=True,
1323 )
1328 )
1324 coreconfigitem(
1329 coreconfigitem(
1325 b'hostsecurity',
1330 b'hostsecurity',
1326 b'.*:fingerprints$',
1331 b'.*:fingerprints$',
1327 default=list,
1332 default=list,
1328 generic=True,
1333 generic=True,
1329 )
1334 )
1330 coreconfigitem(
1335 coreconfigitem(
1331 b'hostsecurity',
1336 b'hostsecurity',
1332 b'.*:verifycertsfile$',
1337 b'.*:verifycertsfile$',
1333 default=None,
1338 default=None,
1334 generic=True,
1339 generic=True,
1335 )
1340 )
1336
1341
1337 coreconfigitem(
1342 coreconfigitem(
1338 b'http_proxy',
1343 b'http_proxy',
1339 b'always',
1344 b'always',
1340 default=False,
1345 default=False,
1341 )
1346 )
1342 coreconfigitem(
1347 coreconfigitem(
1343 b'http_proxy',
1348 b'http_proxy',
1344 b'host',
1349 b'host',
1345 default=None,
1350 default=None,
1346 )
1351 )
1347 coreconfigitem(
1352 coreconfigitem(
1348 b'http_proxy',
1353 b'http_proxy',
1349 b'no',
1354 b'no',
1350 default=list,
1355 default=list,
1351 )
1356 )
1352 coreconfigitem(
1357 coreconfigitem(
1353 b'http_proxy',
1358 b'http_proxy',
1354 b'passwd',
1359 b'passwd',
1355 default=None,
1360 default=None,
1356 )
1361 )
1357 coreconfigitem(
1362 coreconfigitem(
1358 b'http_proxy',
1363 b'http_proxy',
1359 b'user',
1364 b'user',
1360 default=None,
1365 default=None,
1361 )
1366 )
1362
1367
1363 coreconfigitem(
1368 coreconfigitem(
1364 b'http',
1369 b'http',
1365 b'timeout',
1370 b'timeout',
1366 default=None,
1371 default=None,
1367 )
1372 )
1368
1373
1369 coreconfigitem(
1374 coreconfigitem(
1370 b'logtoprocess',
1375 b'logtoprocess',
1371 b'commandexception',
1376 b'commandexception',
1372 default=None,
1377 default=None,
1373 )
1378 )
1374 coreconfigitem(
1379 coreconfigitem(
1375 b'logtoprocess',
1380 b'logtoprocess',
1376 b'commandfinish',
1381 b'commandfinish',
1377 default=None,
1382 default=None,
1378 )
1383 )
1379 coreconfigitem(
1384 coreconfigitem(
1380 b'logtoprocess',
1385 b'logtoprocess',
1381 b'command',
1386 b'command',
1382 default=None,
1387 default=None,
1383 )
1388 )
1384 coreconfigitem(
1389 coreconfigitem(
1385 b'logtoprocess',
1390 b'logtoprocess',
1386 b'develwarn',
1391 b'develwarn',
1387 default=None,
1392 default=None,
1388 )
1393 )
1389 coreconfigitem(
1394 coreconfigitem(
1390 b'logtoprocess',
1395 b'logtoprocess',
1391 b'uiblocked',
1396 b'uiblocked',
1392 default=None,
1397 default=None,
1393 )
1398 )
1394 coreconfigitem(
1399 coreconfigitem(
1395 b'merge',
1400 b'merge',
1396 b'checkunknown',
1401 b'checkunknown',
1397 default=b'abort',
1402 default=b'abort',
1398 )
1403 )
1399 coreconfigitem(
1404 coreconfigitem(
1400 b'merge',
1405 b'merge',
1401 b'checkignored',
1406 b'checkignored',
1402 default=b'abort',
1407 default=b'abort',
1403 )
1408 )
1404 coreconfigitem(
1409 coreconfigitem(
1405 b'experimental',
1410 b'experimental',
1406 b'merge.checkpathconflicts',
1411 b'merge.checkpathconflicts',
1407 default=False,
1412 default=False,
1408 )
1413 )
1409 coreconfigitem(
1414 coreconfigitem(
1410 b'merge',
1415 b'merge',
1411 b'followcopies',
1416 b'followcopies',
1412 default=True,
1417 default=True,
1413 )
1418 )
1414 coreconfigitem(
1419 coreconfigitem(
1415 b'merge',
1420 b'merge',
1416 b'on-failure',
1421 b'on-failure',
1417 default=b'continue',
1422 default=b'continue',
1418 )
1423 )
1419 coreconfigitem(
1424 coreconfigitem(
1420 b'merge',
1425 b'merge',
1421 b'preferancestor',
1426 b'preferancestor',
1422 default=lambda: [b'*'],
1427 default=lambda: [b'*'],
1423 experimental=True,
1428 experimental=True,
1424 )
1429 )
1425 coreconfigitem(
1430 coreconfigitem(
1426 b'merge',
1431 b'merge',
1427 b'strict-capability-check',
1432 b'strict-capability-check',
1428 default=False,
1433 default=False,
1429 )
1434 )
1430 coreconfigitem(
1435 coreconfigitem(
1431 b'merge-tools',
1436 b'merge-tools',
1432 b'.*',
1437 b'.*',
1433 default=None,
1438 default=None,
1434 generic=True,
1439 generic=True,
1435 )
1440 )
1436 coreconfigitem(
1441 coreconfigitem(
1437 b'merge-tools',
1442 b'merge-tools',
1438 br'.*\.args$',
1443 br'.*\.args$',
1439 default=b"$local $base $other",
1444 default=b"$local $base $other",
1440 generic=True,
1445 generic=True,
1441 priority=-1,
1446 priority=-1,
1442 )
1447 )
1443 coreconfigitem(
1448 coreconfigitem(
1444 b'merge-tools',
1449 b'merge-tools',
1445 br'.*\.binary$',
1450 br'.*\.binary$',
1446 default=False,
1451 default=False,
1447 generic=True,
1452 generic=True,
1448 priority=-1,
1453 priority=-1,
1449 )
1454 )
1450 coreconfigitem(
1455 coreconfigitem(
1451 b'merge-tools',
1456 b'merge-tools',
1452 br'.*\.check$',
1457 br'.*\.check$',
1453 default=list,
1458 default=list,
1454 generic=True,
1459 generic=True,
1455 priority=-1,
1460 priority=-1,
1456 )
1461 )
1457 coreconfigitem(
1462 coreconfigitem(
1458 b'merge-tools',
1463 b'merge-tools',
1459 br'.*\.checkchanged$',
1464 br'.*\.checkchanged$',
1460 default=False,
1465 default=False,
1461 generic=True,
1466 generic=True,
1462 priority=-1,
1467 priority=-1,
1463 )
1468 )
1464 coreconfigitem(
1469 coreconfigitem(
1465 b'merge-tools',
1470 b'merge-tools',
1466 br'.*\.executable$',
1471 br'.*\.executable$',
1467 default=dynamicdefault,
1472 default=dynamicdefault,
1468 generic=True,
1473 generic=True,
1469 priority=-1,
1474 priority=-1,
1470 )
1475 )
1471 coreconfigitem(
1476 coreconfigitem(
1472 b'merge-tools',
1477 b'merge-tools',
1473 br'.*\.fixeol$',
1478 br'.*\.fixeol$',
1474 default=False,
1479 default=False,
1475 generic=True,
1480 generic=True,
1476 priority=-1,
1481 priority=-1,
1477 )
1482 )
1478 coreconfigitem(
1483 coreconfigitem(
1479 b'merge-tools',
1484 b'merge-tools',
1480 br'.*\.gui$',
1485 br'.*\.gui$',
1481 default=False,
1486 default=False,
1482 generic=True,
1487 generic=True,
1483 priority=-1,
1488 priority=-1,
1484 )
1489 )
1485 coreconfigitem(
1490 coreconfigitem(
1486 b'merge-tools',
1491 b'merge-tools',
1487 br'.*\.mergemarkers$',
1492 br'.*\.mergemarkers$',
1488 default=b'basic',
1493 default=b'basic',
1489 generic=True,
1494 generic=True,
1490 priority=-1,
1495 priority=-1,
1491 )
1496 )
1492 coreconfigitem(
1497 coreconfigitem(
1493 b'merge-tools',
1498 b'merge-tools',
1494 br'.*\.mergemarkertemplate$',
1499 br'.*\.mergemarkertemplate$',
1495 default=dynamicdefault, # take from command-templates.mergemarker
1500 default=dynamicdefault, # take from command-templates.mergemarker
1496 generic=True,
1501 generic=True,
1497 priority=-1,
1502 priority=-1,
1498 )
1503 )
1499 coreconfigitem(
1504 coreconfigitem(
1500 b'merge-tools',
1505 b'merge-tools',
1501 br'.*\.priority$',
1506 br'.*\.priority$',
1502 default=0,
1507 default=0,
1503 generic=True,
1508 generic=True,
1504 priority=-1,
1509 priority=-1,
1505 )
1510 )
1506 coreconfigitem(
1511 coreconfigitem(
1507 b'merge-tools',
1512 b'merge-tools',
1508 br'.*\.premerge$',
1513 br'.*\.premerge$',
1509 default=dynamicdefault,
1514 default=dynamicdefault,
1510 generic=True,
1515 generic=True,
1511 priority=-1,
1516 priority=-1,
1512 )
1517 )
1513 coreconfigitem(
1518 coreconfigitem(
1514 b'merge-tools',
1519 b'merge-tools',
1515 br'.*\.symlink$',
1520 br'.*\.symlink$',
1516 default=False,
1521 default=False,
1517 generic=True,
1522 generic=True,
1518 priority=-1,
1523 priority=-1,
1519 )
1524 )
1520 coreconfigitem(
1525 coreconfigitem(
1521 b'pager',
1526 b'pager',
1522 b'attend-.*',
1527 b'attend-.*',
1523 default=dynamicdefault,
1528 default=dynamicdefault,
1524 generic=True,
1529 generic=True,
1525 )
1530 )
1526 coreconfigitem(
1531 coreconfigitem(
1527 b'pager',
1532 b'pager',
1528 b'ignore',
1533 b'ignore',
1529 default=list,
1534 default=list,
1530 )
1535 )
1531 coreconfigitem(
1536 coreconfigitem(
1532 b'pager',
1537 b'pager',
1533 b'pager',
1538 b'pager',
1534 default=dynamicdefault,
1539 default=dynamicdefault,
1535 )
1540 )
1536 coreconfigitem(
1541 coreconfigitem(
1537 b'patch',
1542 b'patch',
1538 b'eol',
1543 b'eol',
1539 default=b'strict',
1544 default=b'strict',
1540 )
1545 )
1541 coreconfigitem(
1546 coreconfigitem(
1542 b'patch',
1547 b'patch',
1543 b'fuzz',
1548 b'fuzz',
1544 default=2,
1549 default=2,
1545 )
1550 )
1546 coreconfigitem(
1551 coreconfigitem(
1547 b'paths',
1552 b'paths',
1548 b'default',
1553 b'default',
1549 default=None,
1554 default=None,
1550 )
1555 )
1551 coreconfigitem(
1556 coreconfigitem(
1552 b'paths',
1557 b'paths',
1553 b'default-push',
1558 b'default-push',
1554 default=None,
1559 default=None,
1555 )
1560 )
1556 coreconfigitem(
1561 coreconfigitem(
1557 b'paths',
1562 b'paths',
1558 b'.*',
1563 b'.*',
1559 default=None,
1564 default=None,
1560 generic=True,
1565 generic=True,
1561 )
1566 )
1562 coreconfigitem(
1567 coreconfigitem(
1563 b'phases',
1568 b'phases',
1564 b'checksubrepos',
1569 b'checksubrepos',
1565 default=b'follow',
1570 default=b'follow',
1566 )
1571 )
1567 coreconfigitem(
1572 coreconfigitem(
1568 b'phases',
1573 b'phases',
1569 b'new-commit',
1574 b'new-commit',
1570 default=b'draft',
1575 default=b'draft',
1571 )
1576 )
1572 coreconfigitem(
1577 coreconfigitem(
1573 b'phases',
1578 b'phases',
1574 b'publish',
1579 b'publish',
1575 default=True,
1580 default=True,
1576 )
1581 )
1577 coreconfigitem(
1582 coreconfigitem(
1578 b'profiling',
1583 b'profiling',
1579 b'enabled',
1584 b'enabled',
1580 default=False,
1585 default=False,
1581 )
1586 )
1582 coreconfigitem(
1587 coreconfigitem(
1583 b'profiling',
1588 b'profiling',
1584 b'format',
1589 b'format',
1585 default=b'text',
1590 default=b'text',
1586 )
1591 )
1587 coreconfigitem(
1592 coreconfigitem(
1588 b'profiling',
1593 b'profiling',
1589 b'freq',
1594 b'freq',
1590 default=1000,
1595 default=1000,
1591 )
1596 )
1592 coreconfigitem(
1597 coreconfigitem(
1593 b'profiling',
1598 b'profiling',
1594 b'limit',
1599 b'limit',
1595 default=30,
1600 default=30,
1596 )
1601 )
1597 coreconfigitem(
1602 coreconfigitem(
1598 b'profiling',
1603 b'profiling',
1599 b'nested',
1604 b'nested',
1600 default=0,
1605 default=0,
1601 )
1606 )
1602 coreconfigitem(
1607 coreconfigitem(
1603 b'profiling',
1608 b'profiling',
1604 b'output',
1609 b'output',
1605 default=None,
1610 default=None,
1606 )
1611 )
1607 coreconfigitem(
1612 coreconfigitem(
1608 b'profiling',
1613 b'profiling',
1609 b'showmax',
1614 b'showmax',
1610 default=0.999,
1615 default=0.999,
1611 )
1616 )
1612 coreconfigitem(
1617 coreconfigitem(
1613 b'profiling',
1618 b'profiling',
1614 b'showmin',
1619 b'showmin',
1615 default=dynamicdefault,
1620 default=dynamicdefault,
1616 )
1621 )
1617 coreconfigitem(
1622 coreconfigitem(
1618 b'profiling',
1623 b'profiling',
1619 b'showtime',
1624 b'showtime',
1620 default=True,
1625 default=True,
1621 )
1626 )
1622 coreconfigitem(
1627 coreconfigitem(
1623 b'profiling',
1628 b'profiling',
1624 b'sort',
1629 b'sort',
1625 default=b'inlinetime',
1630 default=b'inlinetime',
1626 )
1631 )
1627 coreconfigitem(
1632 coreconfigitem(
1628 b'profiling',
1633 b'profiling',
1629 b'statformat',
1634 b'statformat',
1630 default=b'hotpath',
1635 default=b'hotpath',
1631 )
1636 )
1632 coreconfigitem(
1637 coreconfigitem(
1633 b'profiling',
1638 b'profiling',
1634 b'time-track',
1639 b'time-track',
1635 default=dynamicdefault,
1640 default=dynamicdefault,
1636 )
1641 )
1637 coreconfigitem(
1642 coreconfigitem(
1638 b'profiling',
1643 b'profiling',
1639 b'type',
1644 b'type',
1640 default=b'stat',
1645 default=b'stat',
1641 )
1646 )
1642 coreconfigitem(
1647 coreconfigitem(
1643 b'progress',
1648 b'progress',
1644 b'assume-tty',
1649 b'assume-tty',
1645 default=False,
1650 default=False,
1646 )
1651 )
1647 coreconfigitem(
1652 coreconfigitem(
1648 b'progress',
1653 b'progress',
1649 b'changedelay',
1654 b'changedelay',
1650 default=1,
1655 default=1,
1651 )
1656 )
1652 coreconfigitem(
1657 coreconfigitem(
1653 b'progress',
1658 b'progress',
1654 b'clear-complete',
1659 b'clear-complete',
1655 default=True,
1660 default=True,
1656 )
1661 )
1657 coreconfigitem(
1662 coreconfigitem(
1658 b'progress',
1663 b'progress',
1659 b'debug',
1664 b'debug',
1660 default=False,
1665 default=False,
1661 )
1666 )
1662 coreconfigitem(
1667 coreconfigitem(
1663 b'progress',
1668 b'progress',
1664 b'delay',
1669 b'delay',
1665 default=3,
1670 default=3,
1666 )
1671 )
1667 coreconfigitem(
1672 coreconfigitem(
1668 b'progress',
1673 b'progress',
1669 b'disable',
1674 b'disable',
1670 default=False,
1675 default=False,
1671 )
1676 )
1672 coreconfigitem(
1677 coreconfigitem(
1673 b'progress',
1678 b'progress',
1674 b'estimateinterval',
1679 b'estimateinterval',
1675 default=60.0,
1680 default=60.0,
1676 )
1681 )
1677 coreconfigitem(
1682 coreconfigitem(
1678 b'progress',
1683 b'progress',
1679 b'format',
1684 b'format',
1680 default=lambda: [b'topic', b'bar', b'number', b'estimate'],
1685 default=lambda: [b'topic', b'bar', b'number', b'estimate'],
1681 )
1686 )
1682 coreconfigitem(
1687 coreconfigitem(
1683 b'progress',
1688 b'progress',
1684 b'refresh',
1689 b'refresh',
1685 default=0.1,
1690 default=0.1,
1686 )
1691 )
1687 coreconfigitem(
1692 coreconfigitem(
1688 b'progress',
1693 b'progress',
1689 b'width',
1694 b'width',
1690 default=dynamicdefault,
1695 default=dynamicdefault,
1691 )
1696 )
1692 coreconfigitem(
1697 coreconfigitem(
1693 b'pull',
1698 b'pull',
1694 b'confirm',
1699 b'confirm',
1695 default=False,
1700 default=False,
1696 )
1701 )
1697 coreconfigitem(
1702 coreconfigitem(
1698 b'push',
1703 b'push',
1699 b'pushvars.server',
1704 b'pushvars.server',
1700 default=False,
1705 default=False,
1701 )
1706 )
1702 coreconfigitem(
1707 coreconfigitem(
1703 b'rewrite',
1708 b'rewrite',
1704 b'backup-bundle',
1709 b'backup-bundle',
1705 default=True,
1710 default=True,
1706 alias=[(b'ui', b'history-editing-backup')],
1711 alias=[(b'ui', b'history-editing-backup')],
1707 )
1712 )
1708 coreconfigitem(
1713 coreconfigitem(
1709 b'rewrite',
1714 b'rewrite',
1710 b'update-timestamp',
1715 b'update-timestamp',
1711 default=False,
1716 default=False,
1712 )
1717 )
1713 coreconfigitem(
1718 coreconfigitem(
1714 b'rewrite',
1719 b'rewrite',
1715 b'empty-successor',
1720 b'empty-successor',
1716 default=b'skip',
1721 default=b'skip',
1717 experimental=True,
1722 experimental=True,
1718 )
1723 )
1719 coreconfigitem(
1724 coreconfigitem(
1720 b'storage',
1725 b'storage',
1721 b'new-repo-backend',
1726 b'new-repo-backend',
1722 default=b'revlogv1',
1727 default=b'revlogv1',
1723 experimental=True,
1728 experimental=True,
1724 )
1729 )
1725 coreconfigitem(
1730 coreconfigitem(
1726 b'storage',
1731 b'storage',
1727 b'revlog.optimize-delta-parent-choice',
1732 b'revlog.optimize-delta-parent-choice',
1728 default=True,
1733 default=True,
1729 alias=[(b'format', b'aggressivemergedeltas')],
1734 alias=[(b'format', b'aggressivemergedeltas')],
1730 )
1735 )
1731 # experimental as long as rust is experimental (or a C version is implemented)
1736 # experimental as long as rust is experimental (or a C version is implemented)
1732 coreconfigitem(
1737 coreconfigitem(
1733 b'storage', b'revlog.nodemap.mmap', default=True, experimental=True
1738 b'storage', b'revlog.nodemap.mmap', default=True, experimental=True
1734 )
1739 )
1735 # experimental as long as format.use-persistent-nodemap is.
1740 # experimental as long as format.use-persistent-nodemap is.
1736 coreconfigitem(
1741 coreconfigitem(
1737 b'storage', b'revlog.nodemap.mode', default=b'compat', experimental=True
1742 b'storage', b'revlog.nodemap.mode', default=b'compat', experimental=True
1738 )
1743 )
1739 coreconfigitem(
1744 coreconfigitem(
1740 b'storage',
1745 b'storage',
1741 b'revlog.reuse-external-delta',
1746 b'revlog.reuse-external-delta',
1742 default=True,
1747 default=True,
1743 )
1748 )
1744 coreconfigitem(
1749 coreconfigitem(
1745 b'storage',
1750 b'storage',
1746 b'revlog.reuse-external-delta-parent',
1751 b'revlog.reuse-external-delta-parent',
1747 default=None,
1752 default=None,
1748 )
1753 )
1749 coreconfigitem(
1754 coreconfigitem(
1750 b'storage',
1755 b'storage',
1751 b'revlog.zlib.level',
1756 b'revlog.zlib.level',
1752 default=None,
1757 default=None,
1753 )
1758 )
1754 coreconfigitem(
1759 coreconfigitem(
1755 b'storage',
1760 b'storage',
1756 b'revlog.zstd.level',
1761 b'revlog.zstd.level',
1757 default=None,
1762 default=None,
1758 )
1763 )
1759 coreconfigitem(
1764 coreconfigitem(
1760 b'server',
1765 b'server',
1761 b'bookmarks-pushkey-compat',
1766 b'bookmarks-pushkey-compat',
1762 default=True,
1767 default=True,
1763 )
1768 )
1764 coreconfigitem(
1769 coreconfigitem(
1765 b'server',
1770 b'server',
1766 b'bundle1',
1771 b'bundle1',
1767 default=True,
1772 default=True,
1768 )
1773 )
1769 coreconfigitem(
1774 coreconfigitem(
1770 b'server',
1775 b'server',
1771 b'bundle1gd',
1776 b'bundle1gd',
1772 default=None,
1777 default=None,
1773 )
1778 )
1774 coreconfigitem(
1779 coreconfigitem(
1775 b'server',
1780 b'server',
1776 b'bundle1.pull',
1781 b'bundle1.pull',
1777 default=None,
1782 default=None,
1778 )
1783 )
1779 coreconfigitem(
1784 coreconfigitem(
1780 b'server',
1785 b'server',
1781 b'bundle1gd.pull',
1786 b'bundle1gd.pull',
1782 default=None,
1787 default=None,
1783 )
1788 )
1784 coreconfigitem(
1789 coreconfigitem(
1785 b'server',
1790 b'server',
1786 b'bundle1.push',
1791 b'bundle1.push',
1787 default=None,
1792 default=None,
1788 )
1793 )
1789 coreconfigitem(
1794 coreconfigitem(
1790 b'server',
1795 b'server',
1791 b'bundle1gd.push',
1796 b'bundle1gd.push',
1792 default=None,
1797 default=None,
1793 )
1798 )
1794 coreconfigitem(
1799 coreconfigitem(
1795 b'server',
1800 b'server',
1796 b'bundle2.stream',
1801 b'bundle2.stream',
1797 default=True,
1802 default=True,
1798 alias=[(b'experimental', b'bundle2.stream')],
1803 alias=[(b'experimental', b'bundle2.stream')],
1799 )
1804 )
1800 coreconfigitem(
1805 coreconfigitem(
1801 b'server',
1806 b'server',
1802 b'compressionengines',
1807 b'compressionengines',
1803 default=list,
1808 default=list,
1804 )
1809 )
1805 coreconfigitem(
1810 coreconfigitem(
1806 b'server',
1811 b'server',
1807 b'concurrent-push-mode',
1812 b'concurrent-push-mode',
1808 default=b'check-related',
1813 default=b'check-related',
1809 )
1814 )
1810 coreconfigitem(
1815 coreconfigitem(
1811 b'server',
1816 b'server',
1812 b'disablefullbundle',
1817 b'disablefullbundle',
1813 default=False,
1818 default=False,
1814 )
1819 )
1815 coreconfigitem(
1820 coreconfigitem(
1816 b'server',
1821 b'server',
1817 b'maxhttpheaderlen',
1822 b'maxhttpheaderlen',
1818 default=1024,
1823 default=1024,
1819 )
1824 )
1820 coreconfigitem(
1825 coreconfigitem(
1821 b'server',
1826 b'server',
1822 b'pullbundle',
1827 b'pullbundle',
1823 default=False,
1828 default=False,
1824 )
1829 )
1825 coreconfigitem(
1830 coreconfigitem(
1826 b'server',
1831 b'server',
1827 b'preferuncompressed',
1832 b'preferuncompressed',
1828 default=False,
1833 default=False,
1829 )
1834 )
1830 coreconfigitem(
1835 coreconfigitem(
1831 b'server',
1836 b'server',
1832 b'streamunbundle',
1837 b'streamunbundle',
1833 default=False,
1838 default=False,
1834 )
1839 )
1835 coreconfigitem(
1840 coreconfigitem(
1836 b'server',
1841 b'server',
1837 b'uncompressed',
1842 b'uncompressed',
1838 default=True,
1843 default=True,
1839 )
1844 )
1840 coreconfigitem(
1845 coreconfigitem(
1841 b'server',
1846 b'server',
1842 b'uncompressedallowsecret',
1847 b'uncompressedallowsecret',
1843 default=False,
1848 default=False,
1844 )
1849 )
1845 coreconfigitem(
1850 coreconfigitem(
1846 b'server',
1851 b'server',
1847 b'view',
1852 b'view',
1848 default=b'served',
1853 default=b'served',
1849 )
1854 )
1850 coreconfigitem(
1855 coreconfigitem(
1851 b'server',
1856 b'server',
1852 b'validate',
1857 b'validate',
1853 default=False,
1858 default=False,
1854 )
1859 )
1855 coreconfigitem(
1860 coreconfigitem(
1856 b'server',
1861 b'server',
1857 b'zliblevel',
1862 b'zliblevel',
1858 default=-1,
1863 default=-1,
1859 )
1864 )
1860 coreconfigitem(
1865 coreconfigitem(
1861 b'server',
1866 b'server',
1862 b'zstdlevel',
1867 b'zstdlevel',
1863 default=3,
1868 default=3,
1864 )
1869 )
1865 coreconfigitem(
1870 coreconfigitem(
1866 b'share',
1871 b'share',
1867 b'pool',
1872 b'pool',
1868 default=None,
1873 default=None,
1869 )
1874 )
1870 coreconfigitem(
1875 coreconfigitem(
1871 b'share',
1876 b'share',
1872 b'poolnaming',
1877 b'poolnaming',
1873 default=b'identity',
1878 default=b'identity',
1874 )
1879 )
1875 coreconfigitem(
1880 coreconfigitem(
1876 b'shelve',
1881 b'shelve',
1877 b'maxbackups',
1882 b'maxbackups',
1878 default=10,
1883 default=10,
1879 )
1884 )
1880 coreconfigitem(
1885 coreconfigitem(
1881 b'smtp',
1886 b'smtp',
1882 b'host',
1887 b'host',
1883 default=None,
1888 default=None,
1884 )
1889 )
1885 coreconfigitem(
1890 coreconfigitem(
1886 b'smtp',
1891 b'smtp',
1887 b'local_hostname',
1892 b'local_hostname',
1888 default=None,
1893 default=None,
1889 )
1894 )
1890 coreconfigitem(
1895 coreconfigitem(
1891 b'smtp',
1896 b'smtp',
1892 b'password',
1897 b'password',
1893 default=None,
1898 default=None,
1894 )
1899 )
1895 coreconfigitem(
1900 coreconfigitem(
1896 b'smtp',
1901 b'smtp',
1897 b'port',
1902 b'port',
1898 default=dynamicdefault,
1903 default=dynamicdefault,
1899 )
1904 )
1900 coreconfigitem(
1905 coreconfigitem(
1901 b'smtp',
1906 b'smtp',
1902 b'tls',
1907 b'tls',
1903 default=b'none',
1908 default=b'none',
1904 )
1909 )
1905 coreconfigitem(
1910 coreconfigitem(
1906 b'smtp',
1911 b'smtp',
1907 b'username',
1912 b'username',
1908 default=None,
1913 default=None,
1909 )
1914 )
1910 coreconfigitem(
1915 coreconfigitem(
1911 b'sparse',
1916 b'sparse',
1912 b'missingwarning',
1917 b'missingwarning',
1913 default=True,
1918 default=True,
1914 experimental=True,
1919 experimental=True,
1915 )
1920 )
1916 coreconfigitem(
1921 coreconfigitem(
1917 b'subrepos',
1922 b'subrepos',
1918 b'allowed',
1923 b'allowed',
1919 default=dynamicdefault, # to make backporting simpler
1924 default=dynamicdefault, # to make backporting simpler
1920 )
1925 )
1921 coreconfigitem(
1926 coreconfigitem(
1922 b'subrepos',
1927 b'subrepos',
1923 b'hg:allowed',
1928 b'hg:allowed',
1924 default=dynamicdefault,
1929 default=dynamicdefault,
1925 )
1930 )
1926 coreconfigitem(
1931 coreconfigitem(
1927 b'subrepos',
1932 b'subrepos',
1928 b'git:allowed',
1933 b'git:allowed',
1929 default=dynamicdefault,
1934 default=dynamicdefault,
1930 )
1935 )
1931 coreconfigitem(
1936 coreconfigitem(
1932 b'subrepos',
1937 b'subrepos',
1933 b'svn:allowed',
1938 b'svn:allowed',
1934 default=dynamicdefault,
1939 default=dynamicdefault,
1935 )
1940 )
1936 coreconfigitem(
1941 coreconfigitem(
1937 b'templates',
1942 b'templates',
1938 b'.*',
1943 b'.*',
1939 default=None,
1944 default=None,
1940 generic=True,
1945 generic=True,
1941 )
1946 )
1942 coreconfigitem(
1947 coreconfigitem(
1943 b'templateconfig',
1948 b'templateconfig',
1944 b'.*',
1949 b'.*',
1945 default=dynamicdefault,
1950 default=dynamicdefault,
1946 generic=True,
1951 generic=True,
1947 )
1952 )
1948 coreconfigitem(
1953 coreconfigitem(
1949 b'trusted',
1954 b'trusted',
1950 b'groups',
1955 b'groups',
1951 default=list,
1956 default=list,
1952 )
1957 )
1953 coreconfigitem(
1958 coreconfigitem(
1954 b'trusted',
1959 b'trusted',
1955 b'users',
1960 b'users',
1956 default=list,
1961 default=list,
1957 )
1962 )
1958 coreconfigitem(
1963 coreconfigitem(
1959 b'ui',
1964 b'ui',
1960 b'_usedassubrepo',
1965 b'_usedassubrepo',
1961 default=False,
1966 default=False,
1962 )
1967 )
1963 coreconfigitem(
1968 coreconfigitem(
1964 b'ui',
1969 b'ui',
1965 b'allowemptycommit',
1970 b'allowemptycommit',
1966 default=False,
1971 default=False,
1967 )
1972 )
1968 coreconfigitem(
1973 coreconfigitem(
1969 b'ui',
1974 b'ui',
1970 b'archivemeta',
1975 b'archivemeta',
1971 default=True,
1976 default=True,
1972 )
1977 )
1973 coreconfigitem(
1978 coreconfigitem(
1974 b'ui',
1979 b'ui',
1975 b'askusername',
1980 b'askusername',
1976 default=False,
1981 default=False,
1977 )
1982 )
1978 coreconfigitem(
1983 coreconfigitem(
1979 b'ui',
1984 b'ui',
1980 b'available-memory',
1985 b'available-memory',
1981 default=None,
1986 default=None,
1982 )
1987 )
1983
1988
1984 coreconfigitem(
1989 coreconfigitem(
1985 b'ui',
1990 b'ui',
1986 b'clonebundlefallback',
1991 b'clonebundlefallback',
1987 default=False,
1992 default=False,
1988 )
1993 )
1989 coreconfigitem(
1994 coreconfigitem(
1990 b'ui',
1995 b'ui',
1991 b'clonebundleprefers',
1996 b'clonebundleprefers',
1992 default=list,
1997 default=list,
1993 )
1998 )
1994 coreconfigitem(
1999 coreconfigitem(
1995 b'ui',
2000 b'ui',
1996 b'clonebundles',
2001 b'clonebundles',
1997 default=True,
2002 default=True,
1998 )
2003 )
1999 coreconfigitem(
2004 coreconfigitem(
2000 b'ui',
2005 b'ui',
2001 b'color',
2006 b'color',
2002 default=b'auto',
2007 default=b'auto',
2003 )
2008 )
2004 coreconfigitem(
2009 coreconfigitem(
2005 b'ui',
2010 b'ui',
2006 b'commitsubrepos',
2011 b'commitsubrepos',
2007 default=False,
2012 default=False,
2008 )
2013 )
2009 coreconfigitem(
2014 coreconfigitem(
2010 b'ui',
2015 b'ui',
2011 b'debug',
2016 b'debug',
2012 default=False,
2017 default=False,
2013 )
2018 )
2014 coreconfigitem(
2019 coreconfigitem(
2015 b'ui',
2020 b'ui',
2016 b'debugger',
2021 b'debugger',
2017 default=None,
2022 default=None,
2018 )
2023 )
2019 coreconfigitem(
2024 coreconfigitem(
2020 b'ui',
2025 b'ui',
2021 b'editor',
2026 b'editor',
2022 default=dynamicdefault,
2027 default=dynamicdefault,
2023 )
2028 )
2024 coreconfigitem(
2029 coreconfigitem(
2025 b'ui',
2030 b'ui',
2026 b'detailed-exit-code',
2031 b'detailed-exit-code',
2027 default=False,
2032 default=False,
2028 experimental=True,
2033 experimental=True,
2029 )
2034 )
2030 coreconfigitem(
2035 coreconfigitem(
2031 b'ui',
2036 b'ui',
2032 b'fallbackencoding',
2037 b'fallbackencoding',
2033 default=None,
2038 default=None,
2034 )
2039 )
2035 coreconfigitem(
2040 coreconfigitem(
2036 b'ui',
2041 b'ui',
2037 b'forcecwd',
2042 b'forcecwd',
2038 default=None,
2043 default=None,
2039 )
2044 )
2040 coreconfigitem(
2045 coreconfigitem(
2041 b'ui',
2046 b'ui',
2042 b'forcemerge',
2047 b'forcemerge',
2043 default=None,
2048 default=None,
2044 )
2049 )
2045 coreconfigitem(
2050 coreconfigitem(
2046 b'ui',
2051 b'ui',
2047 b'formatdebug',
2052 b'formatdebug',
2048 default=False,
2053 default=False,
2049 )
2054 )
2050 coreconfigitem(
2055 coreconfigitem(
2051 b'ui',
2056 b'ui',
2052 b'formatjson',
2057 b'formatjson',
2053 default=False,
2058 default=False,
2054 )
2059 )
2055 coreconfigitem(
2060 coreconfigitem(
2056 b'ui',
2061 b'ui',
2057 b'formatted',
2062 b'formatted',
2058 default=None,
2063 default=None,
2059 )
2064 )
2060 coreconfigitem(
2065 coreconfigitem(
2061 b'ui',
2066 b'ui',
2062 b'interactive',
2067 b'interactive',
2063 default=None,
2068 default=None,
2064 )
2069 )
2065 coreconfigitem(
2070 coreconfigitem(
2066 b'ui',
2071 b'ui',
2067 b'interface',
2072 b'interface',
2068 default=None,
2073 default=None,
2069 )
2074 )
2070 coreconfigitem(
2075 coreconfigitem(
2071 b'ui',
2076 b'ui',
2072 b'interface.chunkselector',
2077 b'interface.chunkselector',
2073 default=None,
2078 default=None,
2074 )
2079 )
2075 coreconfigitem(
2080 coreconfigitem(
2076 b'ui',
2081 b'ui',
2077 b'large-file-limit',
2082 b'large-file-limit',
2078 default=10000000,
2083 default=10000000,
2079 )
2084 )
2080 coreconfigitem(
2085 coreconfigitem(
2081 b'ui',
2086 b'ui',
2082 b'logblockedtimes',
2087 b'logblockedtimes',
2083 default=False,
2088 default=False,
2084 )
2089 )
2085 coreconfigitem(
2090 coreconfigitem(
2086 b'ui',
2091 b'ui',
2087 b'merge',
2092 b'merge',
2088 default=None,
2093 default=None,
2089 )
2094 )
2090 coreconfigitem(
2095 coreconfigitem(
2091 b'ui',
2096 b'ui',
2092 b'mergemarkers',
2097 b'mergemarkers',
2093 default=b'basic',
2098 default=b'basic',
2094 )
2099 )
2095 coreconfigitem(
2100 coreconfigitem(
2096 b'ui',
2101 b'ui',
2097 b'message-output',
2102 b'message-output',
2098 default=b'stdio',
2103 default=b'stdio',
2099 )
2104 )
2100 coreconfigitem(
2105 coreconfigitem(
2101 b'ui',
2106 b'ui',
2102 b'nontty',
2107 b'nontty',
2103 default=False,
2108 default=False,
2104 )
2109 )
2105 coreconfigitem(
2110 coreconfigitem(
2106 b'ui',
2111 b'ui',
2107 b'origbackuppath',
2112 b'origbackuppath',
2108 default=None,
2113 default=None,
2109 )
2114 )
2110 coreconfigitem(
2115 coreconfigitem(
2111 b'ui',
2116 b'ui',
2112 b'paginate',
2117 b'paginate',
2113 default=True,
2118 default=True,
2114 )
2119 )
2115 coreconfigitem(
2120 coreconfigitem(
2116 b'ui',
2121 b'ui',
2117 b'patch',
2122 b'patch',
2118 default=None,
2123 default=None,
2119 )
2124 )
2120 coreconfigitem(
2125 coreconfigitem(
2121 b'ui',
2126 b'ui',
2122 b'portablefilenames',
2127 b'portablefilenames',
2123 default=b'warn',
2128 default=b'warn',
2124 )
2129 )
2125 coreconfigitem(
2130 coreconfigitem(
2126 b'ui',
2131 b'ui',
2127 b'promptecho',
2132 b'promptecho',
2128 default=False,
2133 default=False,
2129 )
2134 )
2130 coreconfigitem(
2135 coreconfigitem(
2131 b'ui',
2136 b'ui',
2132 b'quiet',
2137 b'quiet',
2133 default=False,
2138 default=False,
2134 )
2139 )
2135 coreconfigitem(
2140 coreconfigitem(
2136 b'ui',
2141 b'ui',
2137 b'quietbookmarkmove',
2142 b'quietbookmarkmove',
2138 default=False,
2143 default=False,
2139 )
2144 )
2140 coreconfigitem(
2145 coreconfigitem(
2141 b'ui',
2146 b'ui',
2142 b'relative-paths',
2147 b'relative-paths',
2143 default=b'legacy',
2148 default=b'legacy',
2144 )
2149 )
2145 coreconfigitem(
2150 coreconfigitem(
2146 b'ui',
2151 b'ui',
2147 b'remotecmd',
2152 b'remotecmd',
2148 default=b'hg',
2153 default=b'hg',
2149 )
2154 )
2150 coreconfigitem(
2155 coreconfigitem(
2151 b'ui',
2156 b'ui',
2152 b'report_untrusted',
2157 b'report_untrusted',
2153 default=True,
2158 default=True,
2154 )
2159 )
2155 coreconfigitem(
2160 coreconfigitem(
2156 b'ui',
2161 b'ui',
2157 b'rollback',
2162 b'rollback',
2158 default=True,
2163 default=True,
2159 )
2164 )
2160 coreconfigitem(
2165 coreconfigitem(
2161 b'ui',
2166 b'ui',
2162 b'signal-safe-lock',
2167 b'signal-safe-lock',
2163 default=True,
2168 default=True,
2164 )
2169 )
2165 coreconfigitem(
2170 coreconfigitem(
2166 b'ui',
2171 b'ui',
2167 b'slash',
2172 b'slash',
2168 default=False,
2173 default=False,
2169 )
2174 )
2170 coreconfigitem(
2175 coreconfigitem(
2171 b'ui',
2176 b'ui',
2172 b'ssh',
2177 b'ssh',
2173 default=b'ssh',
2178 default=b'ssh',
2174 )
2179 )
2175 coreconfigitem(
2180 coreconfigitem(
2176 b'ui',
2181 b'ui',
2177 b'ssherrorhint',
2182 b'ssherrorhint',
2178 default=None,
2183 default=None,
2179 )
2184 )
2180 coreconfigitem(
2185 coreconfigitem(
2181 b'ui',
2186 b'ui',
2182 b'statuscopies',
2187 b'statuscopies',
2183 default=False,
2188 default=False,
2184 )
2189 )
2185 coreconfigitem(
2190 coreconfigitem(
2186 b'ui',
2191 b'ui',
2187 b'strict',
2192 b'strict',
2188 default=False,
2193 default=False,
2189 )
2194 )
2190 coreconfigitem(
2195 coreconfigitem(
2191 b'ui',
2196 b'ui',
2192 b'style',
2197 b'style',
2193 default=b'',
2198 default=b'',
2194 )
2199 )
2195 coreconfigitem(
2200 coreconfigitem(
2196 b'ui',
2201 b'ui',
2197 b'supportcontact',
2202 b'supportcontact',
2198 default=None,
2203 default=None,
2199 )
2204 )
2200 coreconfigitem(
2205 coreconfigitem(
2201 b'ui',
2206 b'ui',
2202 b'textwidth',
2207 b'textwidth',
2203 default=78,
2208 default=78,
2204 )
2209 )
2205 coreconfigitem(
2210 coreconfigitem(
2206 b'ui',
2211 b'ui',
2207 b'timeout',
2212 b'timeout',
2208 default=b'600',
2213 default=b'600',
2209 )
2214 )
2210 coreconfigitem(
2215 coreconfigitem(
2211 b'ui',
2216 b'ui',
2212 b'timeout.warn',
2217 b'timeout.warn',
2213 default=0,
2218 default=0,
2214 )
2219 )
2215 coreconfigitem(
2220 coreconfigitem(
2216 b'ui',
2221 b'ui',
2217 b'timestamp-output',
2222 b'timestamp-output',
2218 default=False,
2223 default=False,
2219 )
2224 )
2220 coreconfigitem(
2225 coreconfigitem(
2221 b'ui',
2226 b'ui',
2222 b'traceback',
2227 b'traceback',
2223 default=False,
2228 default=False,
2224 )
2229 )
2225 coreconfigitem(
2230 coreconfigitem(
2226 b'ui',
2231 b'ui',
2227 b'tweakdefaults',
2232 b'tweakdefaults',
2228 default=False,
2233 default=False,
2229 )
2234 )
2230 coreconfigitem(b'ui', b'username', alias=[(b'ui', b'user')])
2235 coreconfigitem(b'ui', b'username', alias=[(b'ui', b'user')])
2231 coreconfigitem(
2236 coreconfigitem(
2232 b'ui',
2237 b'ui',
2233 b'verbose',
2238 b'verbose',
2234 default=False,
2239 default=False,
2235 )
2240 )
2236 coreconfigitem(
2241 coreconfigitem(
2237 b'verify',
2242 b'verify',
2238 b'skipflags',
2243 b'skipflags',
2239 default=None,
2244 default=None,
2240 )
2245 )
2241 coreconfigitem(
2246 coreconfigitem(
2242 b'web',
2247 b'web',
2243 b'allowbz2',
2248 b'allowbz2',
2244 default=False,
2249 default=False,
2245 )
2250 )
2246 coreconfigitem(
2251 coreconfigitem(
2247 b'web',
2252 b'web',
2248 b'allowgz',
2253 b'allowgz',
2249 default=False,
2254 default=False,
2250 )
2255 )
2251 coreconfigitem(
2256 coreconfigitem(
2252 b'web',
2257 b'web',
2253 b'allow-pull',
2258 b'allow-pull',
2254 alias=[(b'web', b'allowpull')],
2259 alias=[(b'web', b'allowpull')],
2255 default=True,
2260 default=True,
2256 )
2261 )
2257 coreconfigitem(
2262 coreconfigitem(
2258 b'web',
2263 b'web',
2259 b'allow-push',
2264 b'allow-push',
2260 alias=[(b'web', b'allow_push')],
2265 alias=[(b'web', b'allow_push')],
2261 default=list,
2266 default=list,
2262 )
2267 )
2263 coreconfigitem(
2268 coreconfigitem(
2264 b'web',
2269 b'web',
2265 b'allowzip',
2270 b'allowzip',
2266 default=False,
2271 default=False,
2267 )
2272 )
2268 coreconfigitem(
2273 coreconfigitem(
2269 b'web',
2274 b'web',
2270 b'archivesubrepos',
2275 b'archivesubrepos',
2271 default=False,
2276 default=False,
2272 )
2277 )
2273 coreconfigitem(
2278 coreconfigitem(
2274 b'web',
2279 b'web',
2275 b'cache',
2280 b'cache',
2276 default=True,
2281 default=True,
2277 )
2282 )
2278 coreconfigitem(
2283 coreconfigitem(
2279 b'web',
2284 b'web',
2280 b'comparisoncontext',
2285 b'comparisoncontext',
2281 default=5,
2286 default=5,
2282 )
2287 )
2283 coreconfigitem(
2288 coreconfigitem(
2284 b'web',
2289 b'web',
2285 b'contact',
2290 b'contact',
2286 default=None,
2291 default=None,
2287 )
2292 )
2288 coreconfigitem(
2293 coreconfigitem(
2289 b'web',
2294 b'web',
2290 b'deny_push',
2295 b'deny_push',
2291 default=list,
2296 default=list,
2292 )
2297 )
2293 coreconfigitem(
2298 coreconfigitem(
2294 b'web',
2299 b'web',
2295 b'guessmime',
2300 b'guessmime',
2296 default=False,
2301 default=False,
2297 )
2302 )
2298 coreconfigitem(
2303 coreconfigitem(
2299 b'web',
2304 b'web',
2300 b'hidden',
2305 b'hidden',
2301 default=False,
2306 default=False,
2302 )
2307 )
2303 coreconfigitem(
2308 coreconfigitem(
2304 b'web',
2309 b'web',
2305 b'labels',
2310 b'labels',
2306 default=list,
2311 default=list,
2307 )
2312 )
2308 coreconfigitem(
2313 coreconfigitem(
2309 b'web',
2314 b'web',
2310 b'logoimg',
2315 b'logoimg',
2311 default=b'hglogo.png',
2316 default=b'hglogo.png',
2312 )
2317 )
2313 coreconfigitem(
2318 coreconfigitem(
2314 b'web',
2319 b'web',
2315 b'logourl',
2320 b'logourl',
2316 default=b'https://mercurial-scm.org/',
2321 default=b'https://mercurial-scm.org/',
2317 )
2322 )
2318 coreconfigitem(
2323 coreconfigitem(
2319 b'web',
2324 b'web',
2320 b'accesslog',
2325 b'accesslog',
2321 default=b'-',
2326 default=b'-',
2322 )
2327 )
2323 coreconfigitem(
2328 coreconfigitem(
2324 b'web',
2329 b'web',
2325 b'address',
2330 b'address',
2326 default=b'',
2331 default=b'',
2327 )
2332 )
2328 coreconfigitem(
2333 coreconfigitem(
2329 b'web',
2334 b'web',
2330 b'allow-archive',
2335 b'allow-archive',
2331 alias=[(b'web', b'allow_archive')],
2336 alias=[(b'web', b'allow_archive')],
2332 default=list,
2337 default=list,
2333 )
2338 )
2334 coreconfigitem(
2339 coreconfigitem(
2335 b'web',
2340 b'web',
2336 b'allow_read',
2341 b'allow_read',
2337 default=list,
2342 default=list,
2338 )
2343 )
2339 coreconfigitem(
2344 coreconfigitem(
2340 b'web',
2345 b'web',
2341 b'baseurl',
2346 b'baseurl',
2342 default=None,
2347 default=None,
2343 )
2348 )
2344 coreconfigitem(
2349 coreconfigitem(
2345 b'web',
2350 b'web',
2346 b'cacerts',
2351 b'cacerts',
2347 default=None,
2352 default=None,
2348 )
2353 )
2349 coreconfigitem(
2354 coreconfigitem(
2350 b'web',
2355 b'web',
2351 b'certificate',
2356 b'certificate',
2352 default=None,
2357 default=None,
2353 )
2358 )
2354 coreconfigitem(
2359 coreconfigitem(
2355 b'web',
2360 b'web',
2356 b'collapse',
2361 b'collapse',
2357 default=False,
2362 default=False,
2358 )
2363 )
2359 coreconfigitem(
2364 coreconfigitem(
2360 b'web',
2365 b'web',
2361 b'csp',
2366 b'csp',
2362 default=None,
2367 default=None,
2363 )
2368 )
2364 coreconfigitem(
2369 coreconfigitem(
2365 b'web',
2370 b'web',
2366 b'deny_read',
2371 b'deny_read',
2367 default=list,
2372 default=list,
2368 )
2373 )
2369 coreconfigitem(
2374 coreconfigitem(
2370 b'web',
2375 b'web',
2371 b'descend',
2376 b'descend',
2372 default=True,
2377 default=True,
2373 )
2378 )
2374 coreconfigitem(
2379 coreconfigitem(
2375 b'web',
2380 b'web',
2376 b'description',
2381 b'description',
2377 default=b"",
2382 default=b"",
2378 )
2383 )
2379 coreconfigitem(
2384 coreconfigitem(
2380 b'web',
2385 b'web',
2381 b'encoding',
2386 b'encoding',
2382 default=lambda: encoding.encoding,
2387 default=lambda: encoding.encoding,
2383 )
2388 )
2384 coreconfigitem(
2389 coreconfigitem(
2385 b'web',
2390 b'web',
2386 b'errorlog',
2391 b'errorlog',
2387 default=b'-',
2392 default=b'-',
2388 )
2393 )
2389 coreconfigitem(
2394 coreconfigitem(
2390 b'web',
2395 b'web',
2391 b'ipv6',
2396 b'ipv6',
2392 default=False,
2397 default=False,
2393 )
2398 )
2394 coreconfigitem(
2399 coreconfigitem(
2395 b'web',
2400 b'web',
2396 b'maxchanges',
2401 b'maxchanges',
2397 default=10,
2402 default=10,
2398 )
2403 )
2399 coreconfigitem(
2404 coreconfigitem(
2400 b'web',
2405 b'web',
2401 b'maxfiles',
2406 b'maxfiles',
2402 default=10,
2407 default=10,
2403 )
2408 )
2404 coreconfigitem(
2409 coreconfigitem(
2405 b'web',
2410 b'web',
2406 b'maxshortchanges',
2411 b'maxshortchanges',
2407 default=60,
2412 default=60,
2408 )
2413 )
2409 coreconfigitem(
2414 coreconfigitem(
2410 b'web',
2415 b'web',
2411 b'motd',
2416 b'motd',
2412 default=b'',
2417 default=b'',
2413 )
2418 )
2414 coreconfigitem(
2419 coreconfigitem(
2415 b'web',
2420 b'web',
2416 b'name',
2421 b'name',
2417 default=dynamicdefault,
2422 default=dynamicdefault,
2418 )
2423 )
2419 coreconfigitem(
2424 coreconfigitem(
2420 b'web',
2425 b'web',
2421 b'port',
2426 b'port',
2422 default=8000,
2427 default=8000,
2423 )
2428 )
2424 coreconfigitem(
2429 coreconfigitem(
2425 b'web',
2430 b'web',
2426 b'prefix',
2431 b'prefix',
2427 default=b'',
2432 default=b'',
2428 )
2433 )
2429 coreconfigitem(
2434 coreconfigitem(
2430 b'web',
2435 b'web',
2431 b'push_ssl',
2436 b'push_ssl',
2432 default=True,
2437 default=True,
2433 )
2438 )
2434 coreconfigitem(
2439 coreconfigitem(
2435 b'web',
2440 b'web',
2436 b'refreshinterval',
2441 b'refreshinterval',
2437 default=20,
2442 default=20,
2438 )
2443 )
2439 coreconfigitem(
2444 coreconfigitem(
2440 b'web',
2445 b'web',
2441 b'server-header',
2446 b'server-header',
2442 default=None,
2447 default=None,
2443 )
2448 )
2444 coreconfigitem(
2449 coreconfigitem(
2445 b'web',
2450 b'web',
2446 b'static',
2451 b'static',
2447 default=None,
2452 default=None,
2448 )
2453 )
2449 coreconfigitem(
2454 coreconfigitem(
2450 b'web',
2455 b'web',
2451 b'staticurl',
2456 b'staticurl',
2452 default=None,
2457 default=None,
2453 )
2458 )
2454 coreconfigitem(
2459 coreconfigitem(
2455 b'web',
2460 b'web',
2456 b'stripes',
2461 b'stripes',
2457 default=1,
2462 default=1,
2458 )
2463 )
2459 coreconfigitem(
2464 coreconfigitem(
2460 b'web',
2465 b'web',
2461 b'style',
2466 b'style',
2462 default=b'paper',
2467 default=b'paper',
2463 )
2468 )
2464 coreconfigitem(
2469 coreconfigitem(
2465 b'web',
2470 b'web',
2466 b'templates',
2471 b'templates',
2467 default=None,
2472 default=None,
2468 )
2473 )
2469 coreconfigitem(
2474 coreconfigitem(
2470 b'web',
2475 b'web',
2471 b'view',
2476 b'view',
2472 default=b'served',
2477 default=b'served',
2473 experimental=True,
2478 experimental=True,
2474 )
2479 )
2475 coreconfigitem(
2480 coreconfigitem(
2476 b'worker',
2481 b'worker',
2477 b'backgroundclose',
2482 b'backgroundclose',
2478 default=dynamicdefault,
2483 default=dynamicdefault,
2479 )
2484 )
2480 # Windows defaults to a limit of 512 open files. A buffer of 128
2485 # Windows defaults to a limit of 512 open files. A buffer of 128
2481 # should give us enough headway.
2486 # should give us enough headway.
2482 coreconfigitem(
2487 coreconfigitem(
2483 b'worker',
2488 b'worker',
2484 b'backgroundclosemaxqueue',
2489 b'backgroundclosemaxqueue',
2485 default=384,
2490 default=384,
2486 )
2491 )
2487 coreconfigitem(
2492 coreconfigitem(
2488 b'worker',
2493 b'worker',
2489 b'backgroundcloseminfilecount',
2494 b'backgroundcloseminfilecount',
2490 default=2048,
2495 default=2048,
2491 )
2496 )
2492 coreconfigitem(
2497 coreconfigitem(
2493 b'worker',
2498 b'worker',
2494 b'backgroundclosethreadcount',
2499 b'backgroundclosethreadcount',
2495 default=4,
2500 default=4,
2496 )
2501 )
2497 coreconfigitem(
2502 coreconfigitem(
2498 b'worker',
2503 b'worker',
2499 b'enabled',
2504 b'enabled',
2500 default=True,
2505 default=True,
2501 )
2506 )
2502 coreconfigitem(
2507 coreconfigitem(
2503 b'worker',
2508 b'worker',
2504 b'numcpus',
2509 b'numcpus',
2505 default=None,
2510 default=None,
2506 )
2511 )
2507
2512
2508 # Rebase related configuration moved to core because other extension are doing
2513 # Rebase related configuration moved to core because other extension are doing
2509 # strange things. For example, shelve import the extensions to reuse some bit
2514 # strange things. For example, shelve import the extensions to reuse some bit
2510 # without formally loading it.
2515 # without formally loading it.
2511 coreconfigitem(
2516 coreconfigitem(
2512 b'commands',
2517 b'commands',
2513 b'rebase.requiredest',
2518 b'rebase.requiredest',
2514 default=False,
2519 default=False,
2515 )
2520 )
2516 coreconfigitem(
2521 coreconfigitem(
2517 b'experimental',
2522 b'experimental',
2518 b'rebaseskipobsolete',
2523 b'rebaseskipobsolete',
2519 default=True,
2524 default=True,
2520 )
2525 )
2521 coreconfigitem(
2526 coreconfigitem(
2522 b'rebase',
2527 b'rebase',
2523 b'singletransaction',
2528 b'singletransaction',
2524 default=False,
2529 default=False,
2525 )
2530 )
2526 coreconfigitem(
2531 coreconfigitem(
2527 b'rebase',
2532 b'rebase',
2528 b'experimental.inmemory',
2533 b'experimental.inmemory',
2529 default=False,
2534 default=False,
2530 )
2535 )
@@ -1,1446 +1,1478
1 ==================================================
1 ==================================================
2 Test obsmarkers interaction with bundle and strip
2 Test obsmarkers interaction with bundle and strip
3 ==================================================
3 ==================================================
4
4
5 Setup a repository with various case
5 Setup a repository with various case
6 ====================================
6 ====================================
7
7
8 Config setup
8 Config setup
9 ------------
9 ------------
10
10
11 $ cat >> $HGRCPATH <<EOF
11 $ cat >> $HGRCPATH <<EOF
12 > [command-templates]
12 > [command-templates]
13 > # simpler log output
13 > # simpler log output
14 > log = "{node|short}: {desc}\n"
14 > log = "{node|short}: {desc}\n"
15 >
15 >
16 > [experimental]
16 > [experimental]
17 > # enable evolution
17 > # enable evolution
18 > evolution=true
18 > evolution=true
19 >
19 >
20 > # include obsmarkers in bundle
20 > # include obsmarkers in bundle
21 > evolution.bundle-obsmarker = yes
21 > evolution.bundle-obsmarker = yes
22 >
22 >
23 > [extensions]
23 > [extensions]
24 > # needed for some tests
24 > # needed for some tests
25 > strip =
25 > strip =
26 > [defaults]
26 > [defaults]
27 > # we'll query many hidden changeset
27 > # we'll query many hidden changeset
28 > debugobsolete = --hidden
28 > debugobsolete = --hidden
29 > EOF
29 > EOF
30
30
31 $ mkcommit() {
31 $ mkcommit() {
32 > echo "$1" > "$1"
32 > echo "$1" > "$1"
33 > hg add "$1"
33 > hg add "$1"
34 > hg ci -m "$1"
34 > hg ci -m "$1"
35 > }
35 > }
36
36
37 $ getid() {
37 $ getid() {
38 > hg log --hidden --template '{node}\n' --rev "$1"
38 > hg log --hidden --template '{node}\n' --rev "$1"
39 > }
39 > }
40
40
41 $ mktestrepo () {
41 $ mktestrepo () {
42 > [ -n "$1" ] || exit 1
42 > [ -n "$1" ] || exit 1
43 > cd $TESTTMP
43 > cd $TESTTMP
44 > hg init $1
44 > hg init $1
45 > cd $1
45 > cd $1
46 > mkcommit ROOT
46 > mkcommit ROOT
47 > }
47 > }
48
48
49 Function to compare the expected bundled obsmarkers with the actually bundled
49 Function to compare the expected bundled obsmarkers with the actually bundled
50 obsmarkers. It also check the obsmarkers backed up during strip.
50 obsmarkers. It also check the obsmarkers backed up during strip.
51
51
52 $ testrevs () {
52 $ testrevs () {
53 > revs="$1"
53 > revs="$1"
54 > testname=`basename \`pwd\``
54 > testname=`basename \`pwd\``
55 > revsname=`hg --hidden log -T '-{desc}' --rev "${revs}"`
55 > revsname=`hg --hidden log -T '-{desc}' --rev "${revs}"`
56 > prefix="${TESTTMP}/${testname}${revsname}"
56 > prefix="${TESTTMP}/${testname}${revsname}"
57 > markersfile="${prefix}-relevant-markers.txt"
57 > markersfile="${prefix}-relevant-markers.txt"
58 > exclufile="${prefix}-exclusive-markers.txt"
58 > exclufile="${prefix}-exclusive-markers.txt"
59 > bundlefile="${prefix}-bundle.hg"
59 > bundlefile="${prefix}-bundle.hg"
60 > contentfile="${prefix}-bundle-markers.hg"
60 > contentfile="${prefix}-bundle-markers.hg"
61 > stripcontentfile="${prefix}-bundle-markers.hg"
61 > stripcontentfile="${prefix}-bundle-markers.hg"
62 > hg debugobsolete --hidden --rev "${revs}" | sed 's/^/ /' > "${markersfile}"
62 > hg debugobsolete --hidden --rev "${revs}" | sed 's/^/ /' > "${markersfile}"
63 > hg debugobsolete --hidden --rev "${revs}" --exclusive | sed 's/^/ /' > "${exclufile}"
63 > hg debugobsolete --hidden --rev "${revs}" --exclusive | sed 's/^/ /' > "${exclufile}"
64 > echo '### Matched revisions###'
64 > echo '### Matched revisions###'
65 > hg log --hidden --rev "${revs}" | sort
65 > hg log --hidden --rev "${revs}" | sort
66 > echo '### Relevant markers ###'
66 > echo '### Relevant markers ###'
67 > cat "${markersfile}"
67 > cat "${markersfile}"
68 > printf "# bundling: "
68 > printf "# bundling: "
69 > hg bundle --hidden --base "parents(roots(${revs}))" --rev "${revs}" "${bundlefile}"
69 > hg bundle --hidden --base "parents(roots(${revs}))" --rev "${revs}" "${bundlefile}"
70 > hg debugbundle --part-type obsmarkers "${bundlefile}" | sed 1,3d > "${contentfile}"
70 > hg debugbundle --part-type obsmarkers "${bundlefile}" | sed 1,3d > "${contentfile}"
71 > echo '### Bundled markers ###'
71 > echo '### Bundled markers ###'
72 > cat "${contentfile}"
72 > cat "${contentfile}"
73 > echo '### diff <relevant> <bundled> ###'
73 > echo '### diff <relevant> <bundled> ###'
74 > cmp "${markersfile}" "${contentfile}" || diff -u "${markersfile}" "${contentfile}"
74 > cmp "${markersfile}" "${contentfile}" || diff -u "${markersfile}" "${contentfile}"
75 > echo '#################################'
75 > echo '#################################'
76 > echo '### Exclusive markers ###'
76 > echo '### Exclusive markers ###'
77 > cat "${exclufile}"
77 > cat "${exclufile}"
78 > # if the matched revs do not have children, we also check the result of strip
78 > # if the matched revs do not have children, we also check the result of strip
79 > children=`hg log --hidden --rev "((${revs})::) - (${revs})"`
79 > children=`hg log --hidden --rev "((${revs})::) - (${revs})"`
80 > if [ -z "$children" ];
80 > if [ -z "$children" ];
81 > then
81 > then
82 > printf "# stripping: "
82 > printf "# stripping: "
83 > prestripfile="${prefix}-pre-strip.txt"
83 > prestripfile="${prefix}-pre-strip.txt"
84 > poststripfile="${prefix}-post-strip.txt"
84 > poststripfile="${prefix}-post-strip.txt"
85 > strippedfile="${prefix}-stripped-markers.txt"
85 > strippedfile="${prefix}-stripped-markers.txt"
86 > hg debugobsolete --hidden | sort | sed 's/^/ /' > "${prestripfile}"
86 > hg debugobsolete --hidden | sort | sed 's/^/ /' > "${prestripfile}"
87 > hg strip --hidden --rev "${revs}"
87 > hg strip --hidden --rev "${revs}"
88 > hg debugobsolete --hidden | sort | sed 's/^/ /' > "${poststripfile}"
88 > hg debugobsolete --hidden | sort | sed 's/^/ /' > "${poststripfile}"
89 > hg debugbundle --part-type obsmarkers .hg/strip-backup/* | sed 1,3d > "${stripcontentfile}"
89 > hg debugbundle --part-type obsmarkers .hg/strip-backup/* | sed 1,3d > "${stripcontentfile}"
90 > echo '### Backup markers ###'
90 > echo '### Backup markers ###'
91 > cat "${stripcontentfile}"
91 > cat "${stripcontentfile}"
92 > echo '### diff <relevant> <backed-up> ###'
92 > echo '### diff <relevant> <backed-up> ###'
93 > cmp "${markersfile}" "${stripcontentfile}" || diff -u "${markersfile}" "${stripcontentfile}"
93 > cmp "${markersfile}" "${stripcontentfile}" || diff -u "${markersfile}" "${stripcontentfile}"
94 > echo '#################################'
94 > echo '#################################'
95 > cat "${prestripfile}" "${poststripfile}" | sort | uniq -u > "${strippedfile}"
95 > cat "${prestripfile}" "${poststripfile}" | sort | uniq -u > "${strippedfile}"
96 > echo '### Stripped markers ###'
96 > echo '### Stripped markers ###'
97 > cat "${strippedfile}"
97 > cat "${strippedfile}"
98 > echo '### diff <exclusive> <stripped> ###'
98 > echo '### diff <exclusive> <stripped> ###'
99 > cmp "${exclufile}" "${strippedfile}" || diff -u "${exclufile}" "${strippedfile}"
99 > cmp "${exclufile}" "${strippedfile}" || diff -u "${exclufile}" "${strippedfile}"
100 > echo '#################################'
100 > echo '#################################'
101 > # restore and clean up repo for the next test
101 > # restore and clean up repo for the next test
102 > hg unbundle .hg/strip-backup/* | sed 's/^/# unbundling: /'
102 > hg unbundle .hg/strip-backup/* | sed 's/^/# unbundling: /'
103 > # clean up directory for the next test
103 > # clean up directory for the next test
104 > rm .hg/strip-backup/*
104 > rm .hg/strip-backup/*
105 > fi
105 > fi
106 > }
106 > }
107
107
108 root setup
108 root setup
109 -------------
109 -------------
110
110
111 simple chain
111 simple chain
112 ============
112 ============
113
113
114 . A0
114 . A0
115 . ⇠ø⇠◔ A1
115 . ⇠ø⇠◔ A1
116 . |/
116 . |/
117 . ●
117 . ●
118
118
119 setup
119 setup
120 -----
120 -----
121
121
122 $ mktestrepo simple-chain
122 $ mktestrepo simple-chain
123 $ mkcommit 'C-A0'
123 $ mkcommit 'C-A0'
124 $ hg up 'desc("ROOT")'
124 $ hg up 'desc("ROOT")'
125 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
125 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
126 $ mkcommit 'C-A1'
126 $ mkcommit 'C-A1'
127 created new head
127 created new head
128 $ hg debugobsolete a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 `getid 'desc("C-A0")'`
128 $ hg debugobsolete a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 `getid 'desc("C-A0")'`
129 1 new obsolescence markers
129 1 new obsolescence markers
130 $ hg debugobsolete `getid 'desc("C-A0")'` a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1
130 $ hg debugobsolete `getid 'desc("C-A0")'` a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1
131 1 new obsolescence markers
131 1 new obsolescence markers
132 obsoleted 1 changesets
132 obsoleted 1 changesets
133 $ hg debugobsolete a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 `getid 'desc("C-A1")'`
133 $ hg debugobsolete a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 `getid 'desc("C-A1")'`
134 1 new obsolescence markers
134 1 new obsolescence markers
135
135
136 $ hg up 'desc("ROOT")'
136 $ hg up 'desc("ROOT")'
137 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
137 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
138 $ hg log --hidden -G
138 $ hg log --hidden -G
139 o cf2c22470d67: C-A1
139 o cf2c22470d67: C-A1
140 |
140 |
141 | x 84fcb0dfe17b: C-A0
141 | x 84fcb0dfe17b: C-A0
142 |/
142 |/
143 @ ea207398892e: ROOT
143 @ ea207398892e: ROOT
144
144
145 $ hg debugobsolete
145 $ hg debugobsolete
146 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
146 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
147 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
147 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
148 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
148 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
149
149
150 Actual testing
150 Actual testing
151 --------------
151 --------------
152
152
153 $ testrevs 'desc("C-A0")'
153 $ testrevs 'desc("C-A0")'
154 ### Matched revisions###
154 ### Matched revisions###
155 84fcb0dfe17b: C-A0
155 84fcb0dfe17b: C-A0
156 ### Relevant markers ###
156 ### Relevant markers ###
157 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
157 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
158 # bundling: 1 changesets found
158 # bundling: 1 changesets found
159 ### Bundled markers ###
159 ### Bundled markers ###
160 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
160 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
161 ### diff <relevant> <bundled> ###
161 ### diff <relevant> <bundled> ###
162 #################################
162 #################################
163 ### Exclusive markers ###
163 ### Exclusive markers ###
164 # stripping: saved backup bundle to $TESTTMP/simple-chain/.hg/strip-backup/84fcb0dfe17b-6454bbdc-backup.hg
164 # stripping: saved backup bundle to $TESTTMP/simple-chain/.hg/strip-backup/84fcb0dfe17b-6454bbdc-backup.hg
165 ### Backup markers ###
165 ### Backup markers ###
166 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
166 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
167 ### diff <relevant> <backed-up> ###
167 ### diff <relevant> <backed-up> ###
168 #################################
168 #################################
169 ### Stripped markers ###
169 ### Stripped markers ###
170 ### diff <exclusive> <stripped> ###
170 ### diff <exclusive> <stripped> ###
171 #################################
171 #################################
172 # unbundling: adding changesets
172 # unbundling: adding changesets
173 # unbundling: adding manifests
173 # unbundling: adding manifests
174 # unbundling: adding file changes
174 # unbundling: adding file changes
175 # unbundling: added 1 changesets with 1 changes to 1 files (+1 heads)
175 # unbundling: added 1 changesets with 1 changes to 1 files (+1 heads)
176 # unbundling: (1 other changesets obsolete on arrival)
176 # unbundling: (1 other changesets obsolete on arrival)
177 # unbundling: (run 'hg heads' to see heads)
177 # unbundling: (run 'hg heads' to see heads)
178
178
179 $ testrevs 'desc("C-A1")'
179 $ testrevs 'desc("C-A1")'
180 ### Matched revisions###
180 ### Matched revisions###
181 cf2c22470d67: C-A1
181 cf2c22470d67: C-A1
182 ### Relevant markers ###
182 ### Relevant markers ###
183 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
183 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
184 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
184 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
185 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
185 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
186 # bundling: 1 changesets found
186 # bundling: 1 changesets found
187 ### Bundled markers ###
187 ### Bundled markers ###
188 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
188 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
189 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
189 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
190 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
190 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
191 ### diff <relevant> <bundled> ###
191 ### diff <relevant> <bundled> ###
192 #################################
192 #################################
193 ### Exclusive markers ###
193 ### Exclusive markers ###
194 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
194 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
195 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
195 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
196 # stripping: saved backup bundle to $TESTTMP/simple-chain/.hg/strip-backup/cf2c22470d67-fa0f07b0-backup.hg
196 # stripping: saved backup bundle to $TESTTMP/simple-chain/.hg/strip-backup/cf2c22470d67-fa0f07b0-backup.hg
197 ### Backup markers ###
197 ### Backup markers ###
198 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
198 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
199 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
199 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
200 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
200 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
201 ### diff <relevant> <backed-up> ###
201 ### diff <relevant> <backed-up> ###
202 #################################
202 #################################
203 ### Stripped markers ###
203 ### Stripped markers ###
204 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
204 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
205 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
205 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
206 ### diff <exclusive> <stripped> ###
206 ### diff <exclusive> <stripped> ###
207 #################################
207 #################################
208 # unbundling: adding changesets
208 # unbundling: adding changesets
209 # unbundling: adding manifests
209 # unbundling: adding manifests
210 # unbundling: adding file changes
210 # unbundling: adding file changes
211 # unbundling: added 1 changesets with 1 changes to 1 files (+1 heads)
211 # unbundling: added 1 changesets with 1 changes to 1 files (+1 heads)
212 # unbundling: 2 new obsolescence markers
212 # unbundling: 2 new obsolescence markers
213 # unbundling: obsoleted 1 changesets
213 # unbundling: obsoleted 1 changesets
214 # unbundling: new changesets cf2c22470d67 (1 drafts)
214 # unbundling: new changesets cf2c22470d67 (1 drafts)
215 # unbundling: (run 'hg heads' to see heads)
215 # unbundling: (run 'hg heads' to see heads)
216
216
217 $ testrevs 'desc("C-A")'
217 $ testrevs 'desc("C-A")'
218 ### Matched revisions###
218 ### Matched revisions###
219 84fcb0dfe17b: C-A0
219 84fcb0dfe17b: C-A0
220 cf2c22470d67: C-A1
220 cf2c22470d67: C-A1
221 ### Relevant markers ###
221 ### Relevant markers ###
222 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
222 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
223 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
223 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
224 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
224 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
225 # bundling: 2 changesets found
225 # bundling: 2 changesets found
226 ### Bundled markers ###
226 ### Bundled markers ###
227 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
227 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
228 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
228 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
229 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
229 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
230 ### diff <relevant> <bundled> ###
230 ### diff <relevant> <bundled> ###
231 #################################
231 #################################
232 ### Exclusive markers ###
232 ### Exclusive markers ###
233 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
233 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
234 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
234 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
235 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
235 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
236 # stripping: saved backup bundle to $TESTTMP/simple-chain/.hg/strip-backup/cf2c22470d67-fce4fc64-backup.hg
236 # stripping: saved backup bundle to $TESTTMP/simple-chain/.hg/strip-backup/cf2c22470d67-fce4fc64-backup.hg
237 ### Backup markers ###
237 ### Backup markers ###
238 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
238 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
239 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
239 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
240 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
240 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
241 ### diff <relevant> <backed-up> ###
241 ### diff <relevant> <backed-up> ###
242 #################################
242 #################################
243 ### Stripped markers ###
243 ### Stripped markers ###
244 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
244 84fcb0dfe17b256ebae52e05572993b9194c018a a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
245 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
245 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
246 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
246 a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1a1 cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
247 ### diff <exclusive> <stripped> ###
247 ### diff <exclusive> <stripped> ###
248 #################################
248 #################################
249 # unbundling: adding changesets
249 # unbundling: adding changesets
250 # unbundling: adding manifests
250 # unbundling: adding manifests
251 # unbundling: adding file changes
251 # unbundling: adding file changes
252 # unbundling: added 2 changesets with 2 changes to 2 files (+1 heads)
252 # unbundling: added 2 changesets with 2 changes to 2 files (+1 heads)
253 # unbundling: 3 new obsolescence markers
253 # unbundling: 3 new obsolescence markers
254 # unbundling: new changesets cf2c22470d67 (1 drafts)
254 # unbundling: new changesets cf2c22470d67 (1 drafts)
255 # unbundling: (1 other changesets obsolete on arrival)
255 # unbundling: (1 other changesets obsolete on arrival)
256 # unbundling: (run 'hg heads' to see heads)
256 # unbundling: (run 'hg heads' to see heads)
257
257
258 chain with prune children
258 chain with prune children
259 =========================
259 =========================
260
260
261 . ⇠⊗ B0
261 . ⇠⊗ B0
262 . |
262 . |
263 . ⇠ø⇠◔ A1
263 . ⇠ø⇠◔ A1
264 . |
264 . |
265 . ●
265 . ●
266
266
267 setup
267 setup
268 -----
268 -----
269
269
270 $ mktestrepo prune
270 $ mktestrepo prune
271 $ mkcommit 'C-A0'
271 $ mkcommit 'C-A0'
272 $ mkcommit 'C-B0'
272 $ mkcommit 'C-B0'
273 $ hg up 'desc("ROOT")'
273 $ hg up 'desc("ROOT")'
274 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
274 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
275 $ mkcommit 'C-A1'
275 $ mkcommit 'C-A1'
276 created new head
276 created new head
277 $ hg debugobsolete a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 `getid 'desc("C-A0")'`
277 $ hg debugobsolete a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 `getid 'desc("C-A0")'`
278 1 new obsolescence markers
278 1 new obsolescence markers
279 $ hg debugobsolete `getid 'desc("C-A0")'` `getid 'desc("C-A1")'`
279 $ hg debugobsolete `getid 'desc("C-A0")'` `getid 'desc("C-A1")'`
280 1 new obsolescence markers
280 1 new obsolescence markers
281 obsoleted 1 changesets
281 obsoleted 1 changesets
282 1 new orphan changesets
282 1 new orphan changesets
283 $ hg debugobsolete --record-parents `getid 'desc("C-B0")'`
283 $ hg debugobsolete --record-parents `getid 'desc("C-B0")'`
284 1 new obsolescence markers
284 1 new obsolescence markers
285 obsoleted 1 changesets
285 obsoleted 1 changesets
286 $ hg up 'desc("ROOT")'
286 $ hg up 'desc("ROOT")'
287 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
287 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
288 $ hg log --hidden -G
288 $ hg log --hidden -G
289 o cf2c22470d67: C-A1
289 o cf2c22470d67: C-A1
290 |
290 |
291 | x 29f93b1df87b: C-B0
291 | x 29f93b1df87b: C-B0
292 | |
292 | |
293 | x 84fcb0dfe17b: C-A0
293 | x 84fcb0dfe17b: C-A0
294 |/
294 |/
295 @ ea207398892e: ROOT
295 @ ea207398892e: ROOT
296
296
297 $ hg debugobsolete
297 $ hg debugobsolete
298 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
298 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
299 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
299 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
300 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
300 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
301
301
302 Actual testing
302 Actual testing
303 --------------
303 --------------
304
304
305 $ testrevs 'desc("C-A0")'
305 $ testrevs 'desc("C-A0")'
306 ### Matched revisions###
306 ### Matched revisions###
307 84fcb0dfe17b: C-A0
307 84fcb0dfe17b: C-A0
308 ### Relevant markers ###
308 ### Relevant markers ###
309 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
309 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
310 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
310 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
311 # bundling: 1 changesets found
311 # bundling: 1 changesets found
312 ### Bundled markers ###
312 ### Bundled markers ###
313 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
313 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
314 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
314 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
315 ### diff <relevant> <bundled> ###
315 ### diff <relevant> <bundled> ###
316 #################################
316 #################################
317 ### Exclusive markers ###
317 ### Exclusive markers ###
318
318
319 (The strip markers is considered exclusive to the pruned changeset even if it
319 (The strip markers is considered exclusive to the pruned changeset even if it
320 is also considered "relevant" to its parent. This allows to strip prune
320 is also considered "relevant" to its parent. This allows to strip prune
321 markers. This avoid leaving prune markers from dead-end that could be
321 markers. This avoid leaving prune markers from dead-end that could be
322 problematic)
322 problematic)
323
323
324 $ testrevs 'desc("C-B0")'
324 $ testrevs 'desc("C-B0")'
325 ### Matched revisions###
325 ### Matched revisions###
326 29f93b1df87b: C-B0
326 29f93b1df87b: C-B0
327 ### Relevant markers ###
327 ### Relevant markers ###
328 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
328 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
329 # bundling: 1 changesets found
329 # bundling: 1 changesets found
330 ### Bundled markers ###
330 ### Bundled markers ###
331 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
331 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
332 ### diff <relevant> <bundled> ###
332 ### diff <relevant> <bundled> ###
333 #################################
333 #################################
334 ### Exclusive markers ###
334 ### Exclusive markers ###
335 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
335 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
336 # stripping: saved backup bundle to $TESTTMP/prune/.hg/strip-backup/29f93b1df87b-7fb32101-backup.hg
336 # stripping: saved backup bundle to $TESTTMP/prune/.hg/strip-backup/29f93b1df87b-7fb32101-backup.hg
337 ### Backup markers ###
337 ### Backup markers ###
338 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
338 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
339 ### diff <relevant> <backed-up> ###
339 ### diff <relevant> <backed-up> ###
340 #################################
340 #################################
341 ### Stripped markers ###
341 ### Stripped markers ###
342 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
342 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
343 ### diff <exclusive> <stripped> ###
343 ### diff <exclusive> <stripped> ###
344 #################################
344 #################################
345 # unbundling: adding changesets
345 # unbundling: adding changesets
346 # unbundling: adding manifests
346 # unbundling: adding manifests
347 # unbundling: adding file changes
347 # unbundling: adding file changes
348 # unbundling: added 1 changesets with 1 changes to 1 files
348 # unbundling: added 1 changesets with 1 changes to 1 files
349 # unbundling: 1 new obsolescence markers
349 # unbundling: 1 new obsolescence markers
350 # unbundling: (1 other changesets obsolete on arrival)
350 # unbundling: (1 other changesets obsolete on arrival)
351 # unbundling: (run 'hg update' to get a working copy)
351 # unbundling: (run 'hg update' to get a working copy)
352
352
353 $ testrevs 'desc("C-A1")'
353 $ testrevs 'desc("C-A1")'
354 ### Matched revisions###
354 ### Matched revisions###
355 cf2c22470d67: C-A1
355 cf2c22470d67: C-A1
356 ### Relevant markers ###
356 ### Relevant markers ###
357 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
357 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
358 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
358 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
359 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
359 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
360 # bundling: 1 changesets found
360 # bundling: 1 changesets found
361 ### Bundled markers ###
361 ### Bundled markers ###
362 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
362 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
363 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
363 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
364 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
364 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
365 ### diff <relevant> <bundled> ###
365 ### diff <relevant> <bundled> ###
366 #################################
366 #################################
367 ### Exclusive markers ###
367 ### Exclusive markers ###
368 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
368 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
369 # stripping: saved backup bundle to $TESTTMP/prune/.hg/strip-backup/cf2c22470d67-fa0f07b0-backup.hg
369 # stripping: saved backup bundle to $TESTTMP/prune/.hg/strip-backup/cf2c22470d67-fa0f07b0-backup.hg
370 ### Backup markers ###
370 ### Backup markers ###
371 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
371 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
372 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
372 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
373 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
373 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
374 ### diff <relevant> <backed-up> ###
374 ### diff <relevant> <backed-up> ###
375 #################################
375 #################################
376 ### Stripped markers ###
376 ### Stripped markers ###
377 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
377 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
378 ### diff <exclusive> <stripped> ###
378 ### diff <exclusive> <stripped> ###
379 #################################
379 #################################
380 # unbundling: adding changesets
380 # unbundling: adding changesets
381 # unbundling: adding manifests
381 # unbundling: adding manifests
382 # unbundling: adding file changes
382 # unbundling: adding file changes
383 # unbundling: added 1 changesets with 1 changes to 1 files (+1 heads)
383 # unbundling: added 1 changesets with 1 changes to 1 files (+1 heads)
384 # unbundling: 1 new obsolescence markers
384 # unbundling: 1 new obsolescence markers
385 # unbundling: obsoleted 1 changesets
385 # unbundling: obsoleted 1 changesets
386 # unbundling: new changesets cf2c22470d67 (1 drafts)
386 # unbundling: new changesets cf2c22470d67 (1 drafts)
387 # unbundling: (run 'hg heads' to see heads)
387 # unbundling: (run 'hg heads' to see heads)
388
388
389 bundling multiple revisions
389 bundling multiple revisions
390
390
391 $ testrevs 'desc("C-A")'
391 $ testrevs 'desc("C-A")'
392 ### Matched revisions###
392 ### Matched revisions###
393 84fcb0dfe17b: C-A0
393 84fcb0dfe17b: C-A0
394 cf2c22470d67: C-A1
394 cf2c22470d67: C-A1
395 ### Relevant markers ###
395 ### Relevant markers ###
396 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
396 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
397 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
397 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
398 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
398 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
399 # bundling: 2 changesets found
399 # bundling: 2 changesets found
400 ### Bundled markers ###
400 ### Bundled markers ###
401 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
401 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
402 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
402 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
403 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
403 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
404 ### diff <relevant> <bundled> ###
404 ### diff <relevant> <bundled> ###
405 #################################
405 #################################
406 ### Exclusive markers ###
406 ### Exclusive markers ###
407 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
407 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
408 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
408 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
409
409
410 $ testrevs 'desc("C-")'
410 $ testrevs 'desc("C-")'
411 ### Matched revisions###
411 ### Matched revisions###
412 29f93b1df87b: C-B0
412 29f93b1df87b: C-B0
413 84fcb0dfe17b: C-A0
413 84fcb0dfe17b: C-A0
414 cf2c22470d67: C-A1
414 cf2c22470d67: C-A1
415 ### Relevant markers ###
415 ### Relevant markers ###
416 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
416 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
417 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
417 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
418 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
418 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
419 # bundling: 3 changesets found
419 # bundling: 3 changesets found
420 ### Bundled markers ###
420 ### Bundled markers ###
421 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
421 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
422 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
422 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
423 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
423 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
424 ### diff <relevant> <bundled> ###
424 ### diff <relevant> <bundled> ###
425 #################################
425 #################################
426 ### Exclusive markers ###
426 ### Exclusive markers ###
427 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
427 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
428 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
428 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
429 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
429 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
430 # stripping: saved backup bundle to $TESTTMP/prune/.hg/strip-backup/cf2c22470d67-884c33b0-backup.hg
430 # stripping: saved backup bundle to $TESTTMP/prune/.hg/strip-backup/cf2c22470d67-884c33b0-backup.hg
431 ### Backup markers ###
431 ### Backup markers ###
432 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
432 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
433 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
433 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
434 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
434 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
435 ### diff <relevant> <backed-up> ###
435 ### diff <relevant> <backed-up> ###
436 #################################
436 #################################
437 ### Stripped markers ###
437 ### Stripped markers ###
438 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
438 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
439 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
439 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
440 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
440 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
441 ### diff <exclusive> <stripped> ###
441 ### diff <exclusive> <stripped> ###
442 #################################
442 #################################
443 # unbundling: adding changesets
443 # unbundling: adding changesets
444 # unbundling: adding manifests
444 # unbundling: adding manifests
445 # unbundling: adding file changes
445 # unbundling: adding file changes
446 # unbundling: added 3 changesets with 3 changes to 3 files (+1 heads)
446 # unbundling: added 3 changesets with 3 changes to 3 files (+1 heads)
447 # unbundling: 3 new obsolescence markers
447 # unbundling: 3 new obsolescence markers
448 # unbundling: new changesets cf2c22470d67 (1 drafts)
448 # unbundling: new changesets cf2c22470d67 (1 drafts)
449 # unbundling: (2 other changesets obsolete on arrival)
449 # unbundling: (2 other changesets obsolete on arrival)
450 # unbundling: (run 'hg heads' to see heads)
450 # unbundling: (run 'hg heads' to see heads)
451
451
452 chain with precursors also pruned
452 chain with precursors also pruned
453 =================================
453 =================================
454
454
455 . A0 (also pruned)
455 . A0 (also pruned)
456 . ⇠ø⇠◔ A1
456 . ⇠ø⇠◔ A1
457 . |
457 . |
458 . ●
458 . ●
459
459
460 setup
460 setup
461 -----
461 -----
462
462
463 $ mktestrepo prune-inline
463 $ mktestrepo prune-inline
464 $ mkcommit 'C-A0'
464 $ mkcommit 'C-A0'
465 $ hg up 'desc("ROOT")'
465 $ hg up 'desc("ROOT")'
466 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
466 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
467 $ mkcommit 'C-A1'
467 $ mkcommit 'C-A1'
468 created new head
468 created new head
469 $ hg debugobsolete a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 `getid 'desc("C-A0")'`
469 $ hg debugobsolete a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 `getid 'desc("C-A0")'`
470 1 new obsolescence markers
470 1 new obsolescence markers
471 $ hg debugobsolete --record-parents `getid 'desc("C-A0")'`
471 $ hg debugobsolete --record-parents `getid 'desc("C-A0")'`
472 1 new obsolescence markers
472 1 new obsolescence markers
473 obsoleted 1 changesets
473 obsoleted 1 changesets
474 $ hg debugobsolete `getid 'desc("C-A0")'` `getid 'desc("C-A1")'`
474 $ hg debugobsolete `getid 'desc("C-A0")'` `getid 'desc("C-A1")'`
475 1 new obsolescence markers
475 1 new obsolescence markers
476 $ hg up 'desc("ROOT")'
476 $ hg up 'desc("ROOT")'
477 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
477 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
478 $ hg log --hidden -G
478 $ hg log --hidden -G
479 o cf2c22470d67: C-A1
479 o cf2c22470d67: C-A1
480 |
480 |
481 | x 84fcb0dfe17b: C-A0
481 | x 84fcb0dfe17b: C-A0
482 |/
482 |/
483 @ ea207398892e: ROOT
483 @ ea207398892e: ROOT
484
484
485 $ hg debugobsolete
485 $ hg debugobsolete
486 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
486 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
487 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
487 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
488 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
488 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
489
489
490 Actual testing
490 Actual testing
491 --------------
491 --------------
492
492
493 $ testrevs 'desc("C-A0")'
493 $ testrevs 'desc("C-A0")'
494 ### Matched revisions###
494 ### Matched revisions###
495 84fcb0dfe17b: C-A0
495 84fcb0dfe17b: C-A0
496 ### Relevant markers ###
496 ### Relevant markers ###
497 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
497 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
498 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
498 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
499 # bundling: 1 changesets found
499 # bundling: 1 changesets found
500 ### Bundled markers ###
500 ### Bundled markers ###
501 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
501 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
502 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
502 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
503 ### diff <relevant> <bundled> ###
503 ### diff <relevant> <bundled> ###
504 #################################
504 #################################
505 ### Exclusive markers ###
505 ### Exclusive markers ###
506 # stripping: saved backup bundle to $TESTTMP/prune-inline/.hg/strip-backup/84fcb0dfe17b-6454bbdc-backup.hg
506 # stripping: saved backup bundle to $TESTTMP/prune-inline/.hg/strip-backup/84fcb0dfe17b-6454bbdc-backup.hg
507 ### Backup markers ###
507 ### Backup markers ###
508 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
508 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
509 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
509 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
510 ### diff <relevant> <backed-up> ###
510 ### diff <relevant> <backed-up> ###
511 #################################
511 #################################
512 ### Stripped markers ###
512 ### Stripped markers ###
513 ### diff <exclusive> <stripped> ###
513 ### diff <exclusive> <stripped> ###
514 #################################
514 #################################
515 # unbundling: adding changesets
515 # unbundling: adding changesets
516 # unbundling: adding manifests
516 # unbundling: adding manifests
517 # unbundling: adding file changes
517 # unbundling: adding file changes
518 # unbundling: added 1 changesets with 1 changes to 1 files (+1 heads)
518 # unbundling: added 1 changesets with 1 changes to 1 files (+1 heads)
519 # unbundling: (1 other changesets obsolete on arrival)
519 # unbundling: (1 other changesets obsolete on arrival)
520 # unbundling: (run 'hg heads' to see heads)
520 # unbundling: (run 'hg heads' to see heads)
521
521
522 $ testrevs 'desc("C-A1")'
522 $ testrevs 'desc("C-A1")'
523 ### Matched revisions###
523 ### Matched revisions###
524 cf2c22470d67: C-A1
524 cf2c22470d67: C-A1
525 ### Relevant markers ###
525 ### Relevant markers ###
526 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
526 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
527 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
527 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
528 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
528 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
529 # bundling: 1 changesets found
529 # bundling: 1 changesets found
530 ### Bundled markers ###
530 ### Bundled markers ###
531 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
531 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
532 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
532 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
533 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
533 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
534 ### diff <relevant> <bundled> ###
534 ### diff <relevant> <bundled> ###
535 #################################
535 #################################
536 ### Exclusive markers ###
536 ### Exclusive markers ###
537 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
537 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
538 # stripping: saved backup bundle to $TESTTMP/prune-inline/.hg/strip-backup/cf2c22470d67-fa0f07b0-backup.hg
538 # stripping: saved backup bundle to $TESTTMP/prune-inline/.hg/strip-backup/cf2c22470d67-fa0f07b0-backup.hg
539 ### Backup markers ###
539 ### Backup markers ###
540 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
540 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
541 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
541 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
542 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
542 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
543 ### diff <relevant> <backed-up> ###
543 ### diff <relevant> <backed-up> ###
544 #################################
544 #################################
545 ### Stripped markers ###
545 ### Stripped markers ###
546 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
546 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
547 ### diff <exclusive> <stripped> ###
547 ### diff <exclusive> <stripped> ###
548 #################################
548 #################################
549 # unbundling: adding changesets
549 # unbundling: adding changesets
550 # unbundling: adding manifests
550 # unbundling: adding manifests
551 # unbundling: adding file changes
551 # unbundling: adding file changes
552 # unbundling: added 1 changesets with 1 changes to 1 files (+1 heads)
552 # unbundling: added 1 changesets with 1 changes to 1 files (+1 heads)
553 # unbundling: 1 new obsolescence markers
553 # unbundling: 1 new obsolescence markers
554 # unbundling: new changesets cf2c22470d67 (1 drafts)
554 # unbundling: new changesets cf2c22470d67 (1 drafts)
555 # unbundling: (run 'hg heads' to see heads)
555 # unbundling: (run 'hg heads' to see heads)
556
556
557 $ testrevs 'desc("C-A")'
557 $ testrevs 'desc("C-A")'
558 ### Matched revisions###
558 ### Matched revisions###
559 84fcb0dfe17b: C-A0
559 84fcb0dfe17b: C-A0
560 cf2c22470d67: C-A1
560 cf2c22470d67: C-A1
561 ### Relevant markers ###
561 ### Relevant markers ###
562 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
562 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
563 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
563 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
564 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
564 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
565 # bundling: 2 changesets found
565 # bundling: 2 changesets found
566 ### Bundled markers ###
566 ### Bundled markers ###
567 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
567 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
568 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
568 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
569 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
569 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
570 ### diff <relevant> <bundled> ###
570 ### diff <relevant> <bundled> ###
571 #################################
571 #################################
572 ### Exclusive markers ###
572 ### Exclusive markers ###
573 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
573 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
574 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
574 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
575 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
575 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
576 # stripping: saved backup bundle to $TESTTMP/prune-inline/.hg/strip-backup/cf2c22470d67-fce4fc64-backup.hg
576 # stripping: saved backup bundle to $TESTTMP/prune-inline/.hg/strip-backup/cf2c22470d67-fce4fc64-backup.hg
577 ### Backup markers ###
577 ### Backup markers ###
578 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
578 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
579 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
579 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
580 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
580 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
581 ### diff <relevant> <backed-up> ###
581 ### diff <relevant> <backed-up> ###
582 #################################
582 #################################
583 ### Stripped markers ###
583 ### Stripped markers ###
584 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
584 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
585 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
585 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
586 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
586 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
587 ### diff <exclusive> <stripped> ###
587 ### diff <exclusive> <stripped> ###
588 #################################
588 #################################
589 # unbundling: adding changesets
589 # unbundling: adding changesets
590 # unbundling: adding manifests
590 # unbundling: adding manifests
591 # unbundling: adding file changes
591 # unbundling: adding file changes
592 # unbundling: added 2 changesets with 2 changes to 2 files (+1 heads)
592 # unbundling: added 2 changesets with 2 changes to 2 files (+1 heads)
593 # unbundling: 3 new obsolescence markers
593 # unbundling: 3 new obsolescence markers
594 # unbundling: new changesets cf2c22470d67 (1 drafts)
594 # unbundling: new changesets cf2c22470d67 (1 drafts)
595 # unbundling: (1 other changesets obsolete on arrival)
595 # unbundling: (1 other changesets obsolete on arrival)
596 # unbundling: (run 'hg heads' to see heads)
596 # unbundling: (run 'hg heads' to see heads)
597
597
598 chain with missing prune
598 chain with missing prune
599 ========================
599 ========================
600
600
601 . ⊗ B
601 . ⊗ B
602 . |
602 . |
603 . ⇠◌⇠◔ A1
603 . ⇠◌⇠◔ A1
604 . |
604 . |
605 . ●
605 . ●
606
606
607 setup
607 setup
608 -----
608 -----
609
609
610 $ mktestrepo missing-prune
610 $ mktestrepo missing-prune
611 $ mkcommit 'C-A0'
611 $ mkcommit 'C-A0'
612 $ mkcommit 'C-B0'
612 $ mkcommit 'C-B0'
613 $ hg up 'desc("ROOT")'
613 $ hg up 'desc("ROOT")'
614 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
614 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
615 $ mkcommit 'C-A1'
615 $ mkcommit 'C-A1'
616 created new head
616 created new head
617 $ hg debugobsolete a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 `getid 'desc("C-A0")'`
617 $ hg debugobsolete a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 `getid 'desc("C-A0")'`
618 1 new obsolescence markers
618 1 new obsolescence markers
619 $ hg debugobsolete `getid 'desc("C-A0")'` `getid 'desc("C-A1")'`
619 $ hg debugobsolete `getid 'desc("C-A0")'` `getid 'desc("C-A1")'`
620 1 new obsolescence markers
620 1 new obsolescence markers
621 obsoleted 1 changesets
621 obsoleted 1 changesets
622 1 new orphan changesets
622 1 new orphan changesets
623 $ hg debugobsolete --record-parents `getid 'desc("C-B0")'`
623 $ hg debugobsolete --record-parents `getid 'desc("C-B0")'`
624 1 new obsolescence markers
624 1 new obsolescence markers
625 obsoleted 1 changesets
625 obsoleted 1 changesets
626
626
627 (it is annoying to create prune with parent data without the changeset, so we strip it after the fact)
627 (it is annoying to create prune with parent data without the changeset, so we strip it after the fact)
628
628
629 $ hg strip --hidden --rev 'desc("C-A0")::' --no-backup --config devel.strip-obsmarkers=no
629 $ hg strip --hidden --rev 'desc("C-A0")::' --no-backup --config devel.strip-obsmarkers=no
630
630
631 $ hg up 'desc("ROOT")'
631 $ hg up 'desc("ROOT")'
632 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
632 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
633 $ hg log --hidden -G
633 $ hg log --hidden -G
634 o cf2c22470d67: C-A1
634 o cf2c22470d67: C-A1
635 |
635 |
636 @ ea207398892e: ROOT
636 @ ea207398892e: ROOT
637
637
638 $ hg debugobsolete
638 $ hg debugobsolete
639 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
639 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
640 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
640 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
641 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
641 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
642
642
643 Actual testing
643 Actual testing
644 --------------
644 --------------
645
645
646 $ testrevs 'desc("C-A1")'
646 $ testrevs 'desc("C-A1")'
647 ### Matched revisions###
647 ### Matched revisions###
648 cf2c22470d67: C-A1
648 cf2c22470d67: C-A1
649 ### Relevant markers ###
649 ### Relevant markers ###
650 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
650 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
651 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
651 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
652 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
652 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
653 # bundling: 1 changesets found
653 # bundling: 1 changesets found
654 ### Bundled markers ###
654 ### Bundled markers ###
655 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
655 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
656 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
656 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
657 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
657 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
658 ### diff <relevant> <bundled> ###
658 ### diff <relevant> <bundled> ###
659 #################################
659 #################################
660 ### Exclusive markers ###
660 ### Exclusive markers ###
661 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
661 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
662 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
662 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
663 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
663 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
664 # stripping: saved backup bundle to $TESTTMP/missing-prune/.hg/strip-backup/cf2c22470d67-fa0f07b0-backup.hg
664 # stripping: saved backup bundle to $TESTTMP/missing-prune/.hg/strip-backup/cf2c22470d67-fa0f07b0-backup.hg
665 ### Backup markers ###
665 ### Backup markers ###
666 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
666 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
667 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
667 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
668 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
668 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
669 ### diff <relevant> <backed-up> ###
669 ### diff <relevant> <backed-up> ###
670 #################################
670 #################################
671 ### Stripped markers ###
671 ### Stripped markers ###
672 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
672 29f93b1df87baee1824e014080d8adf145f81783 0 {84fcb0dfe17b256ebae52e05572993b9194c018a} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
673 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
673 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
674 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
674 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
675 ### diff <exclusive> <stripped> ###
675 ### diff <exclusive> <stripped> ###
676 #################################
676 #################################
677 # unbundling: adding changesets
677 # unbundling: adding changesets
678 # unbundling: adding manifests
678 # unbundling: adding manifests
679 # unbundling: adding file changes
679 # unbundling: adding file changes
680 # unbundling: added 1 changesets with 1 changes to 1 files
680 # unbundling: added 1 changesets with 1 changes to 1 files
681 # unbundling: 3 new obsolescence markers
681 # unbundling: 3 new obsolescence markers
682 # unbundling: new changesets cf2c22470d67 (1 drafts)
682 # unbundling: new changesets cf2c22470d67 (1 drafts)
683 # unbundling: (run 'hg update' to get a working copy)
683 # unbundling: (run 'hg update' to get a working copy)
684
684
685 chain with precursors also pruned
685 chain with precursors also pruned
686 =================================
686 =================================
687
687
688 . A0 (also pruned)
688 . A0 (also pruned)
689 . ⇠◌⇠◔ A1
689 . ⇠◌⇠◔ A1
690 . |
690 . |
691 . ●
691 . ●
692
692
693 setup
693 setup
694 -----
694 -----
695
695
696 $ mktestrepo prune-inline-missing
696 $ mktestrepo prune-inline-missing
697 $ mkcommit 'C-A0'
697 $ mkcommit 'C-A0'
698 $ hg up 'desc("ROOT")'
698 $ hg up 'desc("ROOT")'
699 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
699 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
700 $ mkcommit 'C-A1'
700 $ mkcommit 'C-A1'
701 created new head
701 created new head
702 $ hg debugobsolete a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 `getid 'desc("C-A0")'`
702 $ hg debugobsolete a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 `getid 'desc("C-A0")'`
703 1 new obsolescence markers
703 1 new obsolescence markers
704 $ hg debugobsolete --record-parents `getid 'desc("C-A0")'`
704 $ hg debugobsolete --record-parents `getid 'desc("C-A0")'`
705 1 new obsolescence markers
705 1 new obsolescence markers
706 obsoleted 1 changesets
706 obsoleted 1 changesets
707 $ hg debugobsolete `getid 'desc("C-A0")'` `getid 'desc("C-A1")'`
707 $ hg debugobsolete `getid 'desc("C-A0")'` `getid 'desc("C-A1")'`
708 1 new obsolescence markers
708 1 new obsolescence markers
709
709
710 (it is annoying to create prune with parent data without the changeset, so we strip it after the fact)
710 (it is annoying to create prune with parent data without the changeset, so we strip it after the fact)
711
711
712 $ hg strip --hidden --rev 'desc("C-A0")::' --no-backup --config devel.strip-obsmarkers=no
712 $ hg strip --hidden --rev 'desc("C-A0")::' --no-backup --config devel.strip-obsmarkers=no
713
713
714 $ hg up 'desc("ROOT")'
714 $ hg up 'desc("ROOT")'
715 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
715 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
716 $ hg log --hidden -G
716 $ hg log --hidden -G
717 o cf2c22470d67: C-A1
717 o cf2c22470d67: C-A1
718 |
718 |
719 @ ea207398892e: ROOT
719 @ ea207398892e: ROOT
720
720
721 $ hg debugobsolete
721 $ hg debugobsolete
722 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
722 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
723 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
723 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
724 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
724 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
725
725
726 Actual testing
726 Actual testing
727 --------------
727 --------------
728
728
729 $ testrevs 'desc("C-A1")'
729 $ testrevs 'desc("C-A1")'
730 ### Matched revisions###
730 ### Matched revisions###
731 cf2c22470d67: C-A1
731 cf2c22470d67: C-A1
732 ### Relevant markers ###
732 ### Relevant markers ###
733 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
733 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
734 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
734 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
735 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
735 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
736 # bundling: 1 changesets found
736 # bundling: 1 changesets found
737 ### Bundled markers ###
737 ### Bundled markers ###
738 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
738 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
739 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
739 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
740 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
740 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
741 ### diff <relevant> <bundled> ###
741 ### diff <relevant> <bundled> ###
742 #################################
742 #################################
743 ### Exclusive markers ###
743 ### Exclusive markers ###
744 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
744 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
745 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
745 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
746 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
746 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
747 # stripping: saved backup bundle to $TESTTMP/prune-inline-missing/.hg/strip-backup/cf2c22470d67-fa0f07b0-backup.hg
747 # stripping: saved backup bundle to $TESTTMP/prune-inline-missing/.hg/strip-backup/cf2c22470d67-fa0f07b0-backup.hg
748 ### Backup markers ###
748 ### Backup markers ###
749 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
749 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
750 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
750 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
751 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
751 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
752 ### diff <relevant> <backed-up> ###
752 ### diff <relevant> <backed-up> ###
753 #################################
753 #################################
754 ### Stripped markers ###
754 ### Stripped markers ###
755 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
755 84fcb0dfe17b256ebae52e05572993b9194c018a 0 {ea207398892eb49e06441f10dda2a731f0450f20} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
756 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
756 84fcb0dfe17b256ebae52e05572993b9194c018a cf2c22470d67233004e934a31184ac2b35389914 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
757 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
757 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 84fcb0dfe17b256ebae52e05572993b9194c018a 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
758 ### diff <exclusive> <stripped> ###
758 ### diff <exclusive> <stripped> ###
759 #################################
759 #################################
760 # unbundling: adding changesets
760 # unbundling: adding changesets
761 # unbundling: adding manifests
761 # unbundling: adding manifests
762 # unbundling: adding file changes
762 # unbundling: adding file changes
763 # unbundling: added 1 changesets with 1 changes to 1 files
763 # unbundling: added 1 changesets with 1 changes to 1 files
764 # unbundling: 3 new obsolescence markers
764 # unbundling: 3 new obsolescence markers
765 # unbundling: new changesets cf2c22470d67 (1 drafts)
765 # unbundling: new changesets cf2c22470d67 (1 drafts)
766 # unbundling: (run 'hg update' to get a working copy)
766 # unbundling: (run 'hg update' to get a working copy)
767
767
768 Chain with fold and split
768 Chain with fold and split
769 =========================
769 =========================
770
770
771 setup
771 setup
772 -----
772 -----
773
773
774 $ mktestrepo split-fold
774 $ mktestrepo split-fold
775 $ mkcommit 'C-A'
775 $ mkcommit 'C-A'
776 $ hg up 'desc("ROOT")'
776 $ hg up 'desc("ROOT")'
777 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
777 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
778 $ mkcommit 'C-B'
778 $ mkcommit 'C-B'
779 created new head
779 created new head
780 $ hg up 'desc("ROOT")'
780 $ hg up 'desc("ROOT")'
781 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
781 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
782 $ mkcommit 'C-C'
782 $ mkcommit 'C-C'
783 created new head
783 created new head
784 $ hg up 'desc("ROOT")'
784 $ hg up 'desc("ROOT")'
785 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
785 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
786 $ mkcommit 'C-D'
786 $ mkcommit 'C-D'
787 created new head
787 created new head
788 $ hg up 'desc("ROOT")'
788 $ hg up 'desc("ROOT")'
789 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
789 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
790 $ mkcommit 'C-E'
790 $ mkcommit 'C-E'
791 created new head
791 created new head
792 $ hg debugobsolete a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 `getid 'desc("C-A")'`
792 $ hg debugobsolete a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 `getid 'desc("C-A")'`
793 1 new obsolescence markers
793 1 new obsolescence markers
794 $ hg debugobsolete `getid 'desc("C-A")'` `getid 'desc("C-B")'` `getid 'desc("C-C")'` # record split
794 $ hg debugobsolete `getid 'desc("C-A")'` `getid 'desc("C-B")'` `getid 'desc("C-C")'` # record split
795 1 new obsolescence markers
795 1 new obsolescence markers
796 obsoleted 1 changesets
796 obsoleted 1 changesets
797 $ hg debugobsolete `getid 'desc("C-A")'` `getid 'desc("C-D")'` # other divergent
797 $ hg debugobsolete `getid 'desc("C-A")'` `getid 'desc("C-D")'` # other divergent
798 1 new obsolescence markers
798 1 new obsolescence markers
799 3 new content-divergent changesets
799 3 new content-divergent changesets
800 $ hg debugobsolete `getid 'desc("C-A")'` b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0
800 $ hg debugobsolete `getid 'desc("C-A")'` b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0
801 1 new obsolescence markers
801 1 new obsolescence markers
802 $ hg debugobsolete b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 `getid 'desc("C-E")'`
802 $ hg debugobsolete b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 `getid 'desc("C-E")'`
803 1 new obsolescence markers
803 1 new obsolescence markers
804 1 new content-divergent changesets
804 1 new content-divergent changesets
805 $ hg debugobsolete `getid 'desc("C-B")'` `getid 'desc("C-E")'`
805 $ hg debugobsolete `getid 'desc("C-B")'` `getid 'desc("C-E")'`
806 1 new obsolescence markers
806 1 new obsolescence markers
807 obsoleted 1 changesets
807 obsoleted 1 changesets
808 $ hg debugobsolete `getid 'desc("C-C")'` `getid 'desc("C-E")'`
808 $ hg debugobsolete `getid 'desc("C-C")'` `getid 'desc("C-E")'`
809 1 new obsolescence markers
809 1 new obsolescence markers
810 obsoleted 1 changesets
810 obsoleted 1 changesets
811 $ hg debugobsolete `getid 'desc("C-D")'` `getid 'desc("C-E")'`
811 $ hg debugobsolete `getid 'desc("C-D")'` `getid 'desc("C-E")'`
812 1 new obsolescence markers
812 1 new obsolescence markers
813 obsoleted 1 changesets
813 obsoleted 1 changesets
814 $ hg debugobsolete c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 `getid 'desc("C-E")'`
814 $ hg debugobsolete c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 `getid 'desc("C-E")'`
815 1 new obsolescence markers
815 1 new obsolescence markers
816
816
817 $ hg up 'desc("ROOT")'
817 $ hg up 'desc("ROOT")'
818 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
818 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
819 $ hg log --hidden -G
819 $ hg log --hidden -G
820 o 2f20ff6509f0: C-E
820 o 2f20ff6509f0: C-E
821 |
821 |
822 | x 06dc9da25ef0: C-D
822 | x 06dc9da25ef0: C-D
823 |/
823 |/
824 | x 27ec657ca21d: C-C
824 | x 27ec657ca21d: C-C
825 |/
825 |/
826 | x a9b9da38ed96: C-B
826 | x a9b9da38ed96: C-B
827 |/
827 |/
828 | x 9ac430e15fca: C-A
828 | x 9ac430e15fca: C-A
829 |/
829 |/
830 @ ea207398892e: ROOT
830 @ ea207398892e: ROOT
831
831
832 $ hg debugobsolete
832 $ hg debugobsolete
833 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
833 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
834 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
834 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
835 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
835 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
836 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
836 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
837 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
837 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
838 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
838 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
839 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
839 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
840 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
840 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
841 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
841 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
842
842
843 Actual testing
843 Actual testing
844 --------------
844 --------------
845
845
846 $ testrevs 'desc("C-A")'
846 $ testrevs 'desc("C-A")'
847 ### Matched revisions###
847 ### Matched revisions###
848 9ac430e15fca: C-A
848 9ac430e15fca: C-A
849 ### Relevant markers ###
849 ### Relevant markers ###
850 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
850 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
851 # bundling: 1 changesets found
851 # bundling: 1 changesets found
852 ### Bundled markers ###
852 ### Bundled markers ###
853 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
853 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
854 ### diff <relevant> <bundled> ###
854 ### diff <relevant> <bundled> ###
855 #################################
855 #################################
856 ### Exclusive markers ###
856 ### Exclusive markers ###
857 # stripping: saved backup bundle to $TESTTMP/split-fold/.hg/strip-backup/9ac430e15fca-81204eba-backup.hg
857 # stripping: saved backup bundle to $TESTTMP/split-fold/.hg/strip-backup/9ac430e15fca-81204eba-backup.hg
858 ### Backup markers ###
858 ### Backup markers ###
859 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
859 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
860 ### diff <relevant> <backed-up> ###
860 ### diff <relevant> <backed-up> ###
861 #################################
861 #################################
862 ### Stripped markers ###
862 ### Stripped markers ###
863 ### diff <exclusive> <stripped> ###
863 ### diff <exclusive> <stripped> ###
864 #################################
864 #################################
865 # unbundling: adding changesets
865 # unbundling: adding changesets
866 # unbundling: adding manifests
866 # unbundling: adding manifests
867 # unbundling: adding file changes
867 # unbundling: adding file changes
868 # unbundling: added 1 changesets with 1 changes to 1 files (+1 heads)
868 # unbundling: added 1 changesets with 1 changes to 1 files (+1 heads)
869 # unbundling: (1 other changesets obsolete on arrival)
869 # unbundling: (1 other changesets obsolete on arrival)
870 # unbundling: (run 'hg heads' to see heads)
870 # unbundling: (run 'hg heads' to see heads)
871
871
872 $ testrevs 'desc("C-B")'
872 $ testrevs 'desc("C-B")'
873 ### Matched revisions###
873 ### Matched revisions###
874 a9b9da38ed96: C-B
874 a9b9da38ed96: C-B
875 ### Relevant markers ###
875 ### Relevant markers ###
876 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
876 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
877 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
877 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
878 # bundling: 1 changesets found
878 # bundling: 1 changesets found
879 ### Bundled markers ###
879 ### Bundled markers ###
880 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
880 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
881 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
881 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
882 ### diff <relevant> <bundled> ###
882 ### diff <relevant> <bundled> ###
883 #################################
883 #################################
884 ### Exclusive markers ###
884 ### Exclusive markers ###
885 # stripping: saved backup bundle to $TESTTMP/split-fold/.hg/strip-backup/a9b9da38ed96-7465d6e9-backup.hg
885 # stripping: saved backup bundle to $TESTTMP/split-fold/.hg/strip-backup/a9b9da38ed96-7465d6e9-backup.hg
886 ### Backup markers ###
886 ### Backup markers ###
887 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
887 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
888 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
888 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
889 ### diff <relevant> <backed-up> ###
889 ### diff <relevant> <backed-up> ###
890 #################################
890 #################################
891 ### Stripped markers ###
891 ### Stripped markers ###
892 ### diff <exclusive> <stripped> ###
892 ### diff <exclusive> <stripped> ###
893 #################################
893 #################################
894 # unbundling: adding changesets
894 # unbundling: adding changesets
895 # unbundling: adding manifests
895 # unbundling: adding manifests
896 # unbundling: adding file changes
896 # unbundling: adding file changes
897 # unbundling: added 1 changesets with 1 changes to 1 files (+1 heads)
897 # unbundling: added 1 changesets with 1 changes to 1 files (+1 heads)
898 # unbundling: (1 other changesets obsolete on arrival)
898 # unbundling: (1 other changesets obsolete on arrival)
899 # unbundling: (run 'hg heads' to see heads)
899 # unbundling: (run 'hg heads' to see heads)
900
900
901 $ testrevs 'desc("C-C")'
901 $ testrevs 'desc("C-C")'
902 ### Matched revisions###
902 ### Matched revisions###
903 27ec657ca21d: C-C
903 27ec657ca21d: C-C
904 ### Relevant markers ###
904 ### Relevant markers ###
905 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
905 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
906 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
906 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
907 # bundling: 1 changesets found
907 # bundling: 1 changesets found
908 ### Bundled markers ###
908 ### Bundled markers ###
909 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
909 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
910 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
910 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
911 ### diff <relevant> <bundled> ###
911 ### diff <relevant> <bundled> ###
912 #################################
912 #################################
913 ### Exclusive markers ###
913 ### Exclusive markers ###
914 # stripping: saved backup bundle to $TESTTMP/split-fold/.hg/strip-backup/27ec657ca21d-d5dd1c7c-backup.hg
914 # stripping: saved backup bundle to $TESTTMP/split-fold/.hg/strip-backup/27ec657ca21d-d5dd1c7c-backup.hg
915 ### Backup markers ###
915 ### Backup markers ###
916 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
916 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
917 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
917 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
918 ### diff <relevant> <backed-up> ###
918 ### diff <relevant> <backed-up> ###
919 #################################
919 #################################
920 ### Stripped markers ###
920 ### Stripped markers ###
921 ### diff <exclusive> <stripped> ###
921 ### diff <exclusive> <stripped> ###
922 #################################
922 #################################
923 # unbundling: adding changesets
923 # unbundling: adding changesets
924 # unbundling: adding manifests
924 # unbundling: adding manifests
925 # unbundling: adding file changes
925 # unbundling: adding file changes
926 # unbundling: added 1 changesets with 1 changes to 1 files (+1 heads)
926 # unbundling: added 1 changesets with 1 changes to 1 files (+1 heads)
927 # unbundling: (1 other changesets obsolete on arrival)
927 # unbundling: (1 other changesets obsolete on arrival)
928 # unbundling: (run 'hg heads' to see heads)
928 # unbundling: (run 'hg heads' to see heads)
929
929
930 $ testrevs 'desc("C-D")'
930 $ testrevs 'desc("C-D")'
931 ### Matched revisions###
931 ### Matched revisions###
932 06dc9da25ef0: C-D
932 06dc9da25ef0: C-D
933 ### Relevant markers ###
933 ### Relevant markers ###
934 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
934 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
935 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
935 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
936 # bundling: 1 changesets found
936 # bundling: 1 changesets found
937 ### Bundled markers ###
937 ### Bundled markers ###
938 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
938 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
939 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
939 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
940 ### diff <relevant> <bundled> ###
940 ### diff <relevant> <bundled> ###
941 #################################
941 #################################
942 ### Exclusive markers ###
942 ### Exclusive markers ###
943 # stripping: saved backup bundle to $TESTTMP/split-fold/.hg/strip-backup/06dc9da25ef0-9b1c0a91-backup.hg
943 # stripping: saved backup bundle to $TESTTMP/split-fold/.hg/strip-backup/06dc9da25ef0-9b1c0a91-backup.hg
944 ### Backup markers ###
944 ### Backup markers ###
945 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
945 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
946 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
946 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
947 ### diff <relevant> <backed-up> ###
947 ### diff <relevant> <backed-up> ###
948 #################################
948 #################################
949 ### Stripped markers ###
949 ### Stripped markers ###
950 ### diff <exclusive> <stripped> ###
950 ### diff <exclusive> <stripped> ###
951 #################################
951 #################################
952 # unbundling: adding changesets
952 # unbundling: adding changesets
953 # unbundling: adding manifests
953 # unbundling: adding manifests
954 # unbundling: adding file changes
954 # unbundling: adding file changes
955 # unbundling: added 1 changesets with 1 changes to 1 files (+1 heads)
955 # unbundling: added 1 changesets with 1 changes to 1 files (+1 heads)
956 # unbundling: (1 other changesets obsolete on arrival)
956 # unbundling: (1 other changesets obsolete on arrival)
957 # unbundling: (run 'hg heads' to see heads)
957 # unbundling: (run 'hg heads' to see heads)
958
958
959 $ testrevs 'desc("C-E")'
959 $ testrevs 'desc("C-E")'
960 ### Matched revisions###
960 ### Matched revisions###
961 2f20ff6509f0: C-E
961 2f20ff6509f0: C-E
962 ### Relevant markers ###
962 ### Relevant markers ###
963 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
963 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
964 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
964 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
965 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
965 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
966 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
966 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
967 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
967 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
968 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
968 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
969 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
969 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
970 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
970 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
971 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
971 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
972 # bundling: 1 changesets found
972 # bundling: 1 changesets found
973 ### Bundled markers ###
973 ### Bundled markers ###
974 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
974 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
975 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
975 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
976 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
976 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
977 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
977 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
978 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
978 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
979 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
979 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
980 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
980 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
981 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
981 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
982 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
982 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
983 ### diff <relevant> <bundled> ###
983 ### diff <relevant> <bundled> ###
984 #################################
984 #################################
985 ### Exclusive markers ###
985 ### Exclusive markers ###
986 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
986 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
987 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
987 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
988 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
988 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
989 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
989 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
990 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
990 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
991 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
991 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
992 # stripping: saved backup bundle to $TESTTMP/split-fold/.hg/strip-backup/2f20ff6509f0-8adeb22d-backup.hg
992 # stripping: saved backup bundle to $TESTTMP/split-fold/.hg/strip-backup/2f20ff6509f0-8adeb22d-backup.hg
993 3 new content-divergent changesets
993 3 new content-divergent changesets
994 ### Backup markers ###
994 ### Backup markers ###
995 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
995 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
996 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
996 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
997 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
997 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
998 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
998 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
999 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
999 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1000 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1000 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1001 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1001 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1002 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1002 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1003 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1003 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1004 ### diff <relevant> <backed-up> ###
1004 ### diff <relevant> <backed-up> ###
1005 #################################
1005 #################################
1006 ### Stripped markers ###
1006 ### Stripped markers ###
1007 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1007 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1008 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1008 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1009 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1009 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1010 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1010 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1011 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1011 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1012 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1012 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1013 ### diff <exclusive> <stripped> ###
1013 ### diff <exclusive> <stripped> ###
1014 #################################
1014 #################################
1015 # unbundling: adding changesets
1015 # unbundling: adding changesets
1016 # unbundling: adding manifests
1016 # unbundling: adding manifests
1017 # unbundling: adding file changes
1017 # unbundling: adding file changes
1018 # unbundling: added 1 changesets with 1 changes to 1 files (+1 heads)
1018 # unbundling: added 1 changesets with 1 changes to 1 files (+1 heads)
1019 # unbundling: 6 new obsolescence markers
1019 # unbundling: 6 new obsolescence markers
1020 # unbundling: obsoleted 3 changesets
1020 # unbundling: obsoleted 3 changesets
1021 # unbundling: new changesets 2f20ff6509f0 (1 drafts)
1021 # unbundling: new changesets 2f20ff6509f0 (1 drafts)
1022 # unbundling: (run 'hg heads' to see heads)
1022 # unbundling: (run 'hg heads' to see heads)
1023
1023
1024 Bundle multiple revisions
1024 Bundle multiple revisions
1025
1025
1026 * each part of the split
1026 * each part of the split
1027
1027
1028 $ testrevs 'desc("C-B") + desc("C-C")'
1028 $ testrevs 'desc("C-B") + desc("C-C")'
1029 ### Matched revisions###
1029 ### Matched revisions###
1030 27ec657ca21d: C-C
1030 27ec657ca21d: C-C
1031 a9b9da38ed96: C-B
1031 a9b9da38ed96: C-B
1032 ### Relevant markers ###
1032 ### Relevant markers ###
1033 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1033 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1034 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1034 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1035 # bundling: 2 changesets found
1035 # bundling: 2 changesets found
1036 ### Bundled markers ###
1036 ### Bundled markers ###
1037 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1037 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1038 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1038 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1039 ### diff <relevant> <bundled> ###
1039 ### diff <relevant> <bundled> ###
1040 #################################
1040 #################################
1041 ### Exclusive markers ###
1041 ### Exclusive markers ###
1042 # stripping: saved backup bundle to $TESTTMP/split-fold/.hg/strip-backup/a9b9da38ed96-0daf625a-backup.hg
1042 # stripping: saved backup bundle to $TESTTMP/split-fold/.hg/strip-backup/a9b9da38ed96-0daf625a-backup.hg
1043 ### Backup markers ###
1043 ### Backup markers ###
1044 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1044 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1045 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1045 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1046 ### diff <relevant> <backed-up> ###
1046 ### diff <relevant> <backed-up> ###
1047 #################################
1047 #################################
1048 ### Stripped markers ###
1048 ### Stripped markers ###
1049 ### diff <exclusive> <stripped> ###
1049 ### diff <exclusive> <stripped> ###
1050 #################################
1050 #################################
1051 # unbundling: adding changesets
1051 # unbundling: adding changesets
1052 # unbundling: adding manifests
1052 # unbundling: adding manifests
1053 # unbundling: adding file changes
1053 # unbundling: adding file changes
1054 # unbundling: added 2 changesets with 2 changes to 2 files (+2 heads)
1054 # unbundling: added 2 changesets with 2 changes to 2 files (+2 heads)
1055 # unbundling: (2 other changesets obsolete on arrival)
1055 # unbundling: (2 other changesets obsolete on arrival)
1056 # unbundling: (run 'hg heads' to see heads)
1056 # unbundling: (run 'hg heads' to see heads)
1057
1057
1058 * top one and other divergent
1058 * top one and other divergent
1059
1059
1060 $ testrevs 'desc("C-E") + desc("C-D")'
1060 $ testrevs 'desc("C-E") + desc("C-D")'
1061 ### Matched revisions###
1061 ### Matched revisions###
1062 06dc9da25ef0: C-D
1062 06dc9da25ef0: C-D
1063 2f20ff6509f0: C-E
1063 2f20ff6509f0: C-E
1064 ### Relevant markers ###
1064 ### Relevant markers ###
1065 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1065 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1066 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1066 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1067 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1067 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1068 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1068 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1069 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1069 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1070 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1070 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1071 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1071 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1072 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1072 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1073 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1073 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1074 # bundling: 2 changesets found
1074 # bundling: 2 changesets found
1075 ### Bundled markers ###
1075 ### Bundled markers ###
1076 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1076 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1077 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1077 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1078 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1078 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1079 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1079 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1080 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1080 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1081 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1081 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1082 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1082 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1083 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1083 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1084 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1084 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1085 ### diff <relevant> <bundled> ###
1085 ### diff <relevant> <bundled> ###
1086 #################################
1086 #################################
1087 ### Exclusive markers ###
1087 ### Exclusive markers ###
1088 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1088 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1089 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1089 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1090 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1090 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1091 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1091 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1092 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1092 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1093 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1093 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1094 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1094 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1095 # stripping: saved backup bundle to $TESTTMP/split-fold/.hg/strip-backup/2f20ff6509f0-bf1b80f4-backup.hg
1095 # stripping: saved backup bundle to $TESTTMP/split-fold/.hg/strip-backup/2f20ff6509f0-bf1b80f4-backup.hg
1096 ### Backup markers ###
1096 ### Backup markers ###
1097 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1097 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1098 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1098 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1099 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1099 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1100 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1100 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1101 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1101 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1102 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1102 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1103 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1103 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1104 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1104 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1105 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1105 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1106 ### diff <relevant> <backed-up> ###
1106 ### diff <relevant> <backed-up> ###
1107 #################################
1107 #################################
1108 ### Stripped markers ###
1108 ### Stripped markers ###
1109 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1109 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1110 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1110 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1111 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1111 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1112 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1112 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1113 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1113 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1114 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1114 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1115 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1115 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1116 ### diff <exclusive> <stripped> ###
1116 ### diff <exclusive> <stripped> ###
1117 #################################
1117 #################################
1118 # unbundling: adding changesets
1118 # unbundling: adding changesets
1119 # unbundling: adding manifests
1119 # unbundling: adding manifests
1120 # unbundling: adding file changes
1120 # unbundling: adding file changes
1121 # unbundling: added 2 changesets with 2 changes to 2 files (+2 heads)
1121 # unbundling: added 2 changesets with 2 changes to 2 files (+2 heads)
1122 # unbundling: 7 new obsolescence markers
1122 # unbundling: 7 new obsolescence markers
1123 # unbundling: obsoleted 2 changesets
1123 # unbundling: obsoleted 2 changesets
1124 # unbundling: new changesets 2f20ff6509f0 (1 drafts)
1124 # unbundling: new changesets 2f20ff6509f0 (1 drafts)
1125 # unbundling: (1 other changesets obsolete on arrival)
1125 # unbundling: (1 other changesets obsolete on arrival)
1126 # unbundling: (run 'hg heads' to see heads)
1126 # unbundling: (run 'hg heads' to see heads)
1127
1127
1128 * top one and initial precursors
1128 * top one and initial precursors
1129
1129
1130 $ testrevs 'desc("C-E") + desc("C-A")'
1130 $ testrevs 'desc("C-E") + desc("C-A")'
1131 ### Matched revisions###
1131 ### Matched revisions###
1132 2f20ff6509f0: C-E
1132 2f20ff6509f0: C-E
1133 9ac430e15fca: C-A
1133 9ac430e15fca: C-A
1134 ### Relevant markers ###
1134 ### Relevant markers ###
1135 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1135 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1136 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1136 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1137 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1137 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1138 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1138 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1139 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1139 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1140 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1140 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1141 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1141 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1142 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1142 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1143 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1143 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1144 # bundling: 2 changesets found
1144 # bundling: 2 changesets found
1145 ### Bundled markers ###
1145 ### Bundled markers ###
1146 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1146 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1147 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1147 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1148 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1148 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1149 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1149 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1150 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1150 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1151 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1151 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1152 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1152 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1153 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1153 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1154 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1154 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1155 ### diff <relevant> <bundled> ###
1155 ### diff <relevant> <bundled> ###
1156 #################################
1156 #################################
1157 ### Exclusive markers ###
1157 ### Exclusive markers ###
1158 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1158 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1159 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1159 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1160 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1160 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1161 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1161 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1162 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1162 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1163 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1163 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1164 # stripping: saved backup bundle to $TESTTMP/split-fold/.hg/strip-backup/9ac430e15fca-36b6476a-backup.hg
1164 # stripping: saved backup bundle to $TESTTMP/split-fold/.hg/strip-backup/9ac430e15fca-36b6476a-backup.hg
1165 3 new content-divergent changesets
1165 3 new content-divergent changesets
1166 ### Backup markers ###
1166 ### Backup markers ###
1167 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1167 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1168 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1168 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1169 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1169 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1170 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1170 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1171 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1171 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1172 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1172 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1173 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1173 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1174 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1174 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1175 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1175 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1176 ### diff <relevant> <backed-up> ###
1176 ### diff <relevant> <backed-up> ###
1177 #################################
1177 #################################
1178 ### Stripped markers ###
1178 ### Stripped markers ###
1179 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1179 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1180 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1180 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1181 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1181 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1182 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1182 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1183 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1183 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1184 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1184 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1185 ### diff <exclusive> <stripped> ###
1185 ### diff <exclusive> <stripped> ###
1186 #################################
1186 #################################
1187 # unbundling: adding changesets
1187 # unbundling: adding changesets
1188 # unbundling: adding manifests
1188 # unbundling: adding manifests
1189 # unbundling: adding file changes
1189 # unbundling: adding file changes
1190 # unbundling: added 2 changesets with 2 changes to 2 files (+2 heads)
1190 # unbundling: added 2 changesets with 2 changes to 2 files (+2 heads)
1191 # unbundling: 6 new obsolescence markers
1191 # unbundling: 6 new obsolescence markers
1192 # unbundling: obsoleted 3 changesets
1192 # unbundling: obsoleted 3 changesets
1193 # unbundling: new changesets 2f20ff6509f0 (1 drafts)
1193 # unbundling: new changesets 2f20ff6509f0 (1 drafts)
1194 # unbundling: (1 other changesets obsolete on arrival)
1194 # unbundling: (1 other changesets obsolete on arrival)
1195 # unbundling: (run 'hg heads' to see heads)
1195 # unbundling: (run 'hg heads' to see heads)
1196
1196
1197 * top one and one of the split
1197 * top one and one of the split
1198
1198
1199 $ testrevs 'desc("C-E") + desc("C-C")'
1199 $ testrevs 'desc("C-E") + desc("C-C")'
1200 ### Matched revisions###
1200 ### Matched revisions###
1201 27ec657ca21d: C-C
1201 27ec657ca21d: C-C
1202 2f20ff6509f0: C-E
1202 2f20ff6509f0: C-E
1203 ### Relevant markers ###
1203 ### Relevant markers ###
1204 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1204 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1205 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1205 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1206 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1206 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1207 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1207 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1208 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1208 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1209 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1209 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1210 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1210 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1211 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1211 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1212 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1212 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1213 # bundling: 2 changesets found
1213 # bundling: 2 changesets found
1214 ### Bundled markers ###
1214 ### Bundled markers ###
1215 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1215 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1216 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1216 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1217 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1217 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1218 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1218 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1219 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1219 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1220 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1220 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1221 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1221 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1222 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1222 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1223 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1223 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1224 ### diff <relevant> <bundled> ###
1224 ### diff <relevant> <bundled> ###
1225 #################################
1225 #################################
1226 ### Exclusive markers ###
1226 ### Exclusive markers ###
1227 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1227 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1228 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1228 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1229 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1229 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1230 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1230 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1231 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1231 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1232 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1232 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1233 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1233 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1234 # stripping: saved backup bundle to $TESTTMP/split-fold/.hg/strip-backup/2f20ff6509f0-5fdfcd7d-backup.hg
1234 # stripping: saved backup bundle to $TESTTMP/split-fold/.hg/strip-backup/2f20ff6509f0-5fdfcd7d-backup.hg
1235 ### Backup markers ###
1235 ### Backup markers ###
1236 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1236 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1237 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1237 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1238 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1238 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1239 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1239 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1240 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1240 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1241 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1241 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1242 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1242 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1243 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1243 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1244 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1244 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1245 ### diff <relevant> <backed-up> ###
1245 ### diff <relevant> <backed-up> ###
1246 #################################
1246 #################################
1247 ### Stripped markers ###
1247 ### Stripped markers ###
1248 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1248 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1249 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1249 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1250 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1250 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1251 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1251 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1252 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1252 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1253 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1253 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1254 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1254 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1255 ### diff <exclusive> <stripped> ###
1255 ### diff <exclusive> <stripped> ###
1256 #################################
1256 #################################
1257 # unbundling: adding changesets
1257 # unbundling: adding changesets
1258 # unbundling: adding manifests
1258 # unbundling: adding manifests
1259 # unbundling: adding file changes
1259 # unbundling: adding file changes
1260 # unbundling: added 2 changesets with 2 changes to 2 files (+2 heads)
1260 # unbundling: added 2 changesets with 2 changes to 2 files (+2 heads)
1261 # unbundling: 7 new obsolescence markers
1261 # unbundling: 7 new obsolescence markers
1262 # unbundling: obsoleted 2 changesets
1262 # unbundling: obsoleted 2 changesets
1263 # unbundling: new changesets 2f20ff6509f0 (1 drafts)
1263 # unbundling: new changesets 2f20ff6509f0 (1 drafts)
1264 # unbundling: (1 other changesets obsolete on arrival)
1264 # unbundling: (1 other changesets obsolete on arrival)
1265 # unbundling: (run 'hg heads' to see heads)
1265 # unbundling: (run 'hg heads' to see heads)
1266
1266
1267 * all
1267 * all
1268
1268
1269 $ testrevs 'desc("C-")'
1269 $ testrevs 'desc("C-")'
1270 ### Matched revisions###
1270 ### Matched revisions###
1271 06dc9da25ef0: C-D
1271 06dc9da25ef0: C-D
1272 27ec657ca21d: C-C
1272 27ec657ca21d: C-C
1273 2f20ff6509f0: C-E
1273 2f20ff6509f0: C-E
1274 9ac430e15fca: C-A
1274 9ac430e15fca: C-A
1275 a9b9da38ed96: C-B
1275 a9b9da38ed96: C-B
1276 ### Relevant markers ###
1276 ### Relevant markers ###
1277 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1277 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1278 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1278 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1279 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1279 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1280 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1280 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1281 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1281 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1282 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1282 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1283 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1283 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1284 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1284 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1285 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1285 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1286 # bundling: 5 changesets found
1286 # bundling: 5 changesets found
1287 ### Bundled markers ###
1287 ### Bundled markers ###
1288 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1288 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1289 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1289 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1290 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1290 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1291 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1291 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1292 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1292 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1293 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1293 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1294 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1294 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1295 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1295 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1296 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1296 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1297 ### diff <relevant> <bundled> ###
1297 ### diff <relevant> <bundled> ###
1298 #################################
1298 #################################
1299 ### Exclusive markers ###
1299 ### Exclusive markers ###
1300 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1300 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1301 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1301 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1302 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1302 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1303 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1303 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1304 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1304 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1305 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1305 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1306 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1306 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1307 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1307 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1308 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1308 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1309 # stripping: saved backup bundle to $TESTTMP/split-fold/.hg/strip-backup/a9b9da38ed96-eeb4258f-backup.hg
1309 # stripping: saved backup bundle to $TESTTMP/split-fold/.hg/strip-backup/a9b9da38ed96-eeb4258f-backup.hg
1310 ### Backup markers ###
1310 ### Backup markers ###
1311 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1311 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1312 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1312 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1313 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1313 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1314 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1314 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1315 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1315 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1316 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1316 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1317 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1317 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1318 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1318 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1319 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1319 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1320 ### diff <relevant> <backed-up> ###
1320 ### diff <relevant> <backed-up> ###
1321 #################################
1321 #################################
1322 ### Stripped markers ###
1322 ### Stripped markers ###
1323 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1323 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1324 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1324 27ec657ca21dd27c36c99fa75586f72ff0d442f1 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1325 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1325 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 06dc9da25ef03e1ff7864dded5fcba42eff2a3f0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1326 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1326 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c a9b9da38ed96f8c6c14f429441f625a344eb4696 27ec657ca21dd27c36c99fa75586f72ff0d442f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1327 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1327 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1328 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1328 a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0a0 9ac430e15fca923b0ba027ca85d4d75c5c9cb73c 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1329 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1329 a9b9da38ed96f8c6c14f429441f625a344eb4696 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1330 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1330 b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1331 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1331 c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0 2f20ff6509f0e013e90c5c8efd996131c918b0ca 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1332 ### diff <exclusive> <stripped> ###
1332 ### diff <exclusive> <stripped> ###
1333 #################################
1333 #################################
1334 # unbundling: adding changesets
1334 # unbundling: adding changesets
1335 # unbundling: adding manifests
1335 # unbundling: adding manifests
1336 # unbundling: adding file changes
1336 # unbundling: adding file changes
1337 # unbundling: added 5 changesets with 5 changes to 5 files (+4 heads)
1337 # unbundling: added 5 changesets with 5 changes to 5 files (+4 heads)
1338 # unbundling: 9 new obsolescence markers
1338 # unbundling: 9 new obsolescence markers
1339 # unbundling: new changesets 2f20ff6509f0 (1 drafts)
1339 # unbundling: new changesets 2f20ff6509f0 (1 drafts)
1340 # unbundling: (4 other changesets obsolete on arrival)
1340 # unbundling: (4 other changesets obsolete on arrival)
1341 # unbundling: (run 'hg heads' to see heads)
1341 # unbundling: (run 'hg heads' to see heads)
1342
1342
1343 changeset pruned on its own
1343 changeset pruned on its own
1344 ===========================
1344 ===========================
1345
1345
1346 . ⊗ B
1346 . ⊗ B
1347 . |
1347 . |
1348 . ◕ A
1348 . ◕ A
1349 . |
1349 . |
1350 . ●
1350 . ●
1351
1351
1352 setup
1352 setup
1353 -----
1353 -----
1354
1354
1355 $ mktestrepo lonely-prune
1355 $ mktestrepo lonely-prune
1356 $ hg up 'desc("ROOT")'
1356 $ hg up 'desc("ROOT")'
1357 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1357 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
1358 $ mkcommit 'C-A'
1358 $ mkcommit 'C-A'
1359 $ mkcommit 'C-B'
1359 $ mkcommit 'C-B'
1360 $ hg debugobsolete --record-parent `getid 'desc("C-B")'`
1360 $ hg debugobsolete --record-parent `getid 'desc("C-B")'`
1361 1 new obsolescence markers
1361 1 new obsolescence markers
1362 obsoleted 1 changesets
1362 obsoleted 1 changesets
1363
1363
1364 $ hg up 'desc("ROOT")'
1364 $ hg up 'desc("ROOT")'
1365 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
1365 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
1366 $ hg log --hidden -G
1366 $ hg log --hidden -G
1367 x cefb651fc2fd: C-B
1367 x cefb651fc2fd: C-B
1368 |
1368 |
1369 o 9ac430e15fca: C-A
1369 o 9ac430e15fca: C-A
1370 |
1370 |
1371 @ ea207398892e: ROOT
1371 @ ea207398892e: ROOT
1372
1372
1373 $ hg debugobsolete
1373 $ hg debugobsolete
1374 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1374 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1375
1375
1376 Actual testing
1376 Actual testing
1377 --------------
1377 --------------
1378 $ testrevs 'desc("C-A")'
1378 $ testrevs 'desc("C-A")'
1379 ### Matched revisions###
1379 ### Matched revisions###
1380 9ac430e15fca: C-A
1380 9ac430e15fca: C-A
1381 ### Relevant markers ###
1381 ### Relevant markers ###
1382 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1382 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1383 # bundling: 1 changesets found
1383 # bundling: 1 changesets found
1384 ### Bundled markers ###
1384 ### Bundled markers ###
1385 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1385 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1386 ### diff <relevant> <bundled> ###
1386 ### diff <relevant> <bundled> ###
1387 #################################
1387 #################################
1388 ### Exclusive markers ###
1388 ### Exclusive markers ###
1389 $ testrevs 'desc("C-B")'
1389 $ testrevs 'desc("C-B")'
1390 ### Matched revisions###
1390 ### Matched revisions###
1391 cefb651fc2fd: C-B
1391 cefb651fc2fd: C-B
1392 ### Relevant markers ###
1392 ### Relevant markers ###
1393 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1393 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1394 # bundling: 1 changesets found
1394 # bundling: 1 changesets found
1395 ### Bundled markers ###
1395 ### Bundled markers ###
1396 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1396 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1397 ### diff <relevant> <bundled> ###
1397 ### diff <relevant> <bundled> ###
1398 #################################
1398 #################################
1399 ### Exclusive markers ###
1399 ### Exclusive markers ###
1400 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1400 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1401 # stripping: saved backup bundle to $TESTTMP/lonely-prune/.hg/strip-backup/cefb651fc2fd-345c8dfa-backup.hg
1401 # stripping: saved backup bundle to $TESTTMP/lonely-prune/.hg/strip-backup/cefb651fc2fd-345c8dfa-backup.hg
1402 ### Backup markers ###
1402 ### Backup markers ###
1403 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1403 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1404 ### diff <relevant> <backed-up> ###
1404 ### diff <relevant> <backed-up> ###
1405 #################################
1405 #################################
1406 ### Stripped markers ###
1406 ### Stripped markers ###
1407 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1407 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1408 ### diff <exclusive> <stripped> ###
1408 ### diff <exclusive> <stripped> ###
1409 #################################
1409 #################################
1410 # unbundling: adding changesets
1410 # unbundling: adding changesets
1411 # unbundling: adding manifests
1411 # unbundling: adding manifests
1412 # unbundling: adding file changes
1412 # unbundling: adding file changes
1413 # unbundling: added 1 changesets with 1 changes to 1 files
1413 # unbundling: added 1 changesets with 1 changes to 1 files
1414 # unbundling: 1 new obsolescence markers
1414 # unbundling: 1 new obsolescence markers
1415 # unbundling: (1 other changesets obsolete on arrival)
1415 # unbundling: (1 other changesets obsolete on arrival)
1416 # unbundling: (run 'hg update' to get a working copy)
1416 # unbundling: (run 'hg update' to get a working copy)
1417 $ testrevs 'desc("C-")'
1417 $ testrevs 'desc("C-")'
1418 ### Matched revisions###
1418 ### Matched revisions###
1419 9ac430e15fca: C-A
1419 9ac430e15fca: C-A
1420 cefb651fc2fd: C-B
1420 cefb651fc2fd: C-B
1421 ### Relevant markers ###
1421 ### Relevant markers ###
1422 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1422 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1423 # bundling: 2 changesets found
1423 # bundling: 2 changesets found
1424 ### Bundled markers ###
1424 ### Bundled markers ###
1425 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1425 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1426 ### diff <relevant> <bundled> ###
1426 ### diff <relevant> <bundled> ###
1427 #################################
1427 #################################
1428 ### Exclusive markers ###
1428 ### Exclusive markers ###
1429 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1429 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1430 # stripping: saved backup bundle to $TESTTMP/lonely-prune/.hg/strip-backup/9ac430e15fca-b9855b02-backup.hg
1430 # stripping: saved backup bundle to $TESTTMP/lonely-prune/.hg/strip-backup/9ac430e15fca-b9855b02-backup.hg
1431 ### Backup markers ###
1431 ### Backup markers ###
1432 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1432 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1433 ### diff <relevant> <backed-up> ###
1433 ### diff <relevant> <backed-up> ###
1434 #################################
1434 #################################
1435 ### Stripped markers ###
1435 ### Stripped markers ###
1436 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1436 cefb651fc2fdc7bb75e588781de5e432c134e8a5 0 {9ac430e15fca923b0ba027ca85d4d75c5c9cb73c} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
1437 ### diff <exclusive> <stripped> ###
1437 ### diff <exclusive> <stripped> ###
1438 #################################
1438 #################################
1439 # unbundling: adding changesets
1439 # unbundling: adding changesets
1440 # unbundling: adding manifests
1440 # unbundling: adding manifests
1441 # unbundling: adding file changes
1441 # unbundling: adding file changes
1442 # unbundling: added 2 changesets with 2 changes to 2 files
1442 # unbundling: added 2 changesets with 2 changes to 2 files
1443 # unbundling: 1 new obsolescence markers
1443 # unbundling: 1 new obsolescence markers
1444 # unbundling: new changesets 9ac430e15fca (1 drafts)
1444 # unbundling: new changesets 9ac430e15fca (1 drafts)
1445 # unbundling: (1 other changesets obsolete on arrival)
1445 # unbundling: (1 other changesets obsolete on arrival)
1446 # unbundling: (run 'hg update' to get a working copy)
1446 # unbundling: (run 'hg update' to get a working copy)
1447
1448 Test that advisory obsolescence markers in bundles are ignored if unsupported
1449
1450 $ hg init repo-with-obs
1451 $ cd repo-with-obs
1452 $ hg debugbuilddag +1
1453 $ hg debugobsolete `getid 0`
1454 1 new obsolescence markers
1455 obsoleted 1 changesets
1456 $ hg bundle --config experimental.evolution.bundle-obsmarker=true --config experimental.evolution.bundle-obsmarker:mandatory=false --all --hidden bundle-with-obs
1457 1 changesets found
1458 $ cd ..
1459 $ hg init repo-without-obs
1460 $ cd repo-without-obs
1461 $ hg --config experimental.evolution=False unbundle ../repo-with-obs/bundle-with-obs --debug
1462 bundle2-input-bundle: 1 params with-transaction
1463 bundle2-input-part: "changegroup" (params: 1 mandatory 1 advisory) supported
1464 adding changesets
1465 add changeset 1ea73414a91b
1466 adding manifests
1467 adding file changes
1468 bundle2-input-part: total payload size 190
1469 bundle2-input-part: "cache:rev-branch-cache" (advisory) supported
1470 bundle2-input-part: total payload size 39
1471 bundle2-input-part: "obsmarkers" (advisory) supported
1472 bundle2-input-part: total payload size 50
1473 ignoring obsolescence markers, feature not enabled
1474 bundle2-input-bundle: 3 parts total
1475 updating the branch cache
1476 added 1 changesets with 0 changes to 0 files
1477 new changesets 1ea73414a91b (1 drafts)
1478 (run 'hg update' to get a working copy)
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
1 NO CONTENT: modified file
NO CONTENT: modified file
The requested commit or file is too big and content was truncated. Show full diff
General Comments 0
You need to be logged in to leave comments. Login now