mercurial/localrepo.py
changeset 10926 4d81cbd8a851
parent 10920 39c69b5dc258
parent 10925 a101a743c570
child 10960 ca739acf1a98
equal deleted inserted replaced
10924:b2860654e588 10926:4d81cbd8a851
  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')