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)
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)
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"))
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"))