phases: large rewrite on retract boundary
The new code is still pure Python, so we still have room to going significantly
faster. However its complexity of the complex part is `O(|[min_new_draft, tip]|)` instead of
`O(|[min_draft, tip]|` which should help tremendously one repository with old
draft (like mercurial-devel or mozilla-try).
This is especially useful as the most common "retract boundary" operation
happens when we commit/rewrite new drafts or when we push new draft to a
non-publishing server. In this case, the smallest new_revs is very close to the
tip and there is very few work to do.
A few smaller optimisation could be done for these cases and will be introduced in
later changesets.
We still have iterate over large sets of roots, but this is already a great
improvement for a very small amount of work. We gather information on the
affected changeset as we go as we can put it to use in the next changesets.
This extra data collection might slowdown the `register_new` case a bit, however
for register_new, it should not really matters. The set of new nodes is either
small, so the impact is negligible, or the set of new nodes is large, and the
amount of work to do to had them will dominate the overhead the collecting
information in `changed_revs`.
As this new code compute the changes on the fly, it unlock other interesting
improvement to be done in later changeset.
Test EOL update
$ cat >> $HGRCPATH <<EOF
> [diff]
> git = 1
> EOF
$ seteol () {
> if [ $1 = "LF" ]; then
> EOL='\n'
> else
> EOL='\r\n'
> fi
> }
$ makerepo () {
> echo
> echo "# ==== setup repository ===="
> echo '% hg init'
> hg init repo
> cd repo
>
> cat > .hgeol <<EOF
> [patterns]
> **.txt = LF
> EOF
>
> printf "first\nsecond\nthird\n" > a.txt
> printf "f\r\n" > f
> hg commit --addremove -m 'LF commit'
>
> cat > .hgeol <<EOF
> [patterns]
> **.txt = CRLF
> f = LF
> EOF
>
> printf "first\r\nsecond\r\nthird\r\n" > a.txt
> printf "f\n" > f
> hg commit -m 'CRLF commit'
>
> cd ..
> }
$ dotest () {
> seteol $1
>
> echo
> echo "% hg clone repo repo-$1"
> hg clone --noupdate repo repo-$1
> cd repo-$1
>
> cat > .hg/hgrc <<EOF
> [extensions]
> eol =
> EOF
>
> hg update
>
> echo '% a.txt (before)'
> cat a.txt
>
> printf "first${EOL}third${EOL}" > a.txt
>
> echo '% a.txt (after)'
> cat a.txt
> echo '% hg diff'
> hg diff
>
> echo '% hg update 0'
> hg update 0
>
> echo '% a.txt'
> cat a.txt
> echo '% hg diff'
> hg diff
>
>
> cd ..
> rm -r repo-$1
> }
$ makerepo
# ==== setup repository ====
% hg init
adding .hgeol
adding a.txt
adding f
$ dotest LF
% hg clone repo repo-LF
3 files updated, 0 files merged, 0 files removed, 0 files unresolved
% a.txt (before)
first\r (esc)
second\r (esc)
third\r (esc)
% a.txt (after)
first
third
% hg diff
diff --git a/a.txt b/a.txt
--- a/a.txt
+++ b/a.txt
@@ -1,3 +1,2 @@
first\r (esc)
-second\r (esc)
third\r (esc)
% hg update 0
merging a.txt
2 files updated, 1 files merged, 0 files removed, 0 files unresolved
% a.txt
first
third
% hg diff
diff --git a/a.txt b/a.txt
--- a/a.txt
+++ b/a.txt
@@ -1,3 +1,2 @@
first
-second
third
$ dotest CRLF
% hg clone repo repo-CRLF
3 files updated, 0 files merged, 0 files removed, 0 files unresolved
% a.txt (before)
first\r (esc)
second\r (esc)
third\r (esc)
% a.txt (after)
first\r (esc)
third\r (esc)
% hg diff
diff --git a/a.txt b/a.txt
--- a/a.txt
+++ b/a.txt
@@ -1,3 +1,2 @@
first\r (esc)
-second\r (esc)
third\r (esc)
% hg update 0
merging a.txt
2 files updated, 1 files merged, 0 files removed, 0 files unresolved
% a.txt
first
third
% hg diff
diff --git a/a.txt b/a.txt
--- a/a.txt
+++ b/a.txt
@@ -1,3 +1,2 @@
first
-second
third
Test in repo using eol extension, while keeping an eye on how filters are
applied:
$ cd repo
$ hg up -q -c -r null
$ cat > .hg/hgrc <<EOF
> [extensions]
> eol =
> EOF
Update to revision 0 which has no .hgeol, shouldn't use any filters, and
obviously should leave things as tidy as they were before the clean update.
$ hg up -c -r 0 -v --debug
resolving manifests
branchmerge: False, force: False, partial: False
ancestor: 000000000000, local: 000000000000+, remote: 15cbdf8ca3db
calling hook preupdate.eol: hgext.eol.preupdate
.hgeol: remote created -> g
getting .hgeol
filtering .hgeol through isbinary
a.txt: remote created -> g
getting a.txt
filtering a.txt through tolf
f: remote created -> g
getting f
3 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg st
$ hg branch b
marked working directory as branch b
(branches are permanent and global, did you want a bookmark?)
$ hg ci -m b
Merge changes that apply a filter to f:
$ hg merge 1
3 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg st
M .hgeol
M a.txt
M f
$ hg diff
diff --git a/.hgeol b/.hgeol
--- a/.hgeol
+++ b/.hgeol
@@ -1,2 +1,3 @@
[patterns]
-**.txt = LF
+**.txt = CRLF
+f = LF
diff --git a/a.txt b/a.txt
--- a/a.txt
+++ b/a.txt
@@ -1,3 +1,3 @@
-first
-second
-third
+first\r (esc)
+second\r (esc)
+third\r (esc)
diff --git a/f b/f
--- a/f
+++ b/f
@@ -1,1 +1,1 @@
-f\r (esc)
+f
Abort the merge with up -C to revision 0.
Note that files are filtered correctly for revision 0: f is not filtered, a.txt
is filtered with tolf, and everything is left tidy.
$ touch .hgeol * # ensure consistent dirtyness checks ignoring dirstate
$ hg up -C -r 0 -v --debug
eol: detected change in .hgeol
resolving manifests
branchmerge: False, force: True, partial: False
ancestor: 1db78bdd3bd6+, local: 1db78bdd3bd6+, remote: 15cbdf8ca3db
calling hook preupdate.eol: hgext.eol.preupdate
.hgeol: remote is newer -> g
getting .hgeol
filtering .hgeol through isbinary
a.txt: remote is newer -> g
getting a.txt
filtering a.txt through tolf
f: remote is newer -> g
getting f
3 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ touch .hgeol *
$ hg st --debug
eol: detected change in .hgeol
filtering .hgeol through isbinary
filtering a.txt through tolf
skip updating dirstate: identity mismatch (?)
$ hg diff
Things were clean, and updating again will not change anything:
$ touch .hgeol *
$ hg up -C -r 0 -v --debug
eol: detected change in .hgeol
filtering .hgeol through isbinary
filtering a.txt through tolf
resolving manifests
branchmerge: False, force: True, partial: False
ancestor: 15cbdf8ca3db+, local: 15cbdf8ca3db+, remote: 15cbdf8ca3db
calling hook preupdate.eol: hgext.eol.preupdate
starting 4 threads for background file closing (?)
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ touch .hgeol *
$ hg st --debug
eol: detected change in .hgeol
filtering .hgeol through isbinary
filtering a.txt through tolf
$ cd ..
$ rm -r repo