This prepares for porting to generic templater API.
Note that we cannot use '%*s' to pad white spaces because it doesn't take
into account character widths, as described in b021170a2284.
This is necessary for "annotate" to encode ctx.date() in the same manner
as jsonchangeset printer.
It doesn't support list object because keeping mutable object in _item could
be a source of hidden bugs. Also, I can't think of the use case.
If `hg analyze` is run on a revision set which contains no merges, then
`hg synthesize` will raise IndexError trying to select from p2distance,
which will be empty.
Git is fairly unique among VCSes in that it doesn't record copies and renames,
instead choosing to detect them on the fly. Since Mercurial expects copies and
renames to be recorded, it can be valuable to preserve this history while
converting a Git repository to Mercurial. This patch adds a new convert option,
called 'convert.git.similarity', which determines how similar files must be to
be treated as renames or copies.
It's very useful to be able to colourise csets according to their
phases. There was no indication anywhere in the docs that this is
possible.
We use e.g. `changeset.secret = ` instead of `changeset.secret
='none'`, because otherwise this is a BC: it would nullify the effects
given to log.changeset label that usually surrounds the
changeset.{phase} labels. Specifying the label without any effect
instead of 'none' is a true no-op change and purely documentation.
Before, the format was
label(labeled text) # single label
[label1 label2](labeled text) # multiple
Now, it's
[labels|labeled text]
..which should make things a bit more clear.
This is a debug option for showing labels. This can be helpful for
knowing which labels are available for colouring or to see the output
when defining your own templates. A couple of tests are included.
It is a deeply hidden secret that it's possible to colorise so many
things with so many different labels. This is an attempt to document
this. The text is a bit long, but it seems as short as can be while
documenting everything. Perhaps it should be hidden under a --verbose
option.
The following patch splits up changed lines along tabs (using
re.findall), and gives them a "diff.tab" label. This can be used by
the color extension for colorising tabs, like it does right now with
trailing whitespace.
I also provide corresponding tests.
The existing roots(x - y) revset only considered the most recent 100
revisions. This was a good start. But expanding it to the full history
of the repository can dramatically increase execution time and thus
constitutes a useful benchmark.
Before this patch, "hg qselect" with --pop/--reapply may pop patches
unexpectedly, even when all of patches applied before "qselect" are
still pushable.
Strictly speaking about the condition of this issue:
- before "qselect"
- there are N applied patches
- the index of the guarded patch X in the series is less than N
- after "qselect"
- X is still guarded, and
- all of applied patched are still pushable
In the case above, "hg qselect" should keep current status, but it
actually tries to pop patches because of X.
The index in "the series" should be used to examine "pushable" of a
patch by "mq.pushablek()", but the index in "applied patches" is used,
and this may cause unexpected examination of guarded patch.
To examine "pushable" of already applied patch correctly, this patch
uses "mq.applied[i].name": "pushable" is the function introduced by
the previous patch, and it returns "mq.pushable(mq.applied[i].name)[0]".
Before this patch, "hg qselect" with --pop/--reapply may pop incorrect
patches, because the index in "applied patches" is used to pop patches
by "mq.pop()", even though the index in "the series" should be used.
For example, when the already applied patch becomes guarded and it
follows the already guarded (= not yet applied) one, "hg qselect" is
aborted, because it tries to pop to guarded one.
This patch uses "mq.applied[i - 1].name" to pop to the patch, of which
the index in the "applied ones" is "i - 1".
Before this patch, "hg qselect --reapply" is aborted when "--verbose"
is specified, because "mq.appliedname()" returns "INDEX PATCHNAME"
instead of "PATCHNAME" in such case and "mq.push" can't accept the
former as the name of patch.
This patch uses "mq.applied[i].name" instead of "mq.appliedname(i)" as
the name of the patch to be pushed for safety.
Now, there is no code path using "mq.appliedname()", and it should be
removed to prevent developers from using it in the wrong way like this
issue.
Before this patch, "hg qselect" may report incorrect numbers for
"number of guarded, applied patches has changed", because it examines
"pushable" of patches by the index not in "the series" but in "applied
patches", even though "mq.pushable()" expects the former.
To report correct numbers for changing "number of guarded, applied
patches", this patch uses the name of applied patch to examine
pushable-ness of it.
This patch also changes the result of existing "hg qselect" tests,
because they doesn't change pushable-ness of already applied patches.
This patch assumes that "hg qselect" focuses on changing pushable-ness
only of already applied patches, because:
- the report message uses not "previous" (in the series) but
"applied"
- the logic to pop patches for --pop/--reapply examines
pushable-ness only of already applied ones (in fact, there are
some incorrect code paths)
Before this patch, the shell alias causes failure when it takes its
specific (= unknown for "hg") options in the command line, because
"_parse()" can't accept them.
This is the regression introduced by 7849ac1dbc57.
It fixed the issue that ambiguity between shell aliases and commands
defined by extensions was ignored. But it also caused that ambiguous
shell alias is handled in "_parse()" even if it takes specific options
in the command line.
To avoid such failure, this patch checks shell alias again after
loading extensions.
All aliases and commands (including ones defined by extensions) are
completely defined before the 2nd (= newly added in this patch)
"_checkshellalias()" invocation, and "cmdutil.findcmd(strict=False)"
can detect ambiguity between them correctly.
For efficiency, this patch does:
- omit the 2nd "_checkshellalias()" invocation if "[ui] strict= True"
it causes "cmdutil.findcmd(strict=True)", of which result should
be equal to one of the 1st invocation before adding aliases
- avoid removing the 1st "_checkshellalias()" invocation
it causes "cmdutil.findcmd(strict=True)" invocation preventing
shell alias execution from loading extensions uselessly
To reduce changes in the subsequent patch fixing issue4355, this patch
makes "_checkshellalias" reusable regardless of adding aliases.
In this patch, alias definitions are added and restored, only when
"precheck=True".
`hg help -k` on my machine was aborting because the hg-prompt extension
was inserting a string and not a function into help.helptable and help
was blindly calling it.
This patch changes keyword searching to be more robust against
unexpected types.
Incidentally, this avoids the changelog cache being invalidated each time
it's accessed on a repoview.
On a filtering experiment on a repository the size of mozilla-central,
this makes a significant difference:
Before, running hg log -l 10 --time with about 8k changesets filtered out:
time: real 1.490 secs (user 1.450+0.000 sys 0.040+0.000)
After:
time: real 0.540 secs (user 0.530+0.000 sys 0.010+0.000)
The histedit command uses a revset like:
(_intlist('1234\x001235')) and merge()
Previously the optimizer gave a weight of 1.5 to the _intlist side (1 for the
function, 0.5 for the string) which caused it to process the merge() side first.
This caused it to evaluate merge against every commit in the repo, which took
2.5 seconds on a large repo.
I changed the weight of _intlist to 0, since it's a trivial calculation, which
makes it process intlist first, which makes merge apply only to the revs in the
list. Which makes the revset take 0.15 seconds now. Cutting off 2.4 seconds off
our histedit performance.
>From the revset benchmark:
revset #25: (_intlist('20000\x0020001')) and merge()
0) obsolete feature not enabled but 54243 markers found!
! wall 0.036767 comb 0.040000 user 0.040000 sys 0.000000 (best of 100)
1) obsolete feature not enabled but 54243 markers found!
! wall 0.000198 comb 0.000000 user 0.000000 sys 0.000000 (best of 9084)
Strip executes a revset like this:
max(parents(_intlist('1234\x001235')) - _intlist('1234\x001235'))
Previously the parents() revset would do 'subset & parents' which iterates over
each item in the subset and checks if it's in parents. subset is usually the
entire repo (a spanset) so this takes a while.
Reversing the parameters to be 'parents & subset' means the operation becomes
O(number of parents) instead of O(size of repo). It also means the result gets
evaluated immediately (since parents isn't a lazy set), but I think this is a
win in most scenarios.
This shaves 0.3 seconds off strip (amend/histedit/rebase/etc) for large repositories.
revset #0: parents(20000)
0) obsolete feature not enabled but 54243 markers found!
! wall 0.006256 comb 0.010000 user 0.010000 sys 0.000000 (best of 289)
1) obsolete feature not enabled but 54243 markers found!
! wall 0.000391 comb 0.000000 user 0.000000 sys 0.000000 (best of 4323)
Previously descendants() would force the provided subset to become a set. In
the case of revsets like '(%ld::) - (%ld)' (as used by histedit) this would
force the '- (%ld)' set to be evaluated, which produced a set containing every
commit in the repo (except %ld). This takes 0.6s on large repos.
This changes descendants to trust the subset to implement __contains__
efficiently, which improves the above revset to 0.16s. Shaving 0.4 seconds off
of histedit.
revset #27: (20000::) - (20000)
0) obsolete feature not enabled but 54243 markers found!
! wall 0.023640 comb 0.020000 user 0.020000 sys 0.000000 (best of 100)
1) obsolete feature not enabled but 54243 markers found!
! wall 0.019589 comb 0.020000 user 0.020000 sys 0.000000 (best of 100)
This commit removes the final revset related perf hotspot from histedit.
Combined with the previous two patches, they shave a little over 3 seconds off
histedit on large repos.
The internal commit API was changed in 2eef89bfd70d to expect None from the
filectx function when a file is to be deleted, not an IOError. This change
keeps synthrepo up-to-date.
Before this patch, no message is shown for failure of merging at "hg
import".
In such case, merging patch is imported as a normal revision silently,
and it may confuse users.
For simplicity, this patch recommends just using "--exact", even
though importing the merging patch itself is possible without it if:
- the hash of the 1st parent in the patch is equal to one of the
patch imported just before (or the parent of the working
directory, for the 1st patch of the series), and
- the hash of the 2nd parent in the patch is known in the local
repository
When grafting something with a matching origin, it would normally be skipped:
skipping already grafted revision 123 (23 also has origin 12)
But after stripping a graft origin, graft could fail with a reference to the
origin that no longer exists:
abort: unknown revision '5c095ad7e90f871700f02dd1fa5012cb4498a2d4'!
Instead, detect that the origin is unknown and skip it anyway, like:
skipping already grafted revision 8 (2 also has unknown origin 5c095ad7e90f871700f02dd1fa5012cb4498a2d4)
Previously, there was a copy / paste error with using the current changeset's
phase information. We now look up the parent context explicitly.
The line was too long so it is stored into a variable first.