Mon, 27 Jan 2020 20:28:47 +0100 rust-node: avoid meaningless read at the end of odd prefix
Georges Racinet <georges.racinet@octobus.net> [Mon, 27 Jan 2020 20:28:47 +0100] rev 44187
rust-node: avoid meaningless read at the end of odd prefix This should be heavily factored out by the CPU branch predictor anyway. Differential Revision: https://phab.mercurial-scm.org/D8019
Fri, 27 Dec 2019 16:06:54 +0100 rust-nodemap: generic NodeTreeVisitor
Georges Racinet <georges.racinet@octobus.net> [Fri, 27 Dec 2019 16:06:54 +0100] rev 44186
rust-nodemap: generic NodeTreeVisitor This iterator will help avoid code duplication when we'll implement `insert()`, in which we will need to traverse the node tree, and to remember the visited blocks. The structured iterator item will allow different usages from `lookup()` and the upcoming `insert()`. Differential Revision: https://phab.mercurial-scm.org/D7794
Fri, 27 Dec 2019 15:11:43 +0100 rust-nodemap: mutable NodeTree data structure
Georges Racinet <georges.racinet@octobus.net> [Fri, 27 Dec 2019 15:11:43 +0100] rev 44185
rust-nodemap: mutable NodeTree data structure Thanks to the previously indexing abstraction, the only difference in the lookup algorithm is that we don't need the special case for an empty NodeTree any more. We've considered making the mutable root an `Option<Block>`, but that leads to unpleasant checks and `unwrap()` unless we abstract it as typestate patterns (`NodeTree<Immutable>` and `NodeTree<Mutated>`) which seem exaggerated in that case. The initial copy of the root block is a very minor performance penalty, given that it typically occurs just once per transaction. Differential Revision: https://phab.mercurial-scm.org/D7793
Thu, 26 Dec 2019 15:47:14 +0100 rust-nodemap: abstracting the indexing
Georges Racinet <georges.racinet@octobus.net> [Thu, 26 Dec 2019 15:47:14 +0100] rev 44184
rust-nodemap: abstracting the indexing In the forthcoming mutable implementation, we'll have to visit node trees that are more complex than a single slice, although the algorithm will still be expressed in simple indexing terms. We still refrain using `#[inline]` indications as being premature optimizations, but we strongly hope the compiler will indeed inline most of the glue. Differential Revision: https://phab.mercurial-scm.org/D7792
Thu, 23 Jan 2020 17:18:13 +0100 rust-nodemap: NodeMap trait with simplest implementation
Georges Racinet <georges.racinet@octobus.net> [Thu, 23 Jan 2020 17:18:13 +0100] rev 44183
rust-nodemap: NodeMap trait with simplest implementation We're defining here only a small part of the immutable methods it will have at the end. This is so we can focus in the following changesets on the needed abstractions for a mutable append-only serializable version. The first implementor exposes the actual lookup algorithm in its simplest form. It will have to be expanded to account for the missing methods, and the special cases related to NULL_NODE. Differential Revision: https://phab.mercurial-scm.org/D7791
Fri, 27 Dec 2019 23:04:18 +0100 rust-node: handling binary Node prefix
Georges Racinet <georges.racinet@octobus.net> [Fri, 27 Dec 2019 23:04:18 +0100] rev 44182
rust-node: handling binary Node prefix Parallel to the inner signatures of the nodetree functions in revlog.c, we'll have to handle prefixes of `Node` in binary form. Another motivation is that it allows to convert from full Node references to `NodePrefixRef` without copy. This is expected to be by far the most common case in practice. There's a slight complication due to the fact that we'll be sometimes interested in prefixes with an odd number of hexadecimal digits, which translates in binary form by a last byte in which only the highest weight 4 bits are considered. This is totally transparent for callers and could be revised once we have proper means to measure performance. The C implementation does the same, passing the length in nybbles as function arguments. Because Rust byte slices already have a length, we carry the even/odd informaton as a boolean, to avoid introducing logical redundancies and the related potential inconsistency bugs. There are a few candidates for inlining here, but we refrain from such premature optimizations, letting the compiler decide. Differential Revision: https://phab.mercurial-scm.org/D7790
Wed, 22 Jan 2020 16:35:56 +0100 rust-revlog: a trait for the revlog index
Georges Racinet <georges.racinet@octobus.net> [Wed, 22 Jan 2020 16:35:56 +0100] rev 44181
rust-revlog: a trait for the revlog index As explained in the doc comment, this is the minimum needed for our immediate concern, which is to implement a nodemap in Rust. The trait will be later implemented in `hg-cpython` by the index Python object implemented in C, thanks to exposition of the corresponding functions as a capsule. The `None` return cases in `node()` match what the `index_node()` C function does. Differential Revision: https://phab.mercurial-scm.org/D7789
Fri, 24 Jan 2020 17:10:45 -0800 pathauditor: drop a redundant call to bytes.lower()
Martin von Zweigbergk <martinvonz@google.com> [Fri, 24 Jan 2020 17:10:45 -0800] rev 44180
pathauditor: drop a redundant call to bytes.lower() `_lowerclean(s)` calls `s.lower()`, so we don't need to do that before calling it. Differential Revision: https://phab.mercurial-scm.org/D8001
Fri, 24 Jan 2020 15:18:19 -0800 merge: replace a repo.lookup('.') by more typical repo['.'].node()
Martin von Zweigbergk <martinvonz@google.com> [Fri, 24 Jan 2020 15:18:19 -0800] rev 44179
merge: replace a repo.lookup('.') by more typical repo['.'].node() The `repo.lookup('.')` form comes from b3311e26f94f (merge: fix --preview to show all nodes that will be merged (issue2043)., 2010-02-15). I don't know why that commit changed from `repo['.']`, but I don't think there's any reason to do that. Note that performance should not be a reason (anymore?), because repo.lookup() is implemented by first creating a context object. Differential Revision: https://phab.mercurial-scm.org/D7998
Fri, 24 Jan 2020 16:07:42 -0800 merge: drop now-unused "abort" argument from hg.merge()
Martin von Zweigbergk <martinvonz@google.com> [Fri, 24 Jan 2020 16:07:42 -0800] rev 44178
merge: drop now-unused "abort" argument from hg.merge() Differential Revision: https://phab.mercurial-scm.org/D7997
Fri, 24 Jan 2020 17:49:21 -0800 merge: don't auto-pick destination with `hg merge 'wdir()'`
Martin von Zweigbergk <martinvonz@google.com> [Fri, 24 Jan 2020 17:49:21 -0800] rev 44177
merge: don't auto-pick destination with `hg merge 'wdir()'` If the user doesn't specify a commit to merge with, we'll have `node==None` in `commands.merge()`. We'll then try to find a good commit to merge with. However, if the user, for some strange reason, runs `hg merge 'wdir()'`, we'll also have `node==None` and we'll do that same. That's clearly not the intent, so let's not do that. It turns out we'd instead crash on that command after this patch, so I added special handling of it too. Differential Revision: https://phab.mercurial-scm.org/D7996
Fri, 24 Jan 2020 16:05:11 -0800 merge: call hg.abortmerge() directly and return early
Martin von Zweigbergk <martinvonz@google.com> [Fri, 24 Jan 2020 16:05:11 -0800] rev 44176
merge: call hg.abortmerge() directly and return early It's seem really weird to go through a lot of unrelated code before we call `hg.merge(..., abort=True)` when we can just call `hg.abortmerge()` and return early. Differential Revision: https://phab.mercurial-scm.org/D7995
Fri, 24 Jan 2020 16:00:54 -0800 merge: check that there are no conflicts after --abort
Martin von Zweigbergk <martinvonz@google.com> [Fri, 24 Jan 2020 16:00:54 -0800] rev 44175
merge: check that there are no conflicts after --abort Same idea as in abcc82bf0717 (clean: check that there are no conflicts after, 2020-01-24). We should reuse more code here, but that will come later. Differential Revision: https://phab.mercurial-scm.org/D7994
Fri, 24 Jan 2020 15:07:44 -0800 merge: use check_incompatible_arguments() for --abort
Martin von Zweigbergk <martinvonz@google.com> [Fri, 24 Jan 2020 15:07:44 -0800] rev 44174
merge: use check_incompatible_arguments() for --abort Differential Revision: https://phab.mercurial-scm.org/D7993
Fri, 24 Jan 2020 20:27:59 -0800 wix: use original version string for MSI filename stable
Gregory Szorc <gregory.szorc@gmail.com> [Fri, 24 Jan 2020 20:27:59 -0800] rev 44173
wix: use original version string for MSI filename Version string normalization is mostly to placate MSI requirements. I think it makes sense to use the original version string in filenames. Since we can have distinct versions normalizing to the same MSI version string, this will allow us to distinguish between different actual version strings based on the filename. Differential Revision: https://phab.mercurial-scm.org/D8005
Fri, 24 Jan 2020 20:24:29 -0800 wix: always normalize version string stable
Gregory Szorc <gregory.szorc@gmail.com> [Fri, 24 Jan 2020 20:24:29 -0800] rev 44172
wix: always normalize version string Before, it was possible to pass in a custom version string which would not be valid in MSI. So we always normalize the version string. While we're here, also print when we normalize the version string, for better visibility. Differential Revision: https://phab.mercurial-scm.org/D8004
Fri, 24 Jan 2020 20:21:53 -0800 wix: more robust normalization of RC version components stable
Gregory Szorc <gregory.szorc@gmail.com> [Fri, 24 Jan 2020 20:21:53 -0800] rev 44171
wix: more robust normalization of RC version components MSI has strict version requirements where the format is `A.B.C[.D]` and all fields must be numeric (https://docs.microsoft.com/en-us/windows/win32/msi/productversion?redirectedfrom=MSDN). Only the first 3 are used by the installer itself. Mercurial's version strings can have `rcN` and an optional `+<commit>-<date>` fragment at the end. This commit teaches the MSI version normalization to handle both of these more robustly. Before, we would throw away the `.rcN` component completely. e.g. `5.3rc1` would get normalized to `5.3.0`. And worse, `5.3rc0+5-abcdef` would get normalized to `5.3.5`. After this commit, presence of an `.rcN` provides the value for a 4th field. e.g. `5.3rc1` -> `5.3.0.1`. In addition, the commit count from the `+` suffix gets normalized into the 4th version component, but only if the original version string didn't have a 4th version component or if no `rcN` is present. e.g. `5.3+5-abcdef` is `5.3.0.5`. Differential Revision: https://phab.mercurial-scm.org/D8003
Sat, 25 Jan 2020 00:16:04 -0500 copyright: update to 2020 stable
Matt Harbison <matt_harbison@yahoo.com> [Sat, 25 Jan 2020 00:16:04 -0500] rev 44170
copyright: update to 2020 Differential Revision: https://phab.mercurial-scm.org/D8006
Sat, 25 Jan 2020 01:06:46 -0500 phabricator: fix a crash when submitting binaries (issue6260) stable
Matt Harbison <matt_harbison@yahoo.com> [Sat, 25 Jan 2020 01:06:46 -0500] rev 44169
phabricator: fix a crash when submitting binaries (issue6260) I think this assumed that `p1()` returned the changectx instead of the previous filelog entry. Differential Revision: https://phab.mercurial-scm.org/D8010
Wed, 15 Jan 2020 17:15:45 -0800 rebase: move some variables after an error cases where they're not needed
Martin von Zweigbergk <martinvonz@google.com> [Wed, 15 Jan 2020 17:15:45 -0800] rev 44168
rebase: move some variables after an error cases where they're not needed Differential Revision: https://phab.mercurial-scm.org/D7905
Wed, 15 Jan 2020 10:44:23 -0800 rebase: clarify a little by calculating a set in Python instead of in revset
Martin von Zweigbergk <martinvonz@google.com> [Wed, 15 Jan 2020 10:44:23 -0800] rev 44167
rebase: clarify a little by calculating a set in Python instead of in revset By calculating the set in Python, we can give it a name, which helps readability. Differential Revision: https://phab.mercurial-scm.org/D7904
Wed, 15 Jan 2020 15:12:50 -0800 merge: avoid a negation in the definition of updatedirstate
Martin von Zweigbergk <martinvonz@google.com> [Wed, 15 Jan 2020 15:12:50 -0800] rev 44166
merge: avoid a negation in the definition of updatedirstate We only use `partial` in one place: the definition of `updatedirstate`. Let's simplify that a little. Differential Revision: https://phab.mercurial-scm.org/D7900
Fri, 24 Jan 2020 08:32:35 -0800 merge: move definition of `partial` closer to where it's used
Martin von Zweigbergk <martinvonz@google.com> [Fri, 24 Jan 2020 08:32:35 -0800] rev 44165
merge: move definition of `partial` closer to where it's used Differential Revision: https://phab.mercurial-scm.org/D7983
Wed, 22 Jan 2020 13:06:56 -0800 copies: extract function for finding directory renames
Martin von Zweigbergk <martinvonz@google.com> [Wed, 22 Jan 2020 13:06:56 -0800] rev 44164
copies: extract function for finding directory renames The directory rename code is logically quite isolated, so it makes sense to make it physically isolated as well. Differential Revision: https://phab.mercurial-scm.org/D7977
Wed, 22 Jan 2020 15:23:30 -0800 copies: avoid calculating debug-only stuff without --debug
Martin von Zweigbergk <martinvonz@google.com> [Wed, 22 Jan 2020 15:23:30 -0800] rev 44163
copies: avoid calculating debug-only stuff without --debug `renamedeleteset` and `divergeset` is only used with `repo.ui.debugflag`, so let's avoid calculating them otherwise. While at it, I also added a `del renamedeleteset` for consistency. Differential Revision: https://phab.mercurial-scm.org/D7976
Wed, 22 Jan 2020 15:20:12 -0800 copies: move early return in mergecopies() earlier
Martin von Zweigbergk <martinvonz@google.com> [Wed, 22 Jan 2020 15:20:12 -0800] rev 44162
copies: move early return in mergecopies() earlier It wasn't obvious that the early return happened only when there are no copies. That is the case, however, because if `fullcopy` is empty, then so is `copies1` and `copies2`, and then so is `inversecopies1` and `inversecopies2`, and then so is `allsources`, and then so is `copy`, `diverge` and `renamedelete`. By moving the early return earlier, we also avoid calculating the set of added files from the base to each side. Differential Revision: https://phab.mercurial-scm.org/D7975
Fri, 24 Jan 2020 07:00:45 -0800 tests: test merge of renames of different sources to same target
Martin von Zweigbergk <martinvonz@google.com> [Fri, 24 Jan 2020 07:00:45 -0800] rev 44161
tests: test merge of renames of different sources to same target This is a really obscure scenario, but let's still have it tested so we know when it changes. Differential Revision: https://phab.mercurial-scm.org/D7985
Fri, 24 Jan 2020 09:33:02 -0800 clean: check that there are no conflicts after
Martin von Zweigbergk <martinvonz@google.com> [Fri, 24 Jan 2020 09:33:02 -0800] rev 44160
clean: check that there are no conflicts after As noted by Pulkit, there should never be any conflicts after doing a clean update, so `hg.clean()` should never return `True`. Let's check that assertion instead to clarify the code. The callers will now get a `None` instead of a `False` returned, but that should be fine (both result in a 0 exit status). Differential Revision: https://phab.mercurial-scm.org/D7984
Fri, 24 Jan 2020 14:32:53 -0800 progress: delete deprecated ui.progress()
Martin von Zweigbergk <martinvonz@google.com> [Fri, 24 Jan 2020 14:32:53 -0800] rev 44159
progress: delete deprecated ui.progress() Differential Revision: https://phab.mercurial-scm.org/D7991
Fri, 17 Jan 2020 15:34:11 +0100 rust-dependencies: update rayon
Raphaël Gomès <rgomes@octobus.net> [Fri, 17 Jan 2020 15:34:11 +0100] rev 44158
rust-dependencies: update rayon This is just to make sure we use the latest version and also makes it easier to peruse the docs. Differential Revision: https://phab.mercurial-scm.org/D7926
Wed, 22 Jan 2020 20:01:38 -0800 packaging: add configparser to inno requirements file stable
Gregory Szorc <gregory.szorc@gmail.com> [Wed, 22 Jan 2020 20:01:38 -0800] rev 44157
packaging: add configparser to inno requirements file This dependency is missing and pip complains about it in strict hashing mode. How this was missed, I have no clue. Differential Revision: https://phab.mercurial-scm.org/D7973
Fri, 24 Jan 2020 11:05:42 -0500 merge with stable
Augie Fackler <augie@google.com> [Fri, 24 Jan 2020 11:05:42 -0500] rev 44156
merge with stable
Fri, 24 Jan 2020 11:02:59 -0500 Added signature for changeset e4344e463c0c stable
Augie Fackler <raf@durin42.com> [Fri, 24 Jan 2020 11:02:59 -0500] rev 44155
Added signature for changeset e4344e463c0c
Fri, 24 Jan 2020 11:02:58 -0500 Added tag 5.3rc1 for changeset e4344e463c0c stable
Augie Fackler <raf@durin42.com> [Fri, 24 Jan 2020 11:02:58 -0500] rev 44154
Added tag 5.3rc1 for changeset e4344e463c0c
Fri, 24 Jan 2020 01:37:18 -0500 packaging: rename hgrc.d to defaultrc for Windows config files next to the exe stable 5.3rc1
Matt Harbison <matt_harbison@yahoo.com> [Fri, 24 Jan 2020 01:37:18 -0500] rev 44153
packaging: rename hgrc.d to defaultrc for Windows config files next to the exe The code and the help still says that it will read hgrc.d next to the executable. But this directory needs to exist to read the resource based config files. Otherwise even `hg version` errors out: $ /c/Program\ Files/Mercurial/hg.exe version Traceback (most recent call last): File "hg", line 43, in <module> File "mercurial\dispatch.pyc", line 110, in run File "mercurial\dispatch.pyc", line 226, in dispatch File "mercurial\ui.pyc", line 308, in load File "mercurial\rcutil.pyc", line 99, in rccomponents File "mercurial\rcutil.pyc", line 69, in default_rc_resources File "mercurial\utils\resourceutil.pyc", line 84, in contents WindowsError: [Error 3] The system cannot find the path specified: 'c:\\Program Files\\mercurial\\defaultrc\\*.*' Differential Revision: https://phab.mercurial-scm.org/D7981
Fri, 24 Jan 2020 01:11:19 -0500 resourceutil: ensure `_rootpath` is defined under py2exe stable
Matt Harbison <matt_harbison@yahoo.com> [Fri, 24 Jan 2020 01:11:19 -0500] rev 44152
resourceutil: ensure `_rootpath` is defined under py2exe Can't even run `hg version` without this. Differential Revision: https://phab.mercurial-scm.org/D7980
Wed, 15 Jan 2020 15:08:42 -0800 merge: define updatedirstate a little earlier and reuse it
Martin von Zweigbergk <martinvonz@google.com> [Wed, 15 Jan 2020 15:08:42 -0800] rev 44151
merge: define updatedirstate a little earlier and reuse it Differential Revision: https://phab.mercurial-scm.org/D7899
Wed, 15 Jan 2020 15:07:43 -0800 merge: don't call update hook when using in-memory context
Martin von Zweigbergk <martinvonz@google.com> [Wed, 15 Jan 2020 15:07:43 -0800] rev 44150
merge: don't call update hook when using in-memory context I'm pretty sure many hook implementors will assume that they can inspect the working copy and/or dirstate parents when the hook is called, so I don't think we should call the hook when using an in-memory context. The new behavior matches that of the preupdate hook. Differential Revision: https://phab.mercurial-scm.org/D7898
Thu, 23 Jan 2020 13:10:48 -0800 merge with stable
Martin von Zweigbergk <martinvonz@google.com> [Thu, 23 Jan 2020 13:10:48 -0800] rev 44149
merge with stable
Wed, 22 Jan 2020 20:01:38 -0800 packaging: add configparser to inno requirements file
Gregory Szorc <gregory.szorc@gmail.com> [Wed, 22 Jan 2020 20:01:38 -0800] rev 44148
packaging: add configparser to inno requirements file This dependency is missing and pip complains about it in strict hashing mode. How this was missed, I have no clue. Differential Revision: https://phab.mercurial-scm.org/D7973
Wed, 22 Jan 2020 22:23:04 -0800 python-zstandard: blacken at 80 characters
Gregory Szorc <gregory.szorc@gmail.com> [Wed, 22 Jan 2020 22:23:04 -0800] rev 44147
python-zstandard: blacken at 80 characters I made this change upstream and it will make it into the next release of python-zstandard. I figured I'd send it Mercurial's way because it will allow us to drop this directory from the black exclusion list. # skip-blame blackening Differential Revision: https://phab.mercurial-scm.org/D7937
Tue, 21 Jan 2020 15:45:06 -0800 tests: move non-collapse test out of test-rebase-collapse
Martin von Zweigbergk <martinvonz@google.com> [Tue, 21 Jan 2020 15:45:06 -0800] rev 44146
tests: move non-collapse test out of test-rebase-collapse The test case was added in 76630fbbf4fa (test-rebase-collapse: Add test for rebase regression introduced in 12309c09d19a, 2012-01-23). I think `hg rebase --collapse` was involved in either the regression or in the fix that caused the regression, but the test that was added doesn't use `--collapse`, so it doesn't seem to belong in test-rebase-collapse.t. The test case is about copies, so I moved it to test-rebase-rename.t. Differential Revision: https://phab.mercurial-scm.org/D7968
Fri, 22 Nov 2019 20:27:09 -0800 debugcommands: add Python implementation to debuginstall
Gregory Szorc <gregory.szorc@gmail.com> [Fri, 22 Nov 2019 20:27:09 -0800] rev 44145
debugcommands: add Python implementation to debuginstall This seems like a useful detail to print. Differential Revision: https://phab.mercurial-scm.org/D7979
Fri, 22 Nov 2019 20:12:10 -0800 run-tests: remove --py3-warnings
Gregory Szorc <gregory.szorc@gmail.com> [Fri, 22 Nov 2019 20:12:10 -0800] rev 44144
run-tests: remove --py3-warnings This Python 2 only mode was to help Python 2 alert when doing things not supported on Python 3. Now that we have test coverage with Python 3, I don't think we need it. Differential Revision: https://phab.mercurial-scm.org/D7978
Wed, 22 Jan 2020 16:37:05 +0100 rust-node: binary Node ID and conversion utilities
Georges Racinet <georges.racinet@octobus.net> [Wed, 22 Jan 2020 16:37:05 +0100] rev 44143
rust-node: binary Node ID and conversion utilities The choice of type makes sure that a `Node` has the exact wanted size. We'll use a different type for prefixes. Added dependency: hexadecimal conversion relies on the `hex` crate. The fact that sooner or later Mercurial is going to need to change its hash sizes has been taken strongly in consideration: - the hash length is a constant, but that is not directly exposed to callers. Changing the value of that constant is the only thing to do to change the hash length (even in unit tests) - the code could be adapted to support several sizes of hashes, if that turned out to be useful. To that effect, only the size of a given `Node` is exposed in the public API. - callers not involved in initial computation, I/O and FFI are able to operate without a priori assumptions on the hash size. The traits `FromHex` and `ToHex` have not been directly implemented, so that the doc-comments explaining these restrictions would stay really visible in `cargo doc` Differential Revision: https://phab.mercurial-scm.org/D7788
Wed, 22 Jan 2020 16:23:29 +0100 rust-nodemap: building blocks for nodetree structures
Georges Racinet <georges.racinet@octobus.net> [Wed, 22 Jan 2020 16:23:29 +0100] rev 44142
rust-nodemap: building blocks for nodetree structures This is similar to `nodetreenode` in `revlog.c`. We give it a higher level feeling for ease of handling in Rust context and provide tools for tests and debugging. The encoding choice is dictated by our ultimate goal in this series, that is to make an append-only persistent version of `nodetree`: the 0th Block must be adressed from other Blocks. Differential Revision: https://phab.mercurial-scm.org/D7787
Tue, 21 Jan 2020 10:13:08 -0500 lfs: move the initialization of the upload request into the try block
Matt Harbison <matt_harbison@yahoo.com> [Tue, 21 Jan 2020 10:13:08 -0500] rev 44141
lfs: move the initialization of the upload request into the try block This (almost) guarantees that the file is closed in the case of an exception. The one hole is if the `seek(SEEK_END)`/`tell()`/`seek(0)` sequence fails. But that's going to go away when subclassing `httpconnection.httpsendfile` to fix the worker problem, so I'm not going to worry too much. (And that class appears to have the same problem.) Differential Revision: https://phab.mercurial-scm.org/D7959
Tue, 21 Jan 2020 09:55:35 -0500 lfs: drop an unnecessary r'' prefix
Matt Harbison <matt_harbison@yahoo.com> [Tue, 21 Jan 2020 09:55:35 -0500] rev 44140
lfs: drop an unnecessary r'' prefix No longer necessary since the source transformer was removed. # skip-blame for changing string prefixes Differential Revision: https://phab.mercurial-scm.org/D7958
(0) -30000 -10000 -3000 -1000 -300 -100 -48 +48 +100 +300 +1000 +3000 tip