--- a/.hgsigs Thu Jun 16 15:20:48 2022 +0200
+++ b/.hgsigs Mon Jul 11 09:54:40 2022 +0200
@@ -229,3 +229,5 @@
0ddd5e1f5f67438af85d12e4ce6c39021dde9916 0 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
--- a/.hgtags Thu Jun 16 15:20:48 2022 +0200
+++ b/.hgtags Mon Jul 11 09:54:40 2022 +0200
@@ -242,3 +242,5 @@
0ddd5e1f5f67438af85d12e4ce6c39021dde9916 6.1.2
6b10151b962108f65bfa12b3918b1021ca334f73 6.1.3
0cc5f74ff7f0f4ac2427096bddbe102dbc2453ae 6.1.4
+288de6f5d724bba7bf1669e2838f196962bb7528 6.2rc0
+094a5fa3cf52f936e0de3f1e507c818bee5ece6b 6.2
--- a/contrib/import-checker.py Thu Jun 16 15:20:48 2022 +0200
+++ b/contrib/import-checker.py Mon Jul 11 09:54:40 2022 +0200
@@ -47,6 +47,7 @@
'mercurial.thirdparty.zope',
'mercurial.thirdparty.zope.interface',
'typing',
+ 'xml.etree.ElementTree',
)
# Allow list of symbols that can be directly imported.
--- a/hgext/convert/darcs.py Thu Jun 16 15:20:48 2022 +0200
+++ b/hgext/convert/darcs.py Mon Jul 11 09:54:40 2022 +0200
@@ -8,6 +8,10 @@
import os
import re
import shutil
+from xml.etree.ElementTree import (
+ ElementTree,
+ XMLParser,
+)
from mercurial.i18n import _
from mercurial import (
@@ -20,26 +24,6 @@
NoRepo = common.NoRepo
-# The naming drift of ElementTree is fun!
-
-try:
- import xml.etree.cElementTree.ElementTree as ElementTree
- import xml.etree.cElementTree.XMLParser as XMLParser
-except ImportError:
- try:
- import xml.etree.ElementTree.ElementTree as ElementTree
- import xml.etree.ElementTree.XMLParser as XMLParser
- except ImportError:
- try:
- import elementtree.cElementTree.ElementTree as ElementTree
- import elementtree.cElementTree.XMLParser as XMLParser
- except ImportError:
- try:
- import elementtree.ElementTree.ElementTree as ElementTree
- import elementtree.ElementTree.XMLParser as XMLParser
- except ImportError:
- pass
-
class darcs_source(common.converter_source, common.commandline):
def __init__(self, ui, repotype, path, revs=None):
@@ -58,7 +42,7 @@
_(b'darcs version 2.1 or newer needed (found %r)') % version
)
- if b"ElementTree" not in globals():
+ if "ElementTree" not in globals():
raise error.Abort(_(b"Python ElementTree module is not available"))
self.path = os.path.realpath(path)
@@ -94,9 +78,9 @@
)
tagname = None
child = None
- for elt in tree.findall(b'patch'):
- node = elt.get(b'hash')
- name = elt.findtext(b'name', b'')
+ for elt in tree.findall('patch'):
+ node = self.recode(elt.get('hash'))
+ name = self.recode(elt.findtext('name', ''))
if name.startswith(b'TAG '):
tagname = name[4:].strip()
elif tagname is not None:
@@ -126,7 +110,7 @@
# While we are decoding the XML as latin-1 to be as liberal as
# possible, etree will still raise an exception if any
# non-printable characters are in the XML changelog.
- parser = XMLParser(encoding=b'latin-1')
+ parser = XMLParser(encoding='latin-1')
p = self._run(cmd, **kwargs)
etree.parse(p.stdout, parser=parser)
p.wait()
@@ -136,7 +120,7 @@
def format(self):
output, status = self.run(b'show', b'repo', repodir=self.path)
self.checkexit(status)
- m = re.search(r'^\s*Format:\s*(.*)$', output, re.MULTILINE)
+ m = re.search(br'^\s*Format:\s*(.*)$', output, re.MULTILINE)
if not m:
return None
return b','.join(sorted(f.strip() for f in m.group(1).split(b',')))
@@ -159,13 +143,13 @@
def getcommit(self, rev):
elt = self.changes[rev]
dateformat = b'%a %b %d %H:%M:%S %Z %Y'
- date = dateutil.strdate(elt.get(b'local_date'), dateformat)
- desc = elt.findtext(b'name') + b'\n' + elt.findtext(b'comment', b'')
+ date = dateutil.strdate(elt.get('local_date'), dateformat)
+ desc = elt.findtext('name') + '\n' + elt.findtext('comment', '')
# etree can return unicode objects for name, comment, and author,
# so recode() is used to ensure str objects are emitted.
newdateformat = b'%Y-%m-%d %H:%M:%S %1%2'
return common.commit(
- author=self.recode(elt.get(b'author')),
+ author=self.recode(elt.get('author')),
date=dateutil.datestr(date, newdateformat),
desc=self.recode(desc).strip(),
parents=self.parents[rev],
@@ -176,7 +160,7 @@
b'pull',
self.path,
all=True,
- match=b'hash %s' % rev,
+ match=b'hash %s' % self.recode(rev),
no_test=True,
no_posthook=True,
external_merge=b'/bin/false',
@@ -194,13 +178,14 @@
copies = {}
changes = []
man = None
- for elt in self.changes[rev].find(b'summary').getchildren():
- if elt.tag in (b'add_directory', b'remove_directory'):
+ for elt in self.changes[rev].find('summary'):
+ if elt.tag in ('add_directory', 'remove_directory'):
continue
- if elt.tag == b'move':
+ if elt.tag == 'move':
if man is None:
man = self.manifest()
- source, dest = elt.get(b'from'), elt.get(b'to')
+ source = self.recode(elt.get('from'))
+ dest = self.recode(elt.get('to'))
if source in man:
# File move
changes.append((source, rev))
@@ -217,7 +202,7 @@
changes.append((fdest, rev))
copies[fdest] = f
else:
- changes.append((elt.text.strip(), rev))
+ changes.append((self.recode(elt.text.strip()), rev))
self.pull(rev)
self.lastrev = rev
return sorted(changes), copies, set()
--- a/mercurial/upgrade_utils/actions.py Thu Jun 16 15:20:48 2022 +0200
+++ b/mercurial/upgrade_utils/actions.py Mon Jul 11 09:54:40 2022 +0200
@@ -683,7 +683,11 @@
newactions.append(d)
- newactions.extend(o for o in sorted(optimizations) if o not in newactions)
+ newactions.extend(
+ o
+ for o in sorted(optimizations, key=(lambda x: x.name))
+ if o not in newactions
+ )
# FUTURE consider adding some optimizations here for certain transitions.
# e.g. adding generaldelta could schedule parent redeltas.
--- a/mercurial/utils/procutil.py Thu Jun 16 15:20:48 2022 +0200
+++ b/mercurial/utils/procutil.py Mon Jul 11 09:54:40 2022 +0200
@@ -80,12 +80,32 @@
def make_line_buffered(stream):
- if not isinstance(stream, io.BufferedIOBase):
- # On Python 3, buffered streams can be expected to subclass
- # BufferedIOBase. This is definitively the case for the streams
- # initialized by the interpreter. For unbuffered streams, we don't need
- # to emulate line buffering.
+ # First, check if we need to wrap the stream.
+ check_stream = stream
+ while True:
+ if isinstance(check_stream, WriteAllWrapper):
+ check_stream = check_stream.orig
+ elif pycompat.iswindows and isinstance(
+ check_stream,
+ # pytype: disable=module-attr
+ platform.winstdout
+ # pytype: enable=module-attr
+ ):
+ check_stream = check_stream.fp
+ else:
+ break
+ if isinstance(check_stream, io.RawIOBase):
+ # The stream is unbuffered, we don't need to emulate line buffering.
return stream
+ elif isinstance(check_stream, io.BufferedIOBase):
+ # The stream supports some kind of buffering. We can't assume that
+ # lines are flushed. Fall back to wrapping the stream.
+ pass
+ else:
+ raise NotImplementedError(
+ "can't determine whether stream is buffered or not"
+ )
+
if isinstance(stream, LineBufferedWrapper):
return stream
return LineBufferedWrapper(stream)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/relnotes/6.2 Mon Jul 11 09:54:40 2022 +0200
@@ -0,0 +1,69 @@
+= Mercurial 6.2rc0 =
+
+'''This is the first release to support Python 3.6+ ''only'''''
+
+== New Features ==
+ * Introduce a way to auto-upgrade a repo for certain requirements (see `hg help config.format`)
+ * filemerge: add support for partial conflict resolution by external tool
+ * contrib: add a partial-merge tool for sorted lists (such as Python imports)
+ * revlog: reorder p1 and p2 when p1 is null and p2 is not while respecting issue6528
+ * rhg: add support for ignoring all extensions
+ * completion: install completers to conventional locations
+ * revert: ask user to confirm before tracking new file when interactive
+ * Rust implementation now uses the new dirstate API
+ * sslutil: be less strict about which ciphers are allowed when using --insecure
+ * sslutil: support TLSV1_ALERT_PROTOCOL_VERSION reason code
+ * absorb: make `--edit-lines` imply `--apply-changes`
+ * diff: add help text to highlight the ability to do merge diffs
+ * censor: make rhg fall back to python when encountering a censored node
+ * clone: use better names for temp files
+ * debuglock: make the command more useful in non-interactive mode
+ * debugdeltachain: distinct between snapshot and other diffs
+ * debugindex: rename to debugindex debug-revlog-index
+ * Make debug-revlog-index give out more information
+ * sparse: use the rust code even when sparse is present
+
+== Bug Fixes ==
+ * Python 3 bugfixes
+ * Windows bugfixes
+ * templates: make `firstline` filter not keep '\v', '\f' and similar
+ * rhg: sort unsupported extensions in error message
+ * Improve performance of all functions that extract the first line of a text
+ * crecord: avoid duplicating lines when reverting noeol->eol change
+ * Some config.path options are now discoverable via config
+ * mail: don't complain about a multi-word email.method
+ * bundlespec: do not overwrite bundlespec value with the config one
+ * bundlespec: do not check for `-` in the params portion of the bundlespec
+ * bundlespec: handle the presence of obsmarker part
+ * sparse: start moving away from the global variable for detection of usage
+ * rust-changelog: don't skip empty lines when iterating over changeset lines
+ * narrow: support debugupgraderepo
+ * bundle: quick fix to ludicrous performance penalty
+ * followlines: don't put Unicode directly into the .js file (issue6559)
+ * manifest: improve error message in case for tree manifest
+ * revlog: use %d to format int instead of %lu (issue6565)
+ * revlog: use appropriate format char for int ("i" instead of I")
+ * worker: stop relying on garbage collection to release memoryview
+ * worker: implement _blockingreader.readinto() (issue6444)
+ * worker: avoid potential partial write of pickled data
+
+== Backwards Compatibility Changes ==
+ * '''Removed Python 2 support''': this includes a lot of cleanup in our codebase, automation, testing, etc.
+ * debugindex: rename to debugindex debug-revlog-index
+
+== Miscellaneous ==
+
+ * Fix typos and add missing items from documentation
+ * dirstate-tree: optimize HashMap lookups with raw_entry_mut
+ * Rust dependencies have been upgraded
+ * revlog: rank computation is done by Rust when available
+ * Improve discovery test tooling
+ * Audit the number of queries done in discovery
+ * Improved .hgignore of the mercurial-devel repository itself
+ * Improve test coverage of dirstate-v2
+ * rust-requirements: allow loading repos with `bookmarksinstore` requirement
+ * Various Rust refactorings to help with revlog management
+ * Improve debugability of Rust structs
+ * Improve unit testing of the Rust dirstatemap
+ * Improve robustness of the Rust dirstatemap to corruption
+ * Improve changelog-v2 upgrade system
--- a/rust/hg-core/src/dirstate/entry.rs Thu Jun 16 15:20:48 2022 +0200
+++ b/rust/hg-core/src/dirstate/entry.rs Mon Jul 11 09:54:40 2022 +0200
@@ -83,7 +83,7 @@
second_ambiguous,
})
} else {
- Err(DirstateV2ParseError)
+ Err(DirstateV2ParseError::new("when reading datetime"))
}
}
--- a/rust/hg-core/src/dirstate_tree/dirstate_map.rs Thu Jun 16 15:20:48 2022 +0200
+++ b/rust/hg-core/src/dirstate_tree/dirstate_map.rs Mon Jul 11 09:54:40 2022 +0200
@@ -463,7 +463,7 @@
if let Some(data) = on_disk.get(..data_size) {
Ok(on_disk::read(data, metadata)?)
} else {
- Err(DirstateV2ParseError.into())
+ Err(DirstateV2ParseError::new("not enough bytes on disk").into())
}
}
--- a/rust/hg-core/src/dirstate_tree/on_disk.rs Thu Jun 16 15:20:48 2022 +0200
+++ b/rust/hg-core/src/dirstate_tree/on_disk.rs Mon Jul 11 09:54:40 2022 +0200
@@ -175,11 +175,21 @@
///
/// This should only happen if Mercurial is buggy or a repository is corrupted.
#[derive(Debug)]
-pub struct DirstateV2ParseError;
+pub struct DirstateV2ParseError {
+ message: String,
+}
+
+impl DirstateV2ParseError {
+ pub fn new<S: Into<String>>(message: S) -> Self {
+ Self {
+ message: message.into(),
+ }
+ }
+}
impl From<DirstateV2ParseError> for HgError {
- fn from(_: DirstateV2ParseError) -> Self {
- HgError::corrupted("dirstate-v2 parse error")
+ fn from(e: DirstateV2ParseError) -> Self {
+ HgError::corrupted(format!("dirstate-v2 parse error: {}", e.message))
}
}
@@ -262,13 +272,16 @@
pub fn read_docket(
on_disk: &[u8],
) -> Result<Docket<'_>, DirstateV2ParseError> {
- let (header, uuid) =
- DocketHeader::from_bytes(on_disk).map_err(|_| DirstateV2ParseError)?;
+ let (header, uuid) = DocketHeader::from_bytes(on_disk).map_err(|e| {
+ DirstateV2ParseError::new(format!("when reading docket, {}", e))
+ })?;
let uuid_size = header.uuid_size as usize;
if header.marker == *V2_FORMAT_MARKER && uuid.len() == uuid_size {
Ok(Docket { header, uuid })
} else {
- Err(DirstateV2ParseError)
+ Err(DirstateV2ParseError::new(
+ "invalid format marker or uuid size",
+ ))
}
}
@@ -281,14 +294,17 @@
map.dirstate_version = DirstateVersion::V2;
return Ok(map);
}
- let (meta, _) = TreeMetadata::from_bytes(metadata)
- .map_err(|_| DirstateV2ParseError)?;
+ let (meta, _) = TreeMetadata::from_bytes(metadata).map_err(|e| {
+ DirstateV2ParseError::new(format!("when parsing tree metadata, {}", e))
+ })?;
let dirstate_map = DirstateMap {
on_disk,
- root: dirstate_map::ChildNodes::OnDisk(read_nodes(
- on_disk,
- meta.root_nodes,
- )?),
+ root: dirstate_map::ChildNodes::OnDisk(
+ read_nodes(on_disk, meta.root_nodes).map_err(|mut e| {
+ e.message = format!("{}, when reading root notes", e.message);
+ e
+ })?,
+ ),
nodes_with_entry_count: meta.nodes_with_entry_count.get(),
nodes_with_copy_source_count: meta.nodes_with_copy_source_count.get(),
ignore_patterns_hash: meta.ignore_patterns_hash,
@@ -317,7 +333,7 @@
.expect("dirstate-v2 base_name_start out of bounds");
Ok(start)
} else {
- Err(DirstateV2ParseError)
+ Err(DirstateV2ParseError::new("not enough bytes for base name"))
}
}
@@ -571,11 +587,19 @@
// `&[u8]` cannot occupy the entire addess space.
let start = start.get().try_into().unwrap_or(std::usize::MAX);
let len = len.try_into().unwrap_or(std::usize::MAX);
- on_disk
- .get(start..)
- .and_then(|bytes| T::slice_from_bytes(bytes, len).ok())
+ let bytes = match on_disk.get(start..) {
+ Some(bytes) => bytes,
+ None => {
+ return Err(DirstateV2ParseError::new(
+ "not enough bytes from disk",
+ ))
+ }
+ };
+ T::slice_from_bytes(bytes, len)
+ .map_err(|e| {
+ DirstateV2ParseError::new(format!("when reading a slice, {}", e))
+ })
.map(|(slice, _rest)| slice)
- .ok_or_else(|| DirstateV2ParseError)
}
pub(crate) fn for_each_tracked_path<'on_disk>(
@@ -583,8 +607,9 @@
metadata: &[u8],
mut f: impl FnMut(&'on_disk HgPath),
) -> Result<(), DirstateV2ParseError> {
- let (meta, _) = TreeMetadata::from_bytes(metadata)
- .map_err(|_| DirstateV2ParseError)?;
+ let (meta, _) = TreeMetadata::from_bytes(metadata).map_err(|e| {
+ DirstateV2ParseError::new(format!("when parsing tree metadata, {}", e))
+ })?;
fn recur<'on_disk>(
on_disk: &'on_disk [u8],
nodes: ChildNodes,
--- a/rust/hg-core/src/revlog/revlog.rs Thu Jun 16 15:20:48 2022 +0200
+++ b/rust/hg-core/src/revlog/revlog.rs Mon Jul 11 09:54:40 2022 +0200
@@ -5,7 +5,6 @@
use std::path::Path;
use flate2::read::ZlibDecoder;
-use micro_timer::timed;
use sha1::{Digest, Sha1};
use zstd;
@@ -49,18 +48,20 @@
fn from(error: NodeMapError) -> Self {
match error {
NodeMapError::MultipleResults => RevlogError::AmbiguousPrefix,
- NodeMapError::RevisionNotInIndex(_) => RevlogError::corrupted(),
+ NodeMapError::RevisionNotInIndex(rev) => RevlogError::corrupted(
+ format!("nodemap point to revision {} not in index", rev),
+ ),
}
}
}
-fn corrupted() -> HgError {
- HgError::corrupted("corrupted revlog")
+fn corrupted<S: AsRef<str>>(context: S) -> HgError {
+ HgError::corrupted(format!("corrupted revlog, {}", context.as_ref()))
}
impl RevlogError {
- fn corrupted() -> Self {
- RevlogError::Other(corrupted())
+ fn corrupted<S: AsRef<str>>(context: S) -> Self {
+ RevlogError::Other(corrupted(context))
}
}
@@ -81,7 +82,6 @@
///
/// It will also open the associated data file if index and data are not
/// interleaved.
- #[timed]
pub fn open(
store_vfs: &Vfs,
index_path: impl AsRef<Path>,
@@ -155,7 +155,6 @@
/// Return the revision number for the given node ID, if it exists in this
/// revlog
- #[timed]
pub fn rev_from_node(
&self,
node: NodePrefix,
@@ -205,7 +204,6 @@
/// All entries required to build the final data out of deltas will be
/// retrieved as needed, and the deltas will be applied to the inital
/// snapshot to rebuild the final data.
- #[timed]
pub fn get_rev_data(
&self,
rev: Revision,
@@ -240,7 +238,6 @@
/// Build the full data of a revision out its snapshot
/// and its deltas.
- #[timed]
fn build_data_from_deltas(
snapshot: RevlogEntry,
deltas: &[RevlogEntry],
@@ -329,7 +326,8 @@
&self,
rev: Revision,
) -> Result<RevlogEntry, HgError> {
- return self.get_entry(rev).map_err(|_| corrupted());
+ self.get_entry(rev)
+ .map_err(|_| corrupted(format!("revision {} out of range", rev)))
}
}
@@ -449,7 +447,10 @@
) {
Ok(data)
} else {
- Err(corrupted())
+ Err(corrupted(format!(
+ "hash check failed for revision {}",
+ self.rev
+ )))
}
}
@@ -478,7 +479,10 @@
// zstd data.
b'\x28' => Ok(Cow::Owned(self.uncompressed_zstd_data()?)),
// A proper new format should have had a repo/store requirement.
- _format_type => Err(corrupted()),
+ format_type => Err(corrupted(format!(
+ "unknown compression header '{}'",
+ format_type
+ ))),
}
}
@@ -486,12 +490,16 @@
let mut decoder = ZlibDecoder::new(self.bytes);
if self.is_delta() {
let mut buf = Vec::with_capacity(self.compressed_len as usize);
- decoder.read_to_end(&mut buf).map_err(|_| corrupted())?;
+ decoder
+ .read_to_end(&mut buf)
+ .map_err(|e| corrupted(e.to_string()))?;
Ok(buf)
} else {
let cap = self.uncompressed_len.max(0) as usize;
let mut buf = vec![0; cap];
- decoder.read_exact(&mut buf).map_err(|_| corrupted())?;
+ decoder
+ .read_exact(&mut buf)
+ .map_err(|e| corrupted(e.to_string()))?;
Ok(buf)
}
}
@@ -500,15 +508,15 @@
if self.is_delta() {
let mut buf = Vec::with_capacity(self.compressed_len as usize);
zstd::stream::copy_decode(self.bytes, &mut buf)
- .map_err(|_| corrupted())?;
+ .map_err(|e| corrupted(e.to_string()))?;
Ok(buf)
} else {
let cap = self.uncompressed_len.max(0) as usize;
let mut buf = vec![0; cap];
let len = zstd::block::decompress_to_buffer(self.bytes, &mut buf)
- .map_err(|_| corrupted())?;
+ .map_err(|e| corrupted(e.to_string()))?;
if len != self.uncompressed_len as usize {
- Err(corrupted())
+ Err(corrupted("uncompressed length does not match"))
} else {
Ok(buf)
}
--- a/rust/hg-cpython/src/revlog.rs Thu Jun 16 15:20:48 2022 +0200
+++ b/rust/hg-cpython/src/revlog.rs Mon Jul 11 09:54:40 2022 +0200
@@ -107,7 +107,10 @@
String::from_utf8_lossy(node.data(py)).to_string()
};
- let prefix = NodePrefix::from_hex(&node_as_string).map_err(|_| PyErr::new::<ValueError, _>(py, "Invalid node or prefix"))?;
+ let prefix = NodePrefix::from_hex(&node_as_string)
+ .map_err(|_| PyErr::new::<ValueError, _>(
+ py, format!("Invalid node or prefix '{}'", node_as_string))
+ )?;
nt.find_bin(idx, prefix)
// TODO make an inner API returning the node directly
--- a/rust/rhg/src/commands/cat.rs Thu Jun 16 15:20:48 2022 +0200
+++ b/rust/rhg/src/commands/cat.rs Mon Jul 11 09:54:40 2022 +0200
@@ -67,10 +67,19 @@
let message = "`..` or `.` path segment";
return Err(CommandError::unsupported(message));
}
+ let relative_path = working_directory
+ .strip_prefix(&cwd)
+ .unwrap_or(&working_directory);
let stripped = normalized
.strip_prefix(&working_directory)
- // TODO: error message for path arguments outside of the repo
- .map_err(|_| CommandError::abort(""))?;
+ .map_err(|_| {
+ CommandError::abort(format!(
+ "abort: {} not under root '{}'\n(consider using '--cwd {}')",
+ file,
+ working_directory.display(),
+ relative_path.display(),
+ ))
+ })?;
let hg_file = HgPathBuf::try_from(stripped.to_path_buf())
.map_err(|e| CommandError::abort(e.to_string()))?;
files.push(hg_file);
--- a/rust/rhg/src/commands/status.rs Thu Jun 16 15:20:48 2022 +0200
+++ b/rust/rhg/src/commands/status.rs Mon Jul 11 09:54:40 2022 +0200
@@ -517,10 +517,13 @@
}
let filelog = repo.filelog(hg_path)?;
let fs_len = fs_metadata.len();
- let filelog_entry =
- filelog.entry_for_node(entry.node_id()?).map_err(|_| {
- HgError::corrupted("filelog missing node from manifest")
- })?;
+ let file_node = entry.node_id()?;
+ let filelog_entry = filelog.entry_for_node(file_node).map_err(|_| {
+ HgError::corrupted(format!(
+ "filelog missing node {:?} from manifest",
+ file_node
+ ))
+ })?;
if filelog_entry.file_data_len_not_equal_to(fs_len) {
// No need to read file contents:
// it cannot be equal if it has a different length.
--- a/tests/test-upgrade-repo.t Thu Jun 16 15:20:48 2022 +0200
+++ b/tests/test-upgrade-repo.t Mon Jul 11 09:54:40 2022 +0200
@@ -467,6 +467,7 @@
re-delta-fulladd
every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
+
$ hg debugupgrade --optimize re-delta-parent --quiet
requirements
preserved: dotencode, fncache, generaldelta, revlogv1, share-safe, sparserevlog, store (no-rust !)
@@ -480,6 +481,20 @@
- manifest
+passing multiple optimization:
+
+ $ hg debugupgrade --optimize re-delta-parent --optimize re-delta-multibase --quiet
+ requirements
+ preserved: * (glob)
+
+ optimisations: re-delta-multibase, re-delta-parent
+
+ processed revlogs:
+ - all-filelogs
+ - changelog
+ - manifest
+
+
unknown optimization:
$ hg debugupgrade --optimize foobar