[PATCH] localrepo: fix prepush warnings about new heads (issue 2131)
Peter Arrenbrecht
peter.arrenbrecht at gmail.com
Thu Apr 8 10:22:46 CDT 2010
# HG changeset patch
# User Peter Arrenbrecht <peter.arrenbrecht at gmail.com>
# Date 1270740102 -7200
localrepo: fix prepush warnings about new heads (issue 2131)
Simplifies the prepush check logic and makes it a lot more
direct and comprehensible. Fixes bug when local has changes
on branch A only, but also has a head of branch B that is no
longer a head of B at remote. Push would complain about a
new head on branch B before this fix.
diff --git a/mercurial/localrepo.py b/mercurial/localrepo.py
--- a/mercurial/localrepo.py
+++ b/mercurial/localrepo.py
@@ -1503,6 +1503,11 @@
update, updated_heads = self.findoutgoing(remote, common, remote_heads)
msng_cl, bases, heads = self.changelog.nodesbetween(update, revs)
+ cl = self.changelog
+ outgoingnodeset = set(msng_cl)
+ # compute set of nodes which, if they were a head before, no longer are
+ nolongeraheadnodeset = set(p for n in msng_cl for p in cl.parents(n))
+
def checkbranch(lheads, rheads, branchname=None):
'''
check whether there are more local heads than remote heads on
@@ -1511,26 +1516,10 @@
lheads: local branch heads
rheads: remote branch heads
'''
-
- warn = 0
-
- if len(lheads) > len(rheads):
- warn = 1
- else:
- # add heads we don't have or that are not involved in the push
- newheads = set(lheads)
- for r in rheads:
- if r in self.changelog.nodemap:
- desc = self.changelog.heads(r, heads)
- l = [h for h in heads if h in desc]
- if not l:
- newheads.add(r)
- else:
- newheads.add(r)
- if len(newheads) > len(rheads):
- warn = 1
-
- if warn:
+ newlheads = [n for n in lheads if n in outgoingnodeset]
+ formerrheads = [n for n in rheads if n in nolongeraheadnodeset]
+ if len(newlheads) > len(formerrheads):
+ # we add more new heads than we demote former heads to non-head
if branchname is not None:
msg = _("abort: push creates new remote heads"
" on branch '%s'!\n") % branchname
diff --git a/tests/test-push-warn b/tests/test-push-warn
--- a/tests/test-push-warn
+++ b/tests/test-push-warn
@@ -1,5 +1,8 @@
#!/bin/sh
+echo "[extensions]" >> $HGRCPATH
+echo "graphlog=" >> $HGRCPATH
+
mkdir a
cd a
hg init
@@ -193,5 +196,72 @@
hg -q merge 3
hg -q ci -d '0 0' -mma
hg push ../l -b b
+cd ..
+
+echo % check prepush with new branch head on former topo non-head
+hg init n
+cd n
+hg branch A
+echo a >a
+hg ci -Ama
+hg branch B
+echo b >b
+hg ci -Amb
+# b is now branch head of B, and a topological head
+# a is now branch head of A, but not a topological head
+hg clone . inner
+cd inner
+hg up B
+echo b1 >b1
+hg ci -Amb1
+# in the clone b1 is now the head of B
+cd ..
+hg up 0
+echo a2 >a2
+hg ci -Ama2
+# a2 is now the new branch head of A, and a new topological head
+# it replaces a former inner branch head, so it should at most warn about A, not B
+echo %% glog of local
+hg glog --template "{rev}: {branches} {desc}\n"
+echo %% glog of remote
+hg glog -R inner --template "{rev}: {branches} {desc}\n"
+echo %% outgoing
+hg out inner --template "{rev}: {branches} {desc}\n"
+hg push inner
+cd ..
+
+echo % check prepush with new branch head on former topo head
+hg init o
+cd o
+hg branch A
+echo a >a
+hg ci -Ama
+hg branch B
+echo b >b
+hg ci -Amb
+# b is now branch head of B, and a topological head
+hg up 0
+echo a1 >a1
+hg ci -Ama1
+# a1 is now branch head of A, and a topological head
+hg clone . inner
+cd inner
+hg up B
+echo b1 >b1
+hg ci -Amb1
+# in the clone b1 is now the head of B
+cd ..
+echo a2 >a2
+hg ci -Ama2
+# a2 is now the new branch head of A, and a topological head
+# it replaces a former topological and branch head, so this should not warn
+echo %% glog of local
+hg glog --template "{rev}: {branches} {desc}\n"
+echo %% glog of remote
+hg glog -R inner --template "{rev}: {branches} {desc}\n"
+echo %% outgoing
+hg out inner --template "{rev}: {branches} {desc}\n"
+hg push inner
+cd ..
exit 0
diff --git a/tests/test-push-warn.out b/tests/test-push-warn.out
--- a/tests/test-push-warn.out
+++ b/tests/test-push-warn.out
@@ -175,3 +175,82 @@
searching for changes
abort: push creates new remote heads on branch 'a'!
(did you forget to merge? use push -f to force)
+% check prepush with new branch head on former topo non-head
+marked working directory as branch A
+adding a
+marked working directory as branch B
+adding b
+updating to branch B
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+0 files updated, 0 files merged, 0 files removed, 0 files unresolved
+adding b1
+0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+adding a2
+created new head
+%% glog of local
+@ 2: A a2
+|
+| o 1: B b
+|/
+o 0: A a
+
+%% glog of remote
+@ 2: B b1
+|
+o 1: B b
+|
+o 0: A a
+
+%% outgoing
+comparing with inner
+searching for changes
+2: A a2
+pushing to inner
+searching for changes
+note: unsynced remote changes!
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files (+1 heads)
+% check prepush with new branch head on former topo head
+marked working directory as branch A
+adding a
+marked working directory as branch B
+adding b
+0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+adding a1
+created new head
+updating to branch A
+2 files updated, 0 files merged, 0 files removed, 0 files unresolved
+1 files updated, 0 files merged, 1 files removed, 0 files unresolved
+adding b1
+adding a2
+%% glog of local
+@ 3: A a2
+|
+o 2: A a1
+|
+| o 1: B b
+|/
+o 0: A a
+
+%% glog of remote
+@ 3: B b1
+|
+| o 2: A a1
+| |
+o | 1: B b
+|/
+o 0: A a
+
+%% outgoing
+comparing with inner
+searching for changes
+3: A a2
+pushing to inner
+searching for changes
+note: unsynced remote changes!
+adding changesets
+adding manifests
+adding file changes
+added 1 changesets with 1 changes to 1 files
More information about the Mercurial-devel
mailing list