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