1512 ''' |
1512 ''' |
1513 common = {} |
1513 common = {} |
1514 remote_heads = remote.heads() |
1514 remote_heads = remote.heads() |
1515 inc = self.findincoming(remote, common, remote_heads, force=force) |
1515 inc = self.findincoming(remote, common, remote_heads, force=force) |
1516 |
1516 |
|
1517 cl = self.changelog |
1517 update, updated_heads = self.findoutgoing(remote, common, remote_heads) |
1518 update, updated_heads = self.findoutgoing(remote, common, remote_heads) |
1518 msng_cl, bases, heads = self.changelog.nodesbetween(update, revs) |
1519 outg, bases, heads = cl.nodesbetween(update, revs) |
1519 |
1520 |
1520 def checkbranch(lheads, rheads, lheadcnt, branchname=None): |
1521 if not bases: |
1521 ''' |
1522 self.ui.status(_("no changes found\n")) |
1522 check whether there are more local heads than remote heads on |
1523 return None, 1 |
1523 a specific branch. |
1524 |
1524 |
1525 if not force and remote_heads != [nullid]: |
1525 lheads: local branch heads |
1526 |
1526 rheads: remote branch heads |
1527 def fail_multiple_heads(unsynced, branch=None): |
1527 lheadcnt: total number of local branch heads |
1528 if branch: |
1528 ''' |
|
1529 |
|
1530 warn = 0 |
|
1531 |
|
1532 if len(lheads) > len(rheads): |
|
1533 warn = 1 |
|
1534 else: |
|
1535 # add local heads involved in the push |
|
1536 updatelheads = [self.changelog.heads(x, lheads) |
|
1537 for x in update] |
|
1538 newheads = set(sum(updatelheads, [])) & set(lheads) |
|
1539 |
|
1540 if not newheads: |
|
1541 return True |
|
1542 |
|
1543 # add heads we don't have or that are not involved in the push |
|
1544 for r in rheads: |
|
1545 if r in self.changelog.nodemap: |
|
1546 desc = self.changelog.heads(r, heads) |
|
1547 l = [h for h in heads if h in desc] |
|
1548 if not l: |
|
1549 newheads.add(r) |
|
1550 else: |
|
1551 newheads.add(r) |
|
1552 if len(newheads) > len(rheads): |
|
1553 warn = 1 |
|
1554 |
|
1555 if warn: |
|
1556 if branchname is not None: |
|
1557 msg = _("abort: push creates new remote heads" |
1529 msg = _("abort: push creates new remote heads" |
1558 " on branch '%s'!\n") % branchname |
1530 " on branch '%s'!\n") % branch |
1559 else: |
1531 else: |
1560 msg = _("abort: push creates new remote heads!\n") |
1532 msg = _("abort: push creates new remote heads!\n") |
1561 self.ui.warn(msg) |
1533 self.ui.warn(msg) |
1562 if lheadcnt > len(rheads): |
1534 if unsynced: |
|
1535 self.ui.status(_("(you should pull and merge or" |
|
1536 " use push -f to force)\n")) |
|
1537 else: |
1563 self.ui.status(_("(did you forget to merge?" |
1538 self.ui.status(_("(did you forget to merge?" |
1564 " use push -f to force)\n")) |
1539 " use push -f to force)\n")) |
1565 else: |
1540 return None, 0 |
1566 self.ui.status(_("(you should pull and merge or" |
1541 |
1567 " use push -f to force)\n")) |
1542 if remote.capable('branchmap'): |
1568 return False |
1543 # Check for each named branch if we're creating new remote heads. |
1569 return True |
1544 # To be a remote head after push, node must be either: |
1570 |
1545 # - unknown locally |
1571 if not bases: |
1546 # - a local outgoing head descended from update |
1572 self.ui.status(_("no changes found\n")) |
1547 # - a remote head that's known locally and not |
1573 return None, 1 |
1548 # ancestral to an outgoing head |
1574 elif not force: |
1549 # |
1575 # Check for each named branch if we're creating new remote heads. |
1550 # New named branches cannot be created without --force. |
1576 # To be a remote head after push, node must be either: |
1551 |
1577 # - unknown locally |
1552 # 1. Create set of branches involved in the push. |
1578 # - a local outgoing head descended from update |
1553 branches = set(self[n].branch() for n in outg) |
1579 # - a remote head that's known locally and not |
1554 |
1580 # ancestral to an outgoing head |
1555 # 2. Check for new branches on the remote. |
1581 # |
1556 remotemap = remote.branchmap() |
1582 # New named branches cannot be created without --force. |
1557 newbranches = branches - set(remotemap) |
1583 |
1558 if newbranches: # new branch requires --force |
1584 if remote_heads != [nullid]: |
1559 branchnames = ', '.join("%s" % b for b in newbranches) |
1585 if remote.capable('branchmap'): |
1560 self.ui.warn(_("abort: push creates " |
1586 remotebrheads = remote.branchmap() |
1561 "new remote branches: %s!\n") |
1587 |
1562 % branchnames) |
1588 lbrmap = self.branchmap() |
1563 self.ui.status(_("(use 'hg push -f' to force)\n")) |
1589 localbrheads = {} |
1564 return None, 0 |
1590 if not revs: |
1565 |
1591 for br, hds in lbrmap.iteritems(): |
1566 # 3. Construct the initial oldmap and newmap dicts. |
1592 localbrheads[br] = (len(hds), hds) |
1567 # They contain information about the remote heads before and |
1593 else: |
1568 # after the push, respectively. |
1594 ctxgen = (self[n] for n in msng_cl) |
1569 # Heads not found locally are not included in either dict, |
1595 self._updatebranchcache(localbrheads, ctxgen) |
1570 # since they won't be affected by the push. |
1596 for br, hds in localbrheads.iteritems(): |
1571 # unsynced contains all branches with incoming changesets. |
1597 localbrheads[br] = (len(lbrmap[br]), hds) |
1572 oldmap = {} |
1598 |
1573 newmap = {} |
1599 newbranches = list(set(localbrheads) - set(remotebrheads)) |
1574 unsynced = set() |
1600 if newbranches: # new branch requires --force |
1575 for branch in branches: |
1601 branchnames = ', '.join("%s" % b for b in newbranches) |
1576 remoteheads = remotemap[branch] |
1602 self.ui.warn(_("abort: push creates " |
1577 prunedheads = [h for h in remoteheads if h in cl.nodemap] |
1603 "new remote branches: %s!\n") |
1578 oldmap[branch] = prunedheads |
1604 % branchnames) |
1579 newmap[branch] = list(prunedheads) |
1605 # propose 'push -b .' in the msg too? |
1580 if len(remoteheads) > len(prunedheads): |
1606 self.ui.status(_("(use 'hg push -f' to force)\n")) |
1581 unsynced.add(branch) |
1607 return None, 0 |
1582 |
1608 for branch, x in localbrheads.iteritems(): |
1583 # 4. Update newmap with outgoing changes. |
1609 if branch in remotebrheads: |
1584 # This will possibly add new heads and remove existing ones. |
1610 headcnt, lheads = x |
1585 ctxgen = (self[n] for n in outg) |
1611 rheads = remotebrheads[branch] |
1586 self._updatebranchcache(newmap, ctxgen) |
1612 if not checkbranch(lheads, rheads, headcnt, branch): |
1587 |
1613 return None, 0 |
1588 # 5. Check for new heads. |
1614 else: |
1589 # If there are more heads after the push than before, a suitable |
1615 if not checkbranch(heads, remote_heads, len(heads)): |
1590 # warning, depending on unsynced status, is displayed. |
1616 return None, 0 |
1591 for branch in branches: |
1617 |
1592 if len(newmap[branch]) > len(oldmap[branch]): |
1618 if inc: |
1593 return fail_multiple_heads(branch in unsynced, branch) |
1619 self.ui.warn(_("note: unsynced remote changes!\n")) |
1594 |
1620 |
1595 # 6. Check for unsynced changes on involved branches. |
|
1596 if unsynced: |
|
1597 self.ui.warn(_("note: unsynced remote changes!\n")) |
|
1598 |
|
1599 else: |
|
1600 # Old servers: Check for new topological heads. |
|
1601 # Code based on _updatebranchcache. |
|
1602 newheads = set(h for h in remote_heads if h in cl.nodemap) |
|
1603 oldheadcnt = len(newheads) |
|
1604 newheads.update(outg) |
|
1605 if len(newheads) > 1: |
|
1606 for latest in reversed(outg): |
|
1607 if latest not in newheads: |
|
1608 continue |
|
1609 minhrev = min(cl.rev(h) for h in newheads) |
|
1610 reachable = cl.reachable(latest, cl.node(minhrev)) |
|
1611 reachable.remove(latest) |
|
1612 newheads.difference_update(reachable) |
|
1613 if len(newheads) > oldheadcnt: |
|
1614 return fail_multiple_heads(inc) |
|
1615 if inc: |
|
1616 self.ui.warn(_("note: unsynced remote changes!\n")) |
1621 |
1617 |
1622 if revs is None: |
1618 if revs is None: |
1623 # use the fast path, no race possible on push |
1619 # use the fast path, no race possible on push |
1624 nodes = self.changelog.findmissing(common.keys()) |
1620 nodes = self.changelog.findmissing(common.keys()) |
1625 cg = self._changegroup(nodes, 'push') |
1621 cg = self._changegroup(nodes, 'push') |