Example #1
0
def branchmap(repo, proto):
    branchmap = phases.visiblebranchmap(repo)
    heads = []
    for branch, nodes in branchmap.iteritems():
        branchname = urllib.quote(encoding.fromlocal(branch))
        branchnodes = encodelist(nodes)
        heads.append('%s %s' % (branchname, branchnodes))
    return '\n'.join(heads)
Example #2
0
def checkheads(repo, remote, outgoing, remoteheads, newbranch=False, inc=False):
    """Check that a push won't add any outgoing head

    raise Abort error and display ui message as needed.
    """
    if remoteheads == [nullid]:
        # remote is empty, nothing to check.
        return

    cl = repo.changelog
    if remote.capable('branchmap'):
        # Check for each named branch if we're creating new remote heads.
        # To be a remote head after push, node must be either:
        # - unknown locally
        # - a local outgoing head descended from update
        # - a remote head that's known locally and not
        #   ancestral to an outgoing head

        # 1. Create set of branches involved in the push.
        branches = set(repo[n].branch() for n in outgoing.missing)

        # 2. Check for new branches on the remote.
        if remote.local():
            remotemap = phases.visiblebranchmap(remote)
        else:
            remotemap = remote.branchmap()
        newbranches = branches - set(remotemap)
        if newbranches and not newbranch: # new branch requires --new-branch
            branchnames = ', '.join(sorted(newbranches))
            raise util.Abort(_("push creates new remote branches: %s!")
                               % branchnames,
                             hint=_("use 'hg push --new-branch' to create"
                                    " new remote branches"))
        branches.difference_update(newbranches)

        # 3. Construct the initial oldmap and newmap dicts.
        # They contain information about the remote heads before and
        # after the push, respectively.
        # Heads not found locally are not included in either dict,
        # since they won't be affected by the push.
        # unsynced contains all branches with incoming changesets.
        oldmap = {}
        newmap = {}
        unsynced = set()
        for branch in branches:
            remotebrheads = remotemap[branch]
            prunedbrheads = [h for h in remotebrheads if h in cl.nodemap]
            oldmap[branch] = prunedbrheads
            newmap[branch] = list(prunedbrheads)
            if len(remotebrheads) > len(prunedbrheads):
                unsynced.add(branch)

        # 4. Update newmap with outgoing changes.
        # This will possibly add new heads and remove existing ones.
        ctxgen = (repo[n] for n in outgoing.missing)
        repo._updatebranchcache(newmap, ctxgen)

    else:
        # 1-4b. old servers: Check for new topological heads.
        # Construct {old,new}map with branch = None (topological branch).
        # (code based on _updatebranchcache)
        oldheads = set(h for h in remoteheads if h in cl.nodemap)
        newheads = oldheads.union(outgoing.missing)
        if len(newheads) > 1:
            for latest in reversed(outgoing.missing):
                if latest not in newheads:
                    continue
                minhrev = min(cl.rev(h) for h in newheads)
                reachable = cl.reachable(latest, cl.node(minhrev))
                reachable.remove(latest)
                newheads.difference_update(reachable)
        branches = set([None])
        newmap = {None: newheads}
        oldmap = {None: oldheads}
        unsynced = inc and branches or set()

    # 5. Check for new heads.
    # If there are more heads after the push than before, a suitable
    # error message, depending on unsynced status, is displayed.
    error = None
    for branch in branches:
        newhs = set(newmap[branch])
        oldhs = set(oldmap[branch])
        if len(newhs) > len(oldhs):
            dhs = list(newhs - oldhs)
            if error is None:
                if branch not in ('default', None):
                    error = _("push creates new remote head %s "
                              "on branch '%s'!") % (short(dhs[0]), branch)
                else:
                    error = _("push creates new remote head %s!"
                              ) % short(dhs[0])
                if branch in unsynced:
                    hint = _("you should pull and merge or "
                             "use push -f to force")
                else:
                    hint = _("did you forget to merge? "
                             "use push -f to force")
            if branch is not None:
                repo.ui.note(_("new remote heads on branch '%s'\n") % branch)
            for h in dhs:
                repo.ui.note(_("new remote head %s\n") % short(h))
    if error:
        raise util.Abort(error, hint=hint)

    # 6. Check for unsynced changes on involved branches.
    if unsynced:
        repo.ui.warn(_("note: unsynced remote changes!\n"))
def checkheads(repo,
               remote,
               outgoing,
               remoteheads,
               newbranch=False,
               inc=False):
    """Check that a push won't add any outgoing head

    raise Abort error and display ui message as needed.
    """
    if remoteheads == [nullid]:
        # remote is empty, nothing to check.
        return

    cl = repo.changelog
    if remote.capable('branchmap'):
        # Check for each named branch if we're creating new remote heads.
        # To be a remote head after push, node must be either:
        # - unknown locally
        # - a local outgoing head descended from update
        # - a remote head that's known locally and not
        #   ancestral to an outgoing head

        # 1. Create set of branches involved in the push.
        branches = set(repo[n].branch() for n in outgoing.missing)

        # 2. Check for new branches on the remote.
        if remote.local():
            remotemap = phases.visiblebranchmap(remote)
        else:
            remotemap = remote.branchmap()
        newbranches = branches - set(remotemap)
        if newbranches and not newbranch:  # new branch requires --new-branch
            branchnames = ', '.join(sorted(newbranches))
            raise util.Abort(_("push creates new remote branches: %s!") %
                             branchnames,
                             hint=_("use 'hg push --new-branch' to create"
                                    " new remote branches"))
        branches.difference_update(newbranches)

        # 3. Construct the initial oldmap and newmap dicts.
        # They contain information about the remote heads before and
        # after the push, respectively.
        # Heads not found locally are not included in either dict,
        # since they won't be affected by the push.
        # unsynced contains all branches with incoming changesets.
        oldmap = {}
        newmap = {}
        unsynced = set()
        for branch in branches:
            remotebrheads = remotemap[branch]
            prunedbrheads = [h for h in remotebrheads if h in cl.nodemap]
            oldmap[branch] = prunedbrheads
            newmap[branch] = list(prunedbrheads)
            if len(remotebrheads) > len(prunedbrheads):
                unsynced.add(branch)

        # 4. Update newmap with outgoing changes.
        # This will possibly add new heads and remove existing ones.
        ctxgen = (repo[n] for n in outgoing.missing)
        repo._updatebranchcache(newmap, ctxgen)

    else:
        # 1-4b. old servers: Check for new topological heads.
        # Construct {old,new}map with branch = None (topological branch).
        # (code based on _updatebranchcache)
        oldheads = set(h for h in remoteheads if h in cl.nodemap)
        newheads = oldheads.union(outgoing.missing)
        if len(newheads) > 1:
            for latest in reversed(outgoing.missing):
                if latest not in newheads:
                    continue
                minhrev = min(cl.rev(h) for h in newheads)
                reachable = cl.reachable(latest, cl.node(minhrev))
                reachable.remove(latest)
                newheads.difference_update(reachable)
        branches = set([None])
        newmap = {None: newheads}
        oldmap = {None: oldheads}
        unsynced = inc and branches or set()

    # 5. Check for new heads.
    # If there are more heads after the push than before, a suitable
    # error message, depending on unsynced status, is displayed.
    error = None
    for branch in branches:
        newhs = set(newmap[branch])
        oldhs = set(oldmap[branch])
        if len(newhs) > len(oldhs):
            dhs = list(newhs - oldhs)
            if error is None:
                if branch not in ('default', None):
                    error = _("push creates new remote head %s "
                              "on branch '%s'!") % (short(dhs[0]), branch)
                else:
                    error = _("push creates new remote head %s!") % short(
                        dhs[0])
                if branch in unsynced:
                    hint = _("you should pull and merge or "
                             "use push -f to force")
                else:
                    hint = _("did you forget to merge? "
                             "use push -f to force")
            if branch is not None:
                repo.ui.note(_("new remote heads on branch '%s'\n") % branch)
            for h in dhs:
                repo.ui.note(_("new remote head %s\n") % short(h))
    if error:
        raise util.Abort(error, hint=hint)

    # 6. Check for unsynced changes on involved branches.
    if unsynced:
        repo.ui.warn(_("note: unsynced remote changes!\n"))