Mercurial > hg
view tests/test-convert-filemap.t @ 30155:b7a966ce89ed
changelog: disable delta chains
This patch disables delta chains on changelogs. After this patch, new
entries on changelogs - including existing changelogs - will be stored
as the fulltext of that data (likely compressed). No delta computation
will be performed.
An overview of delta chains and data justifying this change follows.
Revlogs try to store entries as a delta against a previous entry (either
a parent revision in the case of generaldelta or the previous physical
revision when not using generaldelta). Most of the time this is the
correct thing to do: it frequently results in less CPU usage and smaller
storage.
Delta chains are most effective when the base revision being deltad
against is similar to the current data. This tends to occur naturally
for manifests and file data, since only small parts of each tend to
change with each revision. Changelogs, however, are a different story.
Changelog entries represent changesets/commits. And unless commits in a
repository are homogonous (same author, changing same files, similar
commit messages, etc), a delta from one entry to the next tends to be
relatively large compared to the size of the entry. This means that
delta chains tend to be short. How short? Here is the full vs delta
revision breakdown on some real world repos:
Repo % Full % Delta Max Length
hg 45.8 54.2 6
mozilla-central 42.4 57.6 8
mozilla-unified 42.5 57.5 17
pypy 46.1 53.9 6
python-zstandard 46.1 53.9 3
(I threw in python-zstandard as an example of a repo that is homogonous.
It contains a small Python project with changes all from the same
author.)
Contrast this with the manifest revlog for these repos, where 99+% of
revisions are deltas and delta chains run into the thousands.
So delta chains aren't as useful on changelogs. But even a short delta
chain may provide benefits. Let's measure that.
Delta chains may require less CPU to read revisions if the CPU time
spent reading smaller deltas is less than the CPU time used to
decompress larger individual entries. We can measure this via
`hg perfrevlog -c -d 1` to iterate a revlog to resolve each revision's
fulltext. Here are the results of that command on a repo using delta
chains in its changelog and on a repo without delta chains:
hg (forward)
! wall 0.407008 comb 0.410000 user 0.410000 sys 0.000000 (best of 25)
! wall 0.390061 comb 0.390000 user 0.390000 sys 0.000000 (best of 26)
hg (reverse)
! wall 0.515221 comb 0.520000 user 0.520000 sys 0.000000 (best of 19)
! wall 0.400018 comb 0.400000 user 0.390000 sys 0.010000 (best of 25)
mozilla-central (forward)
! wall 4.508296 comb 4.490000 user 4.490000 sys 0.000000 (best of 3)
! wall 4.370222 comb 4.370000 user 4.350000 sys 0.020000 (best of 3)
mozilla-central (reverse)
! wall 5.758995 comb 5.760000 user 5.720000 sys 0.040000 (best of 3)
! wall 4.346503 comb 4.340000 user 4.320000 sys 0.020000 (best of 3)
mozilla-unified (forward)
! wall 4.957088 comb 4.950000 user 4.940000 sys 0.010000 (best of 3)
! wall 4.660528 comb 4.650000 user 4.630000 sys 0.020000 (best of 3)
mozilla-unified (reverse)
! wall 6.119827 comb 6.110000 user 6.090000 sys 0.020000 (best of 3)
! wall 4.675136 comb 4.670000 user 4.670000 sys 0.000000 (best of 3)
pypy (forward)
! wall 1.231122 comb 1.240000 user 1.230000 sys 0.010000 (best of 8)
! wall 1.164896 comb 1.160000 user 1.160000 sys 0.000000 (best of 9)
pypy (reverse)
! wall 1.467049 comb 1.460000 user 1.460000 sys 0.000000 (best of 7)
! wall 1.160200 comb 1.170000 user 1.160000 sys 0.010000 (best of 9)
The data clearly shows that it takes less wall and CPU time to resolve
revisions when there are no delta chains in the changelogs, regardless
of the direction of traversal. Furthermore, not using a delta chain
means that fulltext resolution in reverse is as fast as iterating
forward. So not using delta chains on the changelog is a clear CPU win
for reading operations.
An example of a user-visible operation showing this speed-up is revset
evaluation. Here are results for
`hg perfrevset 'author(gps) or author(mpm)'`:
hg
! wall 1.655506 comb 1.660000 user 1.650000 sys 0.010000 (best of 6)
! wall 1.612723 comb 1.610000 user 1.600000 sys 0.010000 (best of 7)
mozilla-central
! wall 17.629826 comb 17.640000 user 17.600000 sys 0.040000 (best of 3)
! wall 17.311033 comb 17.300000 user 17.260000 sys 0.040000 (best of 3)
What about 00changelog.i size?
Repo Delta Chains No Delta Chains
hg 7,033,250 6,976,771
mozilla-central 82,978,748 81,574,623
mozilla-unified 88,112,349 86,702,162
pypy 20,740,699 20,659,741
The data shows that removing delta chains from the changelog makes the
changelog smaller.
Delta chains are also used during changegroup generation. This
operation essentially converts a series of revisions to one large
delta chain. And changegroup generation is smart: if the delta in
the revlog matches what the changegroup is emitting, it will reuse
the delta instead of recalculating it. We can measure the impact
removing changelog delta chains has on changegroup generation via
`hg perfchangegroupchangelog`:
hg
! wall 1.589245 comb 1.590000 user 1.590000 sys 0.000000 (best of 7)
! wall 1.788060 comb 1.790000 user 1.790000 sys 0.000000 (best of 6)
mozilla-central
! wall 17.382585 comb 17.380000 user 17.340000 sys 0.040000 (best of 3)
! wall 20.161357 comb 20.160000 user 20.120000 sys 0.040000 (best of 3)
mozilla-unified
! wall 18.722839 comb 18.720000 user 18.680000 sys 0.040000 (best of 3)
! wall 21.168075 comb 21.170000 user 21.130000 sys 0.040000 (best of 3)
pypy
! wall 4.828317 comb 4.830000 user 4.820000 sys 0.010000 (best of 3)
! wall 5.415455 comb 5.420000 user 5.410000 sys 0.010000 (best of 3)
The data shows eliminating delta chains makes the changelog part of
changegroup generation slower. This is expected since we now have to
compute deltas for revisions where we could recycle the delta before.
It is worth putting this regression into context of overall changegroup
times. Here is the rough total CPU time spent in changegroup generation
for various repos while using delta chains on the changelog:
Repo CPU Time (s) CPU Time w/ compression
hg 4.50 7.05
mozilla-central 111.1 222.0
pypy 28.68 75.5
Before compression, removing delta chains from the changegroup adds
~4.4% overhead to hg changegroup generation, 1.3% to mozilla-central,
and 2.0% to pypy. When you factor in zlib compression, these percentages
are roughly divided by 2.
While the increased CPU usage for changegroup generation is unfortunate,
I think it is acceptable because the percentage is small, server
operators (those likely impacted most by this) have other mechanisms
to mitigate CPU consumption (namely reducing zlib compression level and
pre-generated clone bundles), and because there is room to optimize this
in the future. For example, we could use the nullid as the base revision,
effectively encoding the full revision for each entry in the changegroup.
When doing this, `hg perfchangegroupchangelog` nearly halves:
mozilla-unified
! wall 21.168075 comb 21.170000 user 21.130000 sys 0.040000 (best of 3)
! wall 11.196461 comb 11.200000 user 11.190000 sys 0.010000 (best of 3)
This looks very promising as a future optimization opportunity.
It's worth that the changes in test-acl.t to the changegroup part size.
This is because revision 6 in the changegroup had a delta chain of
length 2 before and after this patch the base revision is nullrev.
When the base revision is nullrev, cg2packer.deltaparent() hardcodes
the *previous* revision from the changegroup as the delta parent.
This caused the delta in the changegroup to switch base revisions,
the delta to change, and the size to change accordingly. While the
size increased in this case, I think sizes will remain the same
on average, as the delta base for changelog revisions doesn't matter
too much (as this patch shows). So, I don't consider this a regression.
author | Gregory Szorc <gregory.szorc@gmail.com> |
---|---|
date | Thu, 13 Oct 2016 12:50:27 +0200 |
parents | e24eee55c129 |
children | 4441705b7111 |
line wrap: on
line source
$ HGMERGE=true; export HGMERGE $ echo '[extensions]' >> $HGRCPATH $ echo 'convert =' >> $HGRCPATH $ glog() > { > hg log -G --template '{rev} "{desc}" files: {files}\n' "$@" > } $ hg init source $ cd source $ echo foo > foo $ echo baz > baz $ mkdir -p dir/subdir $ echo dir/file >> dir/file $ echo dir/file2 >> dir/file2 $ echo dir/file3 >> dir/file3 # to be corrupted in rev 0 $ echo dir/subdir/file3 >> dir/subdir/file3 $ echo dir/subdir/file4 >> dir/subdir/file4 $ hg ci -d '0 0' -qAm '0: add foo baz dir/' $ echo bar > bar $ echo quux > quux $ echo dir/file4 >> dir/file4 # to be corrupted in rev 1 $ hg copy foo copied $ hg ci -d '1 0' -qAm '1: add bar quux; copy foo to copied' $ echo >> foo $ hg ci -d '2 0' -m '2: change foo' $ hg up -qC 1 $ echo >> bar $ echo >> quux $ hg ci -d '3 0' -m '3: change bar quux' created new head $ hg up -qC 2 $ hg merge -qr 3 $ echo >> bar $ echo >> baz $ hg ci -d '4 0' -m '4: first merge; change bar baz' $ echo >> bar $ echo 1 >> baz $ echo >> quux $ hg ci -d '5 0' -m '5: change bar baz quux' $ hg up -qC 4 $ echo >> foo $ echo 2 >> baz $ hg ci -d '6 0' -m '6: change foo baz' created new head $ hg up -qC 5 $ hg merge -qr 6 $ echo >> bar $ hg ci -d '7 0' -m '7: second merge; change bar' $ echo >> foo $ hg ci -m '8: change foo' $ glog @ 8 "8: change foo" files: foo | o 7 "7: second merge; change bar" files: bar baz |\ | o 6 "6: change foo baz" files: baz foo | | o | 5 "5: change bar baz quux" files: bar baz quux |/ o 4 "4: first merge; change bar baz" files: bar baz |\ | o 3 "3: change bar quux" files: bar quux | | o | 2 "2: change foo" files: foo |/ o 1 "1: add bar quux; copy foo to copied" files: bar copied dir/file4 quux | o 0 "0: add foo baz dir/" files: baz dir/file dir/file2 dir/file3 dir/subdir/file3 dir/subdir/file4 foo final file versions in this repo: $ hg manifest --debug 9463f52fe115e377cf2878d4fc548117211063f2 644 bar 94c1be4dfde2ee8d78db8bbfcf81210813307c3d 644 baz 7711d36246cc83e61fb29cd6d4ef394c63f1ceaf 644 copied 3e20847584beff41d7cd16136b7331ab3d754be0 644 dir/file 75e6d3f8328f5f6ace6bf10b98df793416a09dca 644 dir/file2 e96dce0bc6a217656a3a410e5e6bec2c4f42bf7c 644 dir/file3 6edd55f559cdce67132b12ca09e09cee08b60442 644 dir/file4 5fe139720576e18e34bcc9f79174db8897c8afe9 644 dir/subdir/file3 57a1c1511590f3de52874adfa04effe8a77d64af 644 dir/subdir/file4 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux $ hg debugrename copied copied renamed from foo:2ed2a3912a0b24502043eae84ee4b279c18b90dd $ cd .. Test interaction with startrev and verify that changing it is handled properly: $ > empty $ hg convert --filemap empty source movingstart --config convert.hg.startrev=3 -r4 initializing destination movingstart repository scanning source... sorting... converting... 1 3: change bar quux 0 4: first merge; change bar baz $ hg convert --filemap empty source movingstart scanning source... sorting... converting... 3 5: change bar baz quux 2 6: change foo baz 1 7: second merge; change bar warning: af455ce4166b3c9c88e6309c2b9332171dcea595 parent 61e22ca76c3b3e93df20338c4e02ce286898e825 is missing warning: cf908b3eeedc301c9272ebae931da966d5b326c7 parent 59e1ab45c888289513b7354484dac8a88217beab is missing 0 8: change foo splitrepo tests $ splitrepo() > { > msg="$1" > files="$2" > opts=$3 > echo "% $files: $msg" > prefix=`echo "$files" | sed -e 's/ /-/g'` > fmap="$prefix.fmap" > repo="$prefix.repo" > for i in $files; do > echo "include $i" >> "$fmap" > done > hg -q convert $opts --filemap "$fmap" --datesort source "$repo" > hg up -q -R "$repo" > glog -R "$repo" > hg -R "$repo" manifest --debug > } $ splitrepo 'skip unwanted merges; use 1st parent in 1st merge, 2nd in 2nd' foo % foo: skip unwanted merges; use 1st parent in 1st merge, 2nd in 2nd @ 3 "8: change foo" files: foo | o 2 "6: change foo baz" files: foo | o 1 "2: change foo" files: foo | o 0 "0: add foo baz dir/" files: foo 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo $ splitrepo 'merges are not merges anymore' bar % bar: merges are not merges anymore @ 4 "7: second merge; change bar" files: bar | o 3 "5: change bar baz quux" files: bar | o 2 "4: first merge; change bar baz" files: bar | o 1 "3: change bar quux" files: bar | o 0 "1: add bar quux; copy foo to copied" files: bar 9463f52fe115e377cf2878d4fc548117211063f2 644 bar $ splitrepo '1st merge is not a merge anymore; 2nd still is' baz % baz: 1st merge is not a merge anymore; 2nd still is @ 4 "7: second merge; change bar" files: baz |\ | o 3 "6: change foo baz" files: baz | | o | 2 "5: change bar baz quux" files: baz |/ o 1 "4: first merge; change bar baz" files: baz | o 0 "0: add foo baz dir/" files: baz 94c1be4dfde2ee8d78db8bbfcf81210813307c3d 644 baz $ splitrepo 'we add additional merges when they are interesting' 'foo quux' % foo quux: we add additional merges when they are interesting @ 8 "8: change foo" files: foo | o 7 "7: second merge; change bar" files: |\ | o 6 "6: change foo baz" files: foo | | o | 5 "5: change bar baz quux" files: quux |/ o 4 "4: first merge; change bar baz" files: |\ | o 3 "3: change bar quux" files: quux | | o | 2 "2: change foo" files: foo |/ o 1 "1: add bar quux; copy foo to copied" files: quux | o 0 "0: add foo baz dir/" files: foo 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux $ splitrepo 'partial conversion' 'bar quux' '-r 3' % bar quux: partial conversion @ 1 "3: change bar quux" files: bar quux | o 0 "1: add bar quux; copy foo to copied" files: bar quux b79105bedc55102f394e90a789c9c380117c1b4a 644 bar db0421cc6b685a458c8d86c7d5c004f94429ea23 644 quux $ splitrepo 'complete the partial conversion' 'bar quux' % bar quux: complete the partial conversion @ 4 "7: second merge; change bar" files: bar | o 3 "5: change bar baz quux" files: bar quux | o 2 "4: first merge; change bar baz" files: bar | o 1 "3: change bar quux" files: bar quux | o 0 "1: add bar quux; copy foo to copied" files: bar quux 9463f52fe115e377cf2878d4fc548117211063f2 644 bar bc3eca3f47023a3e70ca0d8cc95a22a6827db19d 644 quux $ rm -r foo.repo $ splitrepo 'partial conversion' 'foo' '-r 3' % foo: partial conversion @ 0 "0: add foo baz dir/" files: foo 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 foo $ splitrepo 'complete the partial conversion' 'foo' % foo: complete the partial conversion @ 3 "8: change foo" files: foo | o 2 "6: change foo baz" files: foo | o 1 "2: change foo" files: foo | o 0 "0: add foo baz dir/" files: foo 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo $ splitrepo 'copied file; source not included in new repo' copied % copied: copied file; source not included in new repo @ 0 "1: add bar quux; copy foo to copied" files: copied 2ed2a3912a0b24502043eae84ee4b279c18b90dd 644 copied $ hg --cwd copied.repo debugrename copied copied not renamed $ splitrepo 'copied file; source included in new repo' 'foo copied' % foo copied: copied file; source included in new repo @ 4 "8: change foo" files: foo | o 3 "6: change foo baz" files: foo | o 2 "2: change foo" files: foo | o 1 "1: add bar quux; copy foo to copied" files: copied | o 0 "0: add foo baz dir/" files: foo 7711d36246cc83e61fb29cd6d4ef394c63f1ceaf 644 copied 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo $ hg --cwd foo-copied.repo debugrename copied copied renamed from foo:2ed2a3912a0b24502043eae84ee4b279c18b90dd verify the top level 'include .' if there is no other includes: $ echo "exclude something" > default.fmap $ hg convert -q --filemap default.fmap -r1 source dummydest2 $ hg -R dummydest2 log --template '{rev} {node|short} {desc|firstline}\n' 1 61e22ca76c3b 1: add bar quux; copy foo to copied 0 c085cf2ee7fe 0: add foo baz dir/ $ echo "include somethingelse" >> default.fmap $ hg convert -q --filemap default.fmap -r1 source dummydest3 $ hg -R dummydest3 log --template '{rev} {node|short} {desc|firstline}\n' $ echo "include ." >> default.fmap $ hg convert -q --filemap default.fmap -r1 source dummydest4 $ hg -R dummydest4 log --template '{rev} {node|short} {desc|firstline}\n' 1 61e22ca76c3b 1: add bar quux; copy foo to copied 0 c085cf2ee7fe 0: add foo baz dir/ ensure that the filemap contains duplicated slashes (issue3612) $ cat > renames.fmap <<EOF > include dir > exclude dir/file2 > rename dir dir2//dir3 > include foo > include copied > rename foo foo2/ > rename copied ./copied2 > exclude dir/subdir > include dir/subdir/file3 > EOF $ rm source/.hg/store/data/dir/file3.i $ rm source/.hg/store/data/dir/file4.i $ hg -q convert --filemap renames.fmap --datesort source dummydest abort: data/dir/file3.i@e96dce0bc6a2: no match found! [255] $ hg -q convert --filemap renames.fmap --datesort --config convert.hg.ignoreerrors=1 source renames.repo ignoring: data/dir/file3.i@e96dce0bc6a2: no match found ignoring: data/dir/file4.i@6edd55f559cd: no match found $ hg up -q -R renames.repo $ glog -R renames.repo @ 4 "8: change foo" files: foo2 | o 3 "6: change foo baz" files: foo2 | o 2 "2: change foo" files: foo2 | o 1 "1: add bar quux; copy foo to copied" files: copied2 | o 0 "0: add foo baz dir/" files: dir2/dir3/file dir2/dir3/subdir/file3 foo2 $ hg -R renames.repo verify checking changesets checking manifests crosschecking files in changesets and manifests checking files 4 files, 5 changesets, 7 total revisions $ hg -R renames.repo manifest --debug d43feacba7a4f1f2080dde4a4b985bd8a0236d46 644 copied2 3e20847584beff41d7cd16136b7331ab3d754be0 644 dir2/dir3/file 5fe139720576e18e34bcc9f79174db8897c8afe9 644 dir2/dir3/subdir/file3 9a7b52012991e4873687192c3e17e61ba3e837a3 644 foo2 $ hg --cwd renames.repo debugrename copied2 copied2 renamed from foo2:2ed2a3912a0b24502043eae84ee4b279c18b90dd copied: $ hg --cwd source cat copied foo copied2: $ hg --cwd renames.repo cat copied2 foo filemap errors $ cat > errors.fmap <<EOF > include dir/ # beware that comments changes error line numbers! > exclude /dir > rename dir//dir /dir//dir/ "out of sync" > include > EOF $ hg -q convert --filemap errors.fmap source errors.repo errors.fmap:3: superfluous / in include '/dir' errors.fmap:3: superfluous / in rename '/dir' errors.fmap:4: unknown directive 'out of sync' errors.fmap:5: path to exclude is missing abort: errors in filemap [255] test branch closing revision pruning if branch is pruned $ hg init branchpruning $ cd branchpruning $ hg branch foo marked working directory as branch foo (branches are permanent and global, did you want a bookmark?) $ echo a > a $ hg ci -Am adda adding a $ hg ci --close-branch -m closefoo $ hg up 0 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg branch empty marked working directory as branch empty (branches are permanent and global, did you want a bookmark?) $ hg ci -m emptybranch $ hg ci --close-branch -m closeempty $ hg up 0 0 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg branch default marked working directory as branch default (branches are permanent and global, did you want a bookmark?) $ echo b > b $ hg ci -Am addb adding b $ hg ci --close-branch -m closedefault $ cat > filemap <<EOF > include b > EOF $ cd .. $ hg convert branchpruning branchpruning-hg1 initializing destination branchpruning-hg1 repository scanning source... sorting... converting... 5 adda 4 closefoo 3 emptybranch 2 closeempty 1 addb 0 closedefault $ glog -R branchpruning-hg1 _ 5 "closedefault" files: | o 4 "addb" files: b | | _ 3 "closeempty" files: | | | o 2 "emptybranch" files: |/ | _ 1 "closefoo" files: |/ o 0 "adda" files: a exercise incremental conversion at the same time $ hg convert -r0 --filemap branchpruning/filemap branchpruning branchpruning-hg2 initializing destination branchpruning-hg2 repository scanning source... sorting... converting... 0 adda $ hg convert -r4 --filemap branchpruning/filemap branchpruning branchpruning-hg2 scanning source... sorting... converting... 0 addb $ hg convert --filemap branchpruning/filemap branchpruning branchpruning-hg2 scanning source... sorting... converting... 3 closefoo 2 emptybranch 1 closeempty 0 closedefault $ glog -R branchpruning-hg2 _ 1 "closedefault" files: | o 0 "addb" files: b Test rebuilding of map with unknown revisions in shamap - it used to crash $ cd branchpruning $ hg up -r 2 0 files updated, 0 files merged, 1 files removed, 0 files unresolved $ hg merge 4 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) $ hg ci -m 'merging something' $ cd .. $ echo "53792d18237d2b64971fa571936869156655338d 6d955580116e82c4b029bd30f321323bae71a7f0" >> branchpruning-hg2/.hg/shamap $ hg convert --filemap branchpruning/filemap branchpruning branchpruning-hg2 --debug --config progress.debug=true run hg source pre-conversion action run hg sink pre-conversion action scanning source... scanning: 1 revisions sorting... converting... 0 merging something source: 2503605b178fe50e8fbbb0e77b97939540aa8c87 converting: 0/1 revisions (0.00%) unknown revmap source: 53792d18237d2b64971fa571936869156655338d run hg sink post-conversion action run hg source post-conversion action filemap rename undoing revision rename $ hg init renameundo $ cd renameundo $ echo 1 > a $ echo 1 > c $ hg ci -qAm add $ hg mv -q a b/a $ hg mv -q c b/c $ hg ci -qm rename $ echo 2 > b/a $ echo 2 > b/c $ hg ci -qm modify $ cd .. $ echo "rename b ." > renameundo.fmap $ hg convert --filemap renameundo.fmap renameundo renameundo2 initializing destination renameundo2 repository scanning source... sorting... converting... 2 add 1 rename filtering out empty revision repository tip rolled back to revision 0 (undo convert) 0 modify $ glog -R renameundo2 o 1 "modify" files: a c | o 0 "add" files: a c test merge parents/empty merges pruning $ glog() > { > hg log -G --template '{rev}:{node|short}@{branch} "{desc}" files: {files}\n' "$@" > } test anonymous branch pruning $ hg init anonymousbranch $ cd anonymousbranch $ echo a > a $ echo b > b $ hg ci -Am add adding a adding b $ echo a >> a $ hg ci -m changea $ hg up 0 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ echo b >> b $ hg ci -m changeb created new head $ hg up 1 2 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg merge 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) $ hg ci -m merge $ cd .. $ cat > filemap <<EOF > include a > EOF $ hg convert --filemap filemap anonymousbranch anonymousbranch-hg initializing destination anonymousbranch-hg repository scanning source... sorting... converting... 3 add 2 changea 1 changeb 0 merge $ glog -R anonymousbranch @ 3:c71d5201a498@default "merge" files: |\ | o 2:607eb44b17f9@default "changeb" files: b | | o | 1:1f60ea617824@default "changea" files: a |/ o 0:0146e6129113@default "add" files: a b $ glog -R anonymousbranch-hg o 1:cda818e7219b@default "changea" files: a | o 0:c334dc3be0da@default "add" files: a $ cat anonymousbranch-hg/.hg/shamap 0146e6129113dba9ac90207cfdf2d7ed35257ae5 c334dc3be0daa2a4e9ce4d2e2bdcba40c09d4916 1f60ea61782421edf8d051ff4fcb61b330f26a4a cda818e7219b5f7f3fb9f49780054ed6a1905ec3 607eb44b17f9348cd5cbd26e16af87ba77b0b037 c334dc3be0daa2a4e9ce4d2e2bdcba40c09d4916 c71d5201a498b2658d105a6bf69d7a0df2649aea cda818e7219b5f7f3fb9f49780054ed6a1905ec3 $ cat > filemap <<EOF > include b > EOF $ hg convert --filemap filemap anonymousbranch anonymousbranch-hg2 initializing destination anonymousbranch-hg2 repository scanning source... sorting... converting... 3 add 2 changea 1 changeb 0 merge $ glog -R anonymousbranch @ 3:c71d5201a498@default "merge" files: |\ | o 2:607eb44b17f9@default "changeb" files: b | | o | 1:1f60ea617824@default "changea" files: a |/ o 0:0146e6129113@default "add" files: a b $ glog -R anonymousbranch-hg2 o 1:62dd350b0df6@default "changeb" files: b | o 0:4b9ced861657@default "add" files: b $ cat anonymousbranch-hg2/.hg/shamap 0146e6129113dba9ac90207cfdf2d7ed35257ae5 4b9ced86165703791653059a1db6ed864630a523 1f60ea61782421edf8d051ff4fcb61b330f26a4a 4b9ced86165703791653059a1db6ed864630a523 607eb44b17f9348cd5cbd26e16af87ba77b0b037 62dd350b0df695f7d2c82a02e0499b16fd790f22 c71d5201a498b2658d105a6bf69d7a0df2649aea 62dd350b0df695f7d2c82a02e0499b16fd790f22 test named branch pruning $ hg init namedbranch $ cd namedbranch $ echo a > a $ echo b > b $ hg ci -Am add adding a adding b $ echo a >> a $ hg ci -m changea $ hg up 0 1 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg branch foo marked working directory as branch foo (branches are permanent and global, did you want a bookmark?) $ echo b >> b $ hg ci -m changeb $ hg up default 2 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg merge foo 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) $ hg ci -m merge $ cd .. $ cat > filemap <<EOF > include a > EOF $ hg convert --filemap filemap namedbranch namedbranch-hg initializing destination namedbranch-hg repository scanning source... sorting... converting... 3 add 2 changea 1 changeb 0 merge $ glog -R namedbranch @ 3:73899bcbe45c@default "merge" files: |\ | o 2:8097982d19fc@foo "changeb" files: b | | o | 1:1f60ea617824@default "changea" files: a |/ o 0:0146e6129113@default "add" files: a b $ glog -R namedbranch-hg o 1:cda818e7219b@default "changea" files: a | o 0:c334dc3be0da@default "add" files: a $ cd namedbranch $ hg --config extensions.mq= strip tip 1 files updated, 0 files merged, 0 files removed, 0 files unresolved saved backup bundle to $TESTTMP/namedbranch/.hg/strip-backup/73899bcbe45c-92adf160-backup.hg (glob) $ hg up foo 2 files updated, 0 files merged, 0 files removed, 0 files unresolved $ hg merge default 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) $ hg ci -m merge $ cd .. $ hg convert --filemap filemap namedbranch namedbranch-hg2 initializing destination namedbranch-hg2 repository scanning source... sorting... converting... 3 add 2 changea 1 changeb 0 merge $ glog -R namedbranch @ 3:e1959de76e1b@foo "merge" files: |\ | o 2:8097982d19fc@foo "changeb" files: b | | o | 1:1f60ea617824@default "changea" files: a |/ o 0:0146e6129113@default "add" files: a b $ glog -R namedbranch-hg2 o 2:dcf314454667@foo "merge" files: |\ | o 1:cda818e7219b@default "changea" files: a |/ o 0:c334dc3be0da@default "add" files: a $ cd .. test converting merges into a repo that contains other files $ hg init merge-test1 $ cd merge-test1 $ touch a && hg commit -Aqm 'add a' $ echo a > a && hg commit -Aqm 'edit a' $ hg up -q 0 $ touch b && hg commit -Aqm 'add b' $ hg merge -q 1 && hg commit -qm 'merge a & b' $ cd .. $ hg init merge-test2 $ cd merge-test2 $ mkdir converted $ touch converted/a toberemoved && hg commit -Aqm 'add converted/a & toberemoved' $ touch x && rm toberemoved && hg commit -Aqm 'add x & remove tobremoved' $ cd .. $ hg log -G -T '{shortest(node)} {desc}' -R merge-test1 @ 1191 merge a & b |\ | o 9077 add b | | o | d19f edit a |/ o ac82 add a $ hg log -G -T '{shortest(node)} {desc}' -R merge-test2 @ 150e add x & remove tobremoved | o bbac add converted/a & toberemoved - Build a shamap where the target converted/a is in on top of an unrelated - change to 'x'. This simulates using convert to merge several repositories - together. $ cat >> merge-test2/.hg/shamap <<EOF > $(hg -R merge-test1 log -r 0 -T '{node}') $(hg -R merge-test2 log -r 0 -T '{node}') > $(hg -R merge-test1 log -r 1 -T '{node}') $(hg -R merge-test2 log -r 1 -T '{node}') > EOF $ cat >> merge-test-filemap <<EOF > rename . converted/ > EOF $ hg convert --filemap merge-test-filemap merge-test1 merge-test2 --traceback scanning source... sorting... converting... 1 add b 0 merge a & b $ hg -R merge-test2 manifest -r tip converted/a converted/b x $ hg -R merge-test2 log -G -T '{shortest(node)} {desc}\n{files % "- {file}\n"}\n' o 6eaa merge a & b |\ - converted/a | | - toberemoved | | | o 2995 add b | | - converted/b | | @ | 150e add x & remove tobremoved |/ - toberemoved | - x | o bbac add converted/a & toberemoved - converted/a - toberemoved $ cd .. Test case where cleanp2 contains a file that doesn't exist in p2 - for example because filemap changed. $ hg init cleanp2 $ cd cleanp2 $ touch f f1 f2 && hg ci -Aqm '0' $ echo f1 > f1 && echo >> f && hg ci -m '1' $ hg up -qr0 && echo f2 > f2 && echo >> f && hg ci -qm '2' $ echo "include f" > filemap $ hg convert --filemap filemap . assuming destination .-hg initializing destination .-hg repository scanning source... sorting... converting... 2 0 1 1 0 2 $ hg merge && hg ci -qm '3' 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (branch merge, don't forget to commit) $ echo "include ." > filemap $ hg convert --filemap filemap . assuming destination .-hg scanning source... sorting... converting... 0 3 $ hg -R .-hg log -G -T '{shortest(node)} {desc}\n{files % "- {file}\n"}\n' o e9ed 3 |\ | o 33a0 2 | | - f | | o | f73e 1 |/ - f | o d681 0 - f $ hg -R .-hg mani -r tip f $ cd ..