prepush: rewrite most of the code from scratch
For servers with branchmap support, the algorithm now works as follows:
1. A list of branches in outgoing changesets is created.
2. Using the remote branchmap, a check for new branches is performed.
3. A map (from branch to head list) of locally known remote heads before
the push is created, and one which, after step 4, will contain the locally
known remote heads after the push.
4. The post-push head map is updated with the outgoing changesets, using the
branch cache update mechanism.
5. A check for new heads is performed, by comparing the length of the head list
before and after push, for each branch. If there are new heads, an error
depending on whether or not there are incoming changes on the branch,
is returned.
6. If the push is allowed, a warning is written if there are incoming changes
on any branches involved in the push.
For old servers, an algorithm similar to step 4-6 above is used to check for
new topological heads only.
Two bugs are also fixed:
1. Sometimes you would be allowed to push new branch heads without --force.
A test for this case was added.
2. You would get the "note: unsynced remote changes!" warning if there were any
incoming changesets, even if they were on unrelated branches.
adding a/a
adding a/b
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
moving a/a to b/a
moving a/b to b/b
2 files updated, 0 files merged, 2 files removed, 0 files unresolved
created new head
searching for copies back to rev 1
unmatched files in local:
a/c
a/d
unmatched files in other:
b/a
b/b
all copies found (* = to merge, ! = divergent):
b/a -> a/a
b/b -> a/b
checking for directory renames
dir a/ -> b/
file a/c -> b/c
file a/d -> b/d
resolving manifests
overwrite None partial False
ancestor f9b20c0d4c51 local ce36d17b18fb+ remote 397f8b00a740
a/d: remote renamed directory to b/d -> d
a/c: remote renamed directory to b/c -> d
a/b: other deleted -> r
a/a: other deleted -> r
b/a: remote created -> g
b/b: remote created -> g
update: a/a 1/6 files (16.67%)
removing a/a
update: a/b 2/6 files (33.33%)
removing a/b
update: a/c 3/6 files (50.00%)
moving a/c to b/c
update: a/d 4/6 files (66.67%)
moving a/d to b/d
update: b/a 5/6 files (83.33%)
getting b/a
update: b/b 6/6 files (100.00%)
getting b/b
4 files updated, 0 files merged, 2 files removed, 0 files unresolved
(branch merge, don't forget to commit)
a/* b/a b/b b/c b/d
M b/a
M b/b
A b/c
a/c
R a/a
R a/b
R a/c
? b/d
b/c renamed from a/c:354ae8da6e890359ef49ade27b68bbc361f3ca88
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
searching for copies back to rev 1
unmatched files in local:
b/a
b/b
b/d
unmatched files in other:
a/c
all copies found (* = to merge, ! = divergent):
b/a -> a/a
b/b -> a/b
checking for directory renames
dir a/ -> b/
file a/c -> b/c
resolving manifests
overwrite None partial False
ancestor f9b20c0d4c51 local 397f8b00a740+ remote ce36d17b18fb
None: local renamed directory to b/c -> d
update:None 1/1 files (100.00%)
getting a/c to b/c
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
a/* b/a b/b b/c b/d
A b/c
a/c
? b/d
created new head
b/c renamed from a/c:354ae8da6e890359ef49ade27b68bbc361f3ca88