def checkheads(repo,
               remote,
               outgoing,
               remoteheads,
               newbranch=False,
               inc=False,
               newbookmarks=[]):
    """Check that a push won't add any outgoing head

    raise Abort error and display ui message as needed.
    """
    # 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
    if remoteheads == [nullid]:
        # remote is empty, nothing to check.
        return

    if remote.capable('branchmap'):
        headssum = _headssummary(repo, remote, outgoing)
    else:
        headssum = _oldheadssummary(repo, remoteheads, outgoing, inc)
    newbranches = [
        branch for branch, heads in headssum.iteritems() if heads[0] is None
    ]
    # 1. Check for new branches on the remote.
    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"))

    # 2. Compute newly pushed bookmarks. We don't warn about bookmarked heads.
    localbookmarks = repo._bookmarks
    remotebookmarks = remote.listkeys('bookmarks')
    bookmarkedheads = set()
    for bm in localbookmarks:
        rnode = remotebookmarks.get(bm)
        if rnode and rnode in repo:
            lctx, rctx = repo[bm], repo[rnode]
            if bookmarks.validdest(repo, rctx, lctx):
                bookmarkedheads.add(lctx.node())
        else:
            if bm in newbookmarks:
                bookmarkedheads.add(repo[bm].node())

    # 3. 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
    allmissing = set(outgoing.missing)
    allfuturecommon = set(c.node() for c in repo.set('%ld', outgoing.common))
    allfuturecommon.update(allmissing)
    for branch, heads in sorted(headssum.iteritems()):
        remoteheads, newheads, unsyncedheads = heads
        candidate_newhs = set(newheads)
        # add unsynced data
        if remoteheads is None:
            oldhs = set()
        else:
            oldhs = set(remoteheads)
        oldhs.update(unsyncedheads)
        candidate_newhs.update(unsyncedheads)
        dhs = None  # delta heads, the new heads on branch
        discardedheads = set()
        if repo.obsstore:
            # remove future heads which are actually obsoleted by another
            # pushed element:
            #
            # XXX as above, There are several cases this case does not handle
            # XXX properly
            #
            # (1) if <nh> is public, it won't be affected by obsolete marker
            #     and a new is created
            #
            # (2) if the new heads have ancestors which are not obsolete and
            #     not ancestors of any other heads we will have a new head too.
            #
            # These two cases will be easy to handle for known changeset but
            # much more tricky for unsynced changes.
            newhs = set()
            for nh in candidate_newhs:
                if nh in repo and repo[nh].phase() <= phases.public:
                    newhs.add(nh)
                else:
                    for suc in obsolete.allsuccessors(repo.obsstore, [nh]):
                        if suc != nh and suc in allfuturecommon:
                            discardedheads.add(nh)
                            break
                    else:
                        newhs.add(nh)
        else:
            newhs = candidate_newhs
        unsynced = sorted(h for h in unsyncedheads if h not in discardedheads)
        if unsynced:
            if None in unsynced:
                # old remote, no heads data
                heads = None
            elif len(unsynced) <= 4 or repo.ui.verbose:
                heads = ' '.join(short(h) for h in unsynced)
            else:
                heads = (' '.join(short(h) for h in unsynced[:4]) + ' ' +
                         _("and %s others") % (len(unsynced) - 4))
            if heads is None:
                repo.ui.status(
                    _("remote has heads that are "
                      "not known locally\n"))
            elif branch is None:
                repo.ui.status(
                    _("remote has heads that are "
                      "not known locally: %s\n") % heads)
            else:
                repo.ui.status(
                    _("remote has heads on branch '%s' that are "
                      "not known locally: %s\n") % (branch, heads))
        if remoteheads is None:
            if len(newhs) > 1:
                dhs = list(newhs)
                if error is None:
                    error = (_("push creates new branch '%s' "
                               "with multiple heads") % (branch))
                    hint = _("merge or"
                             " see \"hg help push\" for details about"
                             " pushing new heads")
        elif len(newhs) > len(oldhs):
            # remove bookmarked or existing remote heads from the new heads list
            dhs = sorted(newhs - bookmarkedheads - oldhs)
        if dhs:
            if error is None:
                if branch not in ('default', None):
                    error = _("push creates new remote head %s "
                              "on branch '%s'!") % (short(dhs[0]), branch)
                elif repo[dhs[0]].bookmarks():
                    error = _("push creates new remote head %s "
                              "with bookmark '%s'!") % (short(
                                  dhs[0]), repo[dhs[0]].bookmarks()[0])
                else:
                    error = _("push creates new remote head %s!") % short(
                        dhs[0])
                if unsyncedheads:
                    hint = _("pull and merge or"
                             " see \"hg help push\" for details about"
                             " pushing new heads")
                else:
                    hint = _("merge or"
                             " see \"hg help push\" for details about"
                             " pushing new heads")
            if branch is None:
                repo.ui.note(_("new remote heads:\n"))
            else:
                repo.ui.note(_("new remote heads on branch '%s':\n") % branch)
            for h in dhs:
                repo.ui.note((" %s\n") % short(h))
    if error:
        raise util.Abort(error, hint=hint)
예제 #2
0
def checkheads(repo, remote, outgoing, remoteheads, newbranch=False, inc=False,
               newbookmarks=[]):
    """Check that a push won't add any outgoing head

    raise Abort error and display ui message as needed.
    """
    # 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
    if remoteheads == [nullid]:
        # remote is empty, nothing to check.
        return

    if remote.capable('branchmap'):
        headssum = _headssummary(repo, remote, outgoing)
    else:
        headssum = _oldheadssummary(repo, remoteheads, outgoing, inc)
    newbranches = [branch for branch, heads in headssum.iteritems()
                   if heads[0] is None]
    # 1. Check for new branches on the remote.
    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"))

    # 2. Compute newly pushed bookmarks. We don't warn about bookmarked heads.
    localbookmarks = repo._bookmarks
    remotebookmarks = remote.listkeys('bookmarks')
    bookmarkedheads = set()
    for bm in localbookmarks:
        rnode = remotebookmarks.get(bm)
        if rnode and rnode in repo:
            lctx, rctx = repo[bm], repo[rnode]
            if bookmarks.validdest(repo, rctx, lctx):
                bookmarkedheads.add(lctx.node())
        else:
            if bm in newbookmarks:
                bookmarkedheads.add(repo[bm].node())

    # 3. 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
    # If there is no obsstore, allfuturecommon won't be used, so no
    # need to compute it.
    if repo.obsstore:
        allmissing = set(outgoing.missing)
        cctx = repo.set('%ld', outgoing.common)
        allfuturecommon = set(c.node() for c in cctx)
        allfuturecommon.update(allmissing)
    for branch, heads in sorted(headssum.iteritems()):
        remoteheads, newheads, unsyncedheads = heads
        candidate_newhs = set(newheads)
        # add unsynced data
        if remoteheads is None:
            oldhs = set()
        else:
            oldhs = set(remoteheads)
        oldhs.update(unsyncedheads)
        candidate_newhs.update(unsyncedheads)
        dhs = None # delta heads, the new heads on branch
        discardedheads = set()
        if repo.obsstore:
            # remove future heads which are actually obsoleted by another
            # pushed element:
            #
            # XXX as above, There are several cases this case does not handle
            # XXX properly
            #
            # (1) if <nh> is public, it won't be affected by obsolete marker
            #     and a new is created
            #
            # (2) if the new heads have ancestors which are not obsolete and
            #     not ancestors of any other heads we will have a new head too.
            #
            # These two cases will be easy to handle for known changeset but
            # much more tricky for unsynced changes.
            newhs = set()
            for nh in candidate_newhs:
                if nh in repo and repo[nh].phase() <= phases.public:
                    newhs.add(nh)
                else:
                    for suc in obsolete.allsuccessors(repo.obsstore, [nh]):
                        if suc != nh and suc in allfuturecommon:
                            discardedheads.add(nh)
                            break
                    else:
                        newhs.add(nh)
        else:
            newhs = candidate_newhs
        unsynced = sorted(h for h in unsyncedheads if h not in discardedheads)
        if unsynced:
            if None in unsynced:
                # old remote, no heads data
                heads = None
            elif len(unsynced) <= 4 or repo.ui.verbose:
                heads = ' '.join(short(h) for h in unsynced)
            else:
                heads = (' '.join(short(h) for h in unsynced[:4]) +
                         ' ' + _("and %s others") % (len(unsynced) - 4))
            if heads is None:
                repo.ui.status(_("remote has heads that are "
                                 "not known locally\n"))
            elif branch is None:
                repo.ui.status(_("remote has heads that are "
                                 "not known locally: %s\n") % heads)
            else:
                repo.ui.status(_("remote has heads on branch '%s' that are "
                                 "not known locally: %s\n") % (branch, heads))
        if remoteheads is None:
            if len(newhs) > 1:
                dhs = list(newhs)
                if error is None:
                    error = (_("push creates new branch '%s' "
                               "with multiple heads") % (branch))
                    hint = _("merge or"
                             " see \"hg help push\" for details about"
                             " pushing new heads")
        elif len(newhs) > len(oldhs):
            # remove bookmarked or existing remote heads from the new heads list
            dhs = sorted(newhs - bookmarkedheads - oldhs)
        if dhs:
            if error is None:
                if branch not in ('default', None):
                    error = _("push creates new remote head %s "
                              "on branch '%s'!") % (short(dhs[0]), branch)
                elif repo[dhs[0]].bookmarks():
                    error = _("push creates new remote head %s "
                              "with bookmark '%s'!") % (
                              short(dhs[0]), repo[dhs[0]].bookmarks()[0])
                else:
                    error = _("push creates new remote head %s!"
                              ) % short(dhs[0])
                if unsyncedheads:
                    hint = _("pull and merge or"
                             " see \"hg help push\" for details about"
                             " pushing new heads")
                else:
                    hint = _("merge or"
                             " see \"hg help push\" for details about"
                             " pushing new heads")
            if branch is None:
                repo.ui.note(_("new remote heads:\n"))
            else:
                repo.ui.note(_("new remote heads on branch '%s':\n") % branch)
            for h in dhs:
                repo.ui.note((" %s\n") % short(h))
    if error:
        raise util.Abort(error, hint=hint)
예제 #3
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.
    """
    # 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
    if remoteheads == [nullid]:
        # remote is empty, nothing to check.
        return

    if remote.capable('branchmap'):
        headssum = _headssummary(repo, remote, outgoing)
    else:
        headssum = _oldheadssummary(repo, remoteheads, outgoing, inc)
    newbranches = [branch for branch, heads in headssum.iteritems()
                   if heads[0] is None]
    # 1. Check for new branches on the remote.
    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"))

    # 2 compute newly pushed bookmarks. We
    # we don't warned about bookmarked heads.
    localbookmarks = repo._bookmarks
    remotebookmarks = remote.listkeys('bookmarks')
    bookmarkedheads = set()
    for bm in localbookmarks:
        rnode = remotebookmarks.get(bm)
        if rnode and rnode in repo:
            lctx, rctx = repo[bm], repo[rnode]
            if bookmarks.validdest(repo, rctx, lctx):
                bookmarkedheads.add(lctx.node())

    # 3. 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
    unsynced = False
    allmissing = set(outgoing.missing)
    allfuturecommon = set(c.node() for c in repo.set('%ld', outgoing.common))
    allfuturecommon.update(allmissing)
    for branch, heads in sorted(headssum.iteritems()):
        candidate_newhs = set(heads[1])
        # add unsynced data
        if heads[0] is None:
            oldhs = set()
        else:
            oldhs = set(heads[0])
        oldhs.update(heads[2])
        candidate_newhs.update(heads[2])
        dhs = None
        discardedheads = set()
        if repo.obsstore:
            # remove future heads which are actually obsolete by another
            # pushed element:
            #
            # XXX as above, There are several cases this case does not handle
            # XXX properly
            #
            # (1) if <nh> is public, it won't be affected by obsolete marker
            #     and a new is created
            #
            # (2) if the new heads have ancestors which are not obsolete and
            #     not ancestors of any other heads we will have a new head too.
            #
            # This two case will be easy to handle for know changeset but much
            # more tricky for unsynced changes.
            newhs = set()
            for nh in candidate_newhs:
                if nh in repo and repo[nh].phase() <= phases.public:
                    newhs.add(nh)
                else:
                    for suc in obsolete.allsuccessors(repo.obsstore, [nh]):
                        if suc != nh and suc in allfuturecommon:
                            discardedheads.add(nh)
                            break
                    else:
                        newhs.add(nh)
        else:
            newhs = candidate_newhs
        if [h for h in heads[2] if h not in discardedheads]:
            unsynced = True
        if heads[0] is None:
            if 1 < len(newhs):
                dhs = list(newhs)
                if error is None:
                    error = (_("push creates multiple headed new branch '%s'")
                             % (branch))
                    hint = _("merge or"
                             " see \"hg help push\" for detail about"
                             " pushing new heads")
        elif len(newhs) > len(oldhs):
            # strip updates to existing remote heads from the new heads list
            dhs = sorted(newhs - bookmarkedheads - oldhs)
        if dhs:
            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 heads[2]: # 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"))
예제 #4
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.
    """
    # 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
    if remoteheads == [nullid]:
        # remote is empty, nothing to check.
        return

    if remote.capable('branchmap'):
        headssum = _headssummary(repo, remote, outgoing)
    else:
        headssum = _oldheadssummary(repo, remoteheads, outgoing, inc)
    newbranches = [branch for branch, heads in headssum.iteritems()
                   if heads[0] is None]
    # 1. Check for new branches on the remote.
    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"))

    # 2 compute newly pushed bookmarks. We
    # we don't warned about bookmarked heads.
    localbookmarks = repo._bookmarks
    remotebookmarks = remote.listkeys('bookmarks')
    bookmarkedheads = set()
    for bm in localbookmarks:
        rnode = remotebookmarks.get(bm)
        if rnode and rnode in repo:
            lctx, rctx = repo[bm], repo[rnode]
            if bookmarks.validdest(repo, rctx, lctx):
                bookmarkedheads.add(lctx.node())

    # 3. 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
    unsynced = False
    allmissing = set(outgoing.missing)
    allfuturecommon = set(c.node() for c in repo.set('%ld', outgoing.common))
    allfuturecommon.update(allmissing)
    for branch, heads in sorted(headssum.iteritems()):
        if heads[0] is None:
            # Maybe we should abort if we push more that one head
            # for new branches ?
            continue
        candidate_newhs = set(heads[1])
        # add unsynced data
        oldhs = set(heads[0])
        oldhs.update(heads[2])
        candidate_newhs.update(heads[2])
        dhs = None
        discardedheads = set()
        if repo.obsstore:
            # remove future heads which are actually obsolete by another
            # pushed element:
            #
            # XXX as above, There are several cases this case does not handle
            # XXX properly
            #
            # (1) if <nh> is public, it won't be affected by obsolete marker
            #     and a new is created
            #
            # (2) if the new heads have ancestors which are not obsolete and
            #     not ancestors of any other heads we will have a new head too.
            #
            # This two case will be easy to handle for know changeset but much
            # more tricky for unsynced changes.
            newhs = set()
            for nh in candidate_newhs:
                if nh in repo and repo[nh].phase() <= phases.public:
                    newhs.add(nh)
                else:
                    for suc in obsolete.allsuccessors(repo.obsstore, [nh]):
                        if suc != nh and suc in allfuturecommon:
                            discardedheads.add(nh)
                            break
                    else:
                        newhs.add(nh)
        else:
            newhs = candidate_newhs
        if [h for h in heads[2] if h not in discardedheads]:
            unsynced = True
        if len(newhs) > len(oldhs):
            # strip updates to existing remote heads from the new heads list
            dhs = sorted(newhs - bookmarkedheads - oldhs)
        if dhs:
            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 heads[2]: # 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"))