Example #1
0
def dorebase(ui, repo, src, destctx):
    rebase.rebase(
        ui,
        repo,
        rev=[revsetlang.formatspec(b'%ld', src)],
        dest=revsetlang.formatspec(b'%d', destctx.rev()),
    )
Example #2
0
def _cachedgetoldworkingcopyparent(repo, wkpnode):
    if not util.safehasattr(repo, '_undooldworkingparentcache'):
        repo._undooldworkingparentcache = {}
    cache = repo._undooldworkingparentcache
    key = wkpnode
    if key not in cache:
        oldworkingparent = _readnode(repo, "workingparent.i", wkpnode)
        oldworkingparent = filter(None, oldworkingparent.split("\n"))
        oldwkprevstring = revsetlang.formatspec('%ls', oldworkingparent)
        urepo = repo.unfiltered()
        cache[key] = smartset.baseset(urepo.revs(oldwkprevstring))
    return cache[key]
Example #3
0
def _localbranch(repo, subset, x):
    """``_localbranch(changectx)``
    localbranch changesets

    Returns all commits within the same localbranch as the changeset(s). A local
    branch is all draft changesets that are connected, uninterupted by public
    changesets.  Any draft commit within a branch, or a public commit at the
    base of the branch, can be passed used to identify localbranches.
    """
    # executed on an filtered repo
    args = revset.getargsdict(x, 'branchrevset', 'changectx')
    revstring = revsetlang.getstring(args.get('changectx'),
                               _('localbranch argument must be a changectx'))
    revs = repo.revs(revstring)
    # we assume that there is only a single rev
    if repo[revs.first()].phase() == phases.public:
        querystring = revsetlang.formatspec('(children(%d) & draft())::',
                                            revs.first())
    else:
        querystring = revsetlang.formatspec('((::%ld) & draft())::', revs)
    return subset & smartset.baseset(repo.revs(querystring))
def getscratchbranchparts(repo, peer, outgoing, ui, bookmark):
    if not outgoing.missing:
        raise error.Abort(_(b'no commits to push'))

    if scratchbranchparttype not in bundle2.bundle2caps(peer):
        raise error.Abort(
            _(b'no server support for %r') % scratchbranchparttype
        )

    _validaterevset(
        repo, revsetlang.formatspec(b'%ln', outgoing.missing), bookmark
    )

    supportedversions = changegroup.supportedoutgoingversions(repo)
    # Explicitly avoid using '01' changegroup version in infinitepush to
    # support general delta
    supportedversions.discard(b'01')
    cgversion = min(supportedversions)
    _handlelfs(repo, outgoing.missing)
    cg = changegroup.makestream(repo, outgoing, cgversion, b'push')

    params = {}
    params[b'cgversion'] = cgversion
    if bookmark:
        params[b'bookmark'] = bookmark
        # 'prevbooknode' is necessary for pushkey reply part
        params[b'bookprevnode'] = b''
        bookmarks = repo._bookmarks
        if bookmark in bookmarks:
            params[b'bookprevnode'] = hex(bookmarks[bookmark])

    # Do not send pushback bundle2 part with bookmarks if remotenames extension
    # is enabled. It will be handled manually in `_push()`
    if not isremotebooksenabled(ui):
        params[b'pushbackbookmarks'] = b'1'

    parts = []

    # .upper() marks this as a mandatory part: server will abort if there's no
    #  handler
    parts.append(
        bundle2.bundlepart(
            scratchbranchparttype.upper(),
            advisoryparams=pycompat.iteritems(params),
            data=cg,
        )
    )

    return parts
Example #5
0
def _cachedgetolddrafts(repo, draftnode, obsnode):
    if not util.safehasattr(repo, '_undoolddraftcache'):
        repo._undoolddraftcache = {}
    cache = repo._undoolddraftcache
    key = draftnode + obsnode
    if key not in cache:
        olddraftheads = _readnode(repo, "draftheads.i", draftnode)
        oldheadslist = olddraftheads.split("\n")
        oldobs = _readnode(repo, "draftobsolete.i", obsnode)
        oldobslist = filter(None, oldobs.split("\n"))
        oldlogrevstring = revsetlang.formatspec(
            '(draft() & ancestors(%ls)) - %ls', oldheadslist, oldobslist)
        urepo = repo.unfiltered()
        cache[key] = smartset.baseset(urepo.revs(oldlogrevstring))
    return cache[key]
Example #6
0
def debugbruterebase(ui, repo, source, dest):
    """for every non-empty subset of source, run rebase -r subset -d dest

    Print one line summary for each subset. Assume obsstore is enabled.
    """
    srevs = list(repo.revs(source))

    with repo.wlock(), repo.lock():
        repolen = len(repo)
        cl = repo.changelog

        def getdesc(rev):
            result = cl.changelogrevision(rev).description
            if rev >= repolen:
                result += b"'"
            return result

        for i in xrange(1, 2**len(srevs)):
            subset = [rev for j, rev in enumerate(srevs) if i & (1 << j) != 0]
            spec = revsetlang.formatspec(b'%ld', subset)
            tr = repo.transaction(b'rebase')
            tr.report = lambda x: 0  # hide "transaction abort"

            ui.pushbuffer()
            try:
                rebase.rebase(ui, repo, dest=dest, rev=[spec])
            except error.Abort as ex:
                summary = b'ABORT: %s' % ex
            except Exception as ex:
                summary = b'CRASH: %s' % ex
            else:
                # short summary about new nodes
                cl = repo.changelog
                descs = []
                for rev in xrange(repolen, len(repo)):
                    desc = b'%s:' % getdesc(rev)
                    for prev in cl.parentrevs(rev):
                        if prev > -1:
                            desc += getdesc(prev)
                    descs.append(desc)
                descs.sort()
                summary = b' '.join(descs)
            ui.popbuffer()
            repo.vfs.tryunlink(b'rebasestate')

            subsetdesc = b''.join(getdesc(rev) for rev in subset)
            ui.write((b'%s: %s\n') % (subsetdesc.rjust(len(srevs)), summary))
            tr.abort()
Example #7
0
def oldworkingparenttemplate(context, mapping, args):
    """String. Workingcopyparent reverseindex repo states ago."""
    reverseindex = templater.evalinteger(context, mapping, args[0],
                                _('undonecommits needs an integer argument'))
    repo = mapping['ctx']._repo
    ctx = mapping['ctx']
    repo = repo.unfiltered()
    revstring = revsetlang.formatspec('oldworkingcopyparent(%d)', reverseindex)
    revs = repo.revs(revstring)
    tonode = repo.changelog.node
    nodes = [tonode(x) for x in revs]
    if ctx.node() in nodes:
        result = ctx.hex()
    else:
        result = None
    return result
Example #8
0
def createrebasepart(repo, peer, outgoing, onto, newhead):
    if not outgoing.missing:
        raise error.Abort(_('no changesets to rebase'))

    if rebaseparttype not in bundle2.bundle2caps(peer):
        raise error.Abort(_('no server support for %r') % rebaseparttype)

    validaterevset(repo, revsetlang.formatspec('%ln', outgoing.missing))

    cg = changegroup.makestream(repo, outgoing, '01', 'push')

    # Explicitly notify the server what obsmarker versions the client supports
    # so the client could receive marker from the server.
    #
    # The core mercurial logic will do the right thing (enable obsmarker
    # capabilities in the pushback bundle) if obsmarker exchange is enabled
    # client-side.
    #
    # But we want the marker without enabling marker exchange, and our server
    # could reply a marker without exchange or even obsstore enabled. So we
    # bypass the "standard" way of capabilities check by sending the supported
    # versions directly in our own part. Note: do not enable "exchange" because
    # it has an unwanted side effect: pushing markers from client to server.
    #
    # "createmarkers" is all we need to be able to write a new marker.
    if obsolete.isenabled(repo, obsolete.createmarkersopt):
        obsmarkerversions = '\0'.join(str(v) for v in obsolete.formats)
    else:
        obsmarkerversions = ''

    # .upper() marks this as a mandatory part: server will abort if there's no
    #  handler
    return bundle2.bundlepart(
        rebaseparttype.upper(),
        mandatoryparams={
            'onto': onto,
            'newhead': repr(newhead),
        }.items(),
        advisoryparams={
            # advisory: (old) server could ignore this without error
            'obsmarkerversions': obsmarkerversions,
        }.items(),
        data = cg)
Example #9
0
def restack(ui, repo, rebaseopts=None):
    """Repair a situation in which one or more changesets in a stack
       have been obsoleted (thereby leaving their descendants in the stack
       unstable) by finding any such changesets and rebasing their descendants
       onto the latest version of each respective changeset.
    """
    rebaseopts = (rebaseopts or {}).copy()

    # TODO: Remove config override after https://phab.mercurial-scm.org/D1063
    config = {('experimental', 'rebase.multidest'): True}

    with ui.configoverride(config), repo.wlock(), repo.lock():
        # Find drafts connected to the current stack via either changelog or
        # obsolete graph. Note: "draft() & ::." is optimized by D441.

        # 1. Connect drafts via changelog
        revs = list(repo.revs('(draft() & ::.)::'))
        if not revs:
            # "." is probably public. Check its direct children.
            revs = repo.revs('draft() & children(.)')
            if not revs:
                ui.status(_('nothing to restack\n'))
                return 1
        # 2. Connect revs via obsolete graph
        revs = list(repo.revs('successors(%ld)+allpredecessors(%ld)',
                              revs, revs))
        # 3. Connect revs via changelog again to cover missing revs
        revs = list(repo.revs('(draft() & ::%ld)::', revs))

        rebaseopts['rev'] = [revsetlang.formatspec('%ld', revs)]
        rebaseopts['dest'] = '_destrestack(SRC)'

        rebase.rebase(ui, repo, **rebaseopts)

        # Ensure that we always end up on the latest version of the
        # current changeset. Usually, this will be taken care of
        # by the rebase operation. However, in some cases (such as
        # if we are on the precursor of the base changeset) the
        # rebase will not update to the latest version, so we need
        # to do this manually.
        successor = repo.revs('allsuccessors(.)').last()
        if successor is not None:
            commands.update(ui, repo, rev=successor)
Example #10
0
def _findnextdelta(repo, reverseindex, branch, direction):
    # finds closest repos state making changes to branch in direction
    # input:
    #   repo: mercurial.localrepo
    #   reverseindex: positive int for index.i
    #   branch: string changectx (commit hash)
    #   direction: positive or negative int
    # output:
    #   int index with next branch delta
    #   this is the first repo state that makes a changectx, bookmark or working
    #   copy parent change that effects the given branch
    if 0 == direction: # no infinite cycles guarantee
        raise error.ProgrammingError
    repo = repo.unfiltered()
    # current state
    try:
        nodedict = _readindex(repo, reverseindex)
    except IndexError:
        raise error.Abort(_("index out of bounds"))
    alphaworkingcopyparent = _readnode(repo, "workingparent.i",
                                       nodedict["workingparent"])
    alphabookstring = _readnode(repo, "bookmarks.i",
                                nodedict["bookmarks"])
    incrementalindex = reverseindex

    spec = revsetlang.formatspec("_localbranch(%s)", branch)
    hexnodes = tohexnode(repo, spec)

    done = False
    while not done:
        # move index
        incrementalindex += direction
        # check this index
        try:
            nodedict = _readindex(repo, incrementalindex)
        except IndexError:
            raise error.Abort(_("index out of bounds"))
        # skip interupted commands
        if 'True' == nodedict['unfinished']:
            break
        # check wkp, commits, bookmarks
        workingcopyparent = _readnode(repo, "workingparent.i",
                                      nodedict["workingparent"])
        bookstring = _readnode(repo, "bookmarks.i", nodedict["bookmarks"])
        # local changes in respect to visible changectxs
        # disjunctive union of present and old = changes
        # intersection of changes and local = localchanges
        localctxchanges = revsetlang.formatspec(
            '((olddraft(%d) + olddraft(%d)) -'
            '(olddraft(%d) and olddraft(%d)))'
            ' and _localbranch(%s)',
            incrementalindex, reverseindex,
            incrementalindex, reverseindex,
            branch)
        done = done or repo.revs(localctxchanges)
        if done: # perf boost
            break
        # bookmark changes
        if alphabookstring != bookstring:
            diff = set(alphabookstring.split("\n")) ^\
                   set(bookstring.split("\n"))
            for mark in diff:
                if mark:
                    kv = mark.rsplit(" ", 1)
                    # was or will the mark be in the localbranch
                    if kv[1] in hexnodes:
                        done = True
                        break

        # working copy parent changes
        # for workingcopyparent, only changes within the scope are interesting
        if alphaworkingcopyparent != workingcopyparent:
            done = done or (workingcopyparent in hexnodes and
                            alphaworkingcopyparent in hexnodes)

    return incrementalindex
Example #11
0
def _logdraftheads(repo, tr):
    spec = revsetlang.formatspec('heads(draft())')
    hexnodes = tohexnode(repo, spec)
    revstring = "\n".join(sorted(hexnodes))
    return writelog(repo, tr, "draftheads.i", revstring)
Example #12
0
 def revs(self, expr, *args):
     expr = revsetlang.formatspec(expr, *args)
     m = revset.match(None, expr)
     return m(self)
Example #13
0
def _logdraftobsolete(repo, tr):
    spec = revsetlang.formatspec('draft() & obsolete()')
    hexnodes = tohexnode(repo, spec)
    revstring = "\n".join(sorted(hexnodes))
    return writelog(repo, tr, "draftobsolete.i", revstring)
Example #14
0
def smartlogrevset(repo, subset, x):
    """``smartlog([master], [recentdays=N])``
    Changesets relevent to you.

    'master' is the head of the public branch.
    Unnamed heads will be hidden unless it's within 'recentdays'.
    """

    args = revset.getargsdict(x, 'smartlogrevset', 'master recentdays')
    if 'master' in args:
        masterstring = revsetlang.getstring(args['master'],
                                            _('master must be a string'))
    else:
        masterstring = ''

    recentdays = revsetlang.getinteger(args.get('recentdays'),
                                       _("recentdays should be int"), -1)

    revs = set()
    heads = set()

    rev = repo.changelog.rev
    ancestor = repo.changelog.ancestor
    node = repo.changelog.node
    parentrevs = repo.changelog.parentrevs

    books = bookmarks.bmstore(repo)
    ignore = re.compile(repo.ui.config('smartlog',
                                       'ignorebookmarks',
                                       '!'))
    for b in books:
        if not ignore.match(b):
            heads.add(rev(books[b]))

    # add 'interesting' remote bookmarks as well
    remotebooks = set()
    if util.safehasattr(repo, 'names') and 'remotebookmarks' in repo.names:
        ns = repo.names['remotebookmarks']
        remotebooks = set(ns.listnames(repo))
        for name in _reposnames(repo.ui):
            if name in remotebooks:
                heads.add(rev(ns.namemap(repo, name)[0]))

    heads.update(repo.revs('.'))

    global hiddenchanges
    headquery = 'head()'
    if remotebooks:
        # When we have remote bookmarks, only show draft heads, since public
        # heads should have a remote bookmark indicating them. This allows us
        # to force push server bookmarks to new locations, and not have the
        # commits clutter the user's smartlog.
        headquery = 'heads(draft())'

    allheads = set(repo.revs(headquery))
    if recentdays >= 0:
        recentquery = revsetlang.formatspec('%r & date(-%d)', headquery,
                                            recentdays)
        recentrevs = set(repo.revs(recentquery))
        hiddenchanges += len(allheads - heads) - len(recentrevs - heads)
        heads.update(recentrevs)
    else:
        heads.update(allheads)

    masterrevset = _masterrevset(repo.ui, repo, masterstring)
    masterrev = _masterrev(repo, masterrevset)

    if masterrev is None:
        masterrev = repo['tip'].rev()

    masternode = node(masterrev)

    # Find all draft ancestors and latest public ancestor of heads
    # that are not in master.
    # We don't want to draw all public commits because there can be too
    # many of them.
    # Don't use revsets, they are too slow
    for head in heads:
        anc = rev(ancestor(node(head), masternode))
        queue = [head]
        while queue:
            current = queue.pop(0)
            if current not in revs:
                revs.add(current)
                # stop as soon as we find public commit
                ispublic = repo[current].phase() == phases.public
                if current != anc and not ispublic:
                    parents = parentrevs(current)
                    for p in parents:
                        if p > anc:
                            queue.append(p)

    # add context: master, current commit, and the common ancestor
    revs.add(masterrev)

    return subset & revs
Example #15
0
def _smartlog(ui, repo, *pats, **opts):
    masterstring = opts.get('master')
    masterrevset = _masterrevset(ui, repo, masterstring)

    revs = set()

    global hiddenchanges
    hiddenchanges = 0

    global commit_info
    commit_info = opts.get('commit_info')

    if not opts.get('rev'):
        if opts.get('all'):
            recentdays = -1
        else:
            recentdays = 14
        masterrev = _masterrev(repo, masterrevset)
        revstring = revsetlang.formatspec('smartlog(%s, %s)', masterrev or '',
                                          recentdays)
        revs.update(scmutil.revrange(repo, [revstring]))
    else:
        revs.update(scmutil.revrange(repo, opts.get('rev')))
        try:
            masterrev = repo.revs('.').first()
        except error.RepoLookupError:
            masterrev = revs[0]

    if -1 in revs:
        revs.remove(-1)

    # It's important that these function caches come after the revsets above,
    # because the revsets may cause extra nodes to become visible, which in
    # turn invalidates the changelog instance.
    rev = repo.changelog.rev
    ancestor = repo.changelog.ancestor
    node = repo.changelog.node

    # Find lowest common ancestors of revs. If we have multiple roots in the
    # repo the following will find one ancestor per group of revs with the
    # same root.
    ancestors = set()
    for r in revs:
        added = False
        for anc in list(ancestors):
            lca = rev(ancestor(node(anc), node(r)))
            if lca != -1:
                if anc != lca:
                    ancestors.discard(anc)
                    ancestors.add(lca)
                added = True

        if not added:
            ancestors.add(r)

    revs |= ancestors

    revs = sorted(list(revs), reverse=True)

    if len(revs) == 0:
        return

    # Print it!
    overrides = {}
    if ui.config('experimental', 'graphstyle.grandparent', '2.') == '|':
        overrides[('experimental', 'graphstyle.grandparent')] = '2.'
    with ui.configoverride(overrides, 'smartlog'):
        revdag = getdag(ui, repo, revs, masterrev)
        displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
        ui.pager('smartlog')
        cmdutil.displaygraph(
            ui, repo, revdag, displayer, graphmod.asciiedges, None, None)

    try:
        with open(repo.vfs.join('completionhints'), 'w+') as f:
            for rev in revdag:
                commit_hash = rev[2].node()
                # Skip fakectxt nodes
                if commit_hash != '...':
                    f.write(nodemod.short(commit_hash) + '\n')
    except IOError:
        # No write access. No big deal.
        pass

    if hiddenchanges:
        msg = _(
            "note: hiding %s old heads without bookmarks\n") % hiddenchanges
        hint = _("(use --all to see them)\n")
        ui.warn(msg)
        ui.warn(hint)
Example #16
0
def _smartlog(ui, repo, *pats, **opts):
    masterstring = opts.get('master')
    masterrevset = _masterrevset(ui, repo, masterstring)

    revs = set()

    global hiddenchanges
    hiddenchanges = 0

    global commit_info
    commit_info = opts.get('commit_info')

    if not opts.get('rev'):
        if opts.get('all'):
            recentdays = -1
        else:
            recentdays = 14
        revstring = revsetlang.formatspec('smartlog(%s, %s)', masterrevset,
                                          recentdays)
        revs.update(scmutil.revrange(repo, [revstring]))
        masterrev = _masterrev(repo, masterrevset)
    else:
        revs.update(scmutil.revrange(repo, opts.get('rev')))
        try:
            masterrev = repo.revs('.').first()
        except error.RepoLookupError:
            masterrev = revs[0]

    if -1 in revs:
        revs.remove(-1)

    # It's important that these function caches come after the revsets above,
    # because the revsets may cause extra nodes to become visible, which in
    # turn invalidates the changelog instance.
    rev = repo.changelog.rev
    ancestor = repo.changelog.ancestor
    node = repo.changelog.node

    # Find lowest common ancestors of revs. If we have multiple roots in the
    # repo the following will find one ancestor per group of revs with the
    # same root.
    ancestors = set()
    for r in revs:
        added = False
        for anc in list(ancestors):
            lca = rev(ancestor(node(anc), node(r)))
            if lca != -1:
                if anc != lca:
                    ancestors.discard(anc)
                    ancestors.add(lca)
                added = True

        if not added:
            ancestors.add(r)

    revs |= ancestors

    revs = sorted(list(revs), reverse=True)

    if len(revs) == 0:
        return

    # Print it!
    overrides = {}
    if ui.config('experimental', 'graphstyle.grandparent') == '|':
        overrides[('experimental', 'graphstyle.grandparent')] = '2.'
    with ui.configoverride(overrides, 'smartlog'):
        revdag = getdag(ui, repo, revs, masterrev)
        displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
        ui.pager('smartlog')
        cmdutil.displaygraph(
            ui, repo, revdag, displayer, graphmod.asciiedges, None, None)

    try:
        with open(repo.vfs.join('completionhints'), 'w+') as f:
            for rev in revdag:
                commit_hash = rev[2].node()
                # Skip fakectxt nodes
                if commit_hash != '...':
                    f.write(nodemod.short(commit_hash) + '\n')
    except IOError:
        # No write access. No big deal.
        pass

    if hiddenchanges:
        msg = _(
            "note: hiding %s old heads without bookmarks\n") % hiddenchanges
        hint = _("(use --all to see them)\n")
        ui.warn(msg)
        ui.warn(hint)
Example #17
0
def dorebase(ui, repo, src, dest):
    rebase.rebase(ui,
                  repo,
                  rev=[revsetlang.formatspec('%ld', src)],
                  dest=revsetlang.formatspec('%d', dest))
Example #18
0
def smartlogrevset(repo, subset, x):
    """``smartlog([master], [recentdays=N])``
    Changesets relevent to you.

    'master' is the head of the public branch.
    Unnamed heads will be hidden unless it's within 'recentdays'.
    """

    args = revset.getargsdict(x, 'smartlogrevset', 'master recentdays')
    if 'master' in args:
        masterstring = revsetlang.getstring(args['master'],
                                            _('master must be a string'))
    else:
        masterstring = ''

    recentdays = revsetlang.getinteger(args.get('recentdays'),
                                       _("recentdays should be int"), -1)

    revs = set()
    heads = set()

    rev = repo.changelog.rev
    branchinfo = repo.changelog.branchinfo
    ancestor = repo.changelog.ancestor
    node = repo.changelog.node
    parentrevs = repo.changelog.parentrevs

    books = bookmarks.bmstore(repo)
    ignore = re.compile(repo.ui.config('smartlog',
                                       'ignorebookmarks',
                                       '!'))
    for b in books:
        if not ignore.match(b):
            heads.add(rev(books[b]))

    # add 'interesting' remote bookmarks as well
    remotebooks = set()
    if util.safehasattr(repo, 'names') and 'remotebookmarks' in repo.names:
        ns = repo.names['remotebookmarks']
        remotebooks = set(ns.listnames(repo))
        for name in _reposnames(repo.ui):
            if name in remotebooks:
                heads.add(rev(ns.namemap(repo, name)[0]))

    heads.update(repo.revs('.'))

    global hiddenchanges
    headquery = 'head() & branch(.)'
    if remotebooks:
        # When we have remote bookmarks, only show draft heads, since public
        # heads should have a remote bookmark indicating them. This allows us
        # to force push server bookmarks to new locations, and not have the
        # commits clutter the user's smartlog.
        headquery = 'draft() &' + headquery

    allheads = set(repo.revs(headquery))
    if recentdays >= 0:
        recentquery = revsetlang.formatspec('%r & date(-%d)', headquery,
                                            recentdays)
        recentrevs = set(repo.revs(recentquery))
        hiddenchanges += len(allheads - heads) - len(recentrevs - heads)
        heads.update(recentrevs)
    else:
        heads.update(allheads)

    branches = set()
    for head in heads:
        branches.add(branchinfo(head)[0])

    masterrevset = _masterrevset(repo.ui, repo, masterstring)
    masterrev = _masterrev(repo, masterrevset)

    if masterrev is None:
        masterbranch = None
    else:
        masterbranch = branchinfo(masterrev)[0]

    for branch in branches:
        if branch != masterbranch:
            try:
                rs = 'first(reverse(branch("%s")) & public())' % branch
                branchmaster = repo.revs(rs).first()
                if branchmaster is None:
                    # local-only (draft) branch
                    rs = 'branch("%s")' % branch
                    branchmaster = repo.revs(rs).first()
            except Exception:
                branchmaster = repo.revs('tip').first()
        else:
            branchmaster = masterrev

        # Find all draft ancestors and latest public ancestor of heads
        # that are not in master.
        # We don't want to draw all public commits because there can be too
        # many of them.
        # Don't use revsets, they are too slow
        for head in heads:
            if branchinfo(head)[0] != branch:
                continue
            anc = rev(ancestor(node(head), node(branchmaster)))
            queue = [head]
            while queue:
                current = queue.pop(0)
                if current not in revs:
                    revs.add(current)
                    # stop as soon as we find public commit
                    ispublic = repo[current].phase() == phases.public
                    if current != anc and not ispublic:
                        parents = parentrevs(current)
                        for p in parents:
                            if p > anc:
                                queue.append(p)

        # add context: master, current commit, and the common ancestor
        revs.add(branchmaster)

        # get common branch ancestor
        if branch != masterbranch:
            anc = None
            for r in revs:
                if branchinfo(r)[0] != branch:
                    continue
                if anc is None:
                    anc = r
                else:
                    anc = rev(ancestor(node(anc), node(r)))
            if anc:
                revs.add(anc)

    return subset & revs
Example #19
0
def _preview(ui, repo, reverseindex):
    # Print smartlog like preview of undo
    # Input:
    #   ui:
    #   repo: mercurial.localrepo
    # Output:
    #   returns 1 on index error, 0 otherwise

    # override "UNDOINDEX" as a variable usable in template
    if not _gapcheck(ui, repo, reverseindex):
        repo.ui.status(_("WARN: missing history between present and this"
                         " state\n"))
    overrides = {
        ('templates', 'UNDOINDEX'): str(reverseindex),
    }

    opts = {}
    opts["template"] = "{undopreview}"
    repo = repo.unfiltered()

    try:
        nodedict = _readindex(repo, reverseindex)
        curdict = _readindex(repo, reverseindex)
    except IndexError:
        return 1

    bookstring = _readnode(repo, "bookmarks.i", nodedict["bookmarks"])
    oldmarks = bookstring.split("\n")
    oldpairs = set()
    for mark in oldmarks:
        kv = mark.rsplit(" ", 1)
        if len(kv) == 2:
            oldpairs.update(kv)
    bookstring = _readnode(repo, "bookmarks.i", curdict["bookmarks"])
    curmarks = bookstring.split("\n")
    curpairs = set()
    for mark in curmarks:
        kv = mark.rsplit(" ", 1)
        if len(kv) == 2:
            curpairs.update(kv)

    diffpairs = oldpairs.symmetric_difference(curpairs)
    # extract hashes from diffpairs

    bookdiffs = []
    for kv in diffpairs:
        bookdiffs += kv[0]

    revstring = revsetlang.formatspec(
        "ancestor(olddraft(0), olddraft(%s)) +"
        "(draft() & ::((olddraft(0) - olddraft(%s)) + "
        "(olddraft(%s) - olddraft(0)) + %ls + '.' + "
        "oldworkingcopyparent(%s)))",
        reverseindex, reverseindex, reverseindex, bookdiffs, reverseindex)

    opts['rev'] = [revstring]
    try:
        with ui.configoverride(overrides):
            cmdutil.graphlog(ui, repo, None, opts)
        # informative output
        nodedict = _readindex(repo, reverseindex)
        time = _readnode(repo, "date.i", nodedict["date"])
        time = util.datestr([float(x) for x in time.split(" ")])
    except IndexError:
        # don't print anything
        return 1

    try:
        nodedict = _readindex(repo, reverseindex - 1)
        commandstr = _readnode(repo, "command.i", nodedict["command"])
        commandlist = commandstr.split("\0")[1:]
        commandstr = " ".join(commandlist)
        uimessage = _('undo to %s, before %s\n') % (time, commandstr)
        repo.ui.status((uimessage))
    except IndexError:
        repo.ui.status(_("most recent state: undoing here won't change"
                        " anything\n"))
    return 0
Example #20
0
def _computerelative(repo, reverseindex, absolute=False, branch=""):
    # allows for relative undos using
    # redonode storage
    # allows for branch undos using
    # findnextdelta logic
    if reverseindex != 0:
        sign = reverseindex / abs(reverseindex)
    else:
        sign = None
    if not absolute:
        try: # attempt to get relative shift
            nodebranch = repo.vfs.read("undolog/redonode").split("\0")
            hexnode = nodebranch[0]
            try:
                oldbranch = nodebranch[1]
            except IndexError:
                oldbranch = ""
            rlog = _getrevlog(repo, 'index.i')
            rev = rlog.rev(bin(hexnode))
            shiftedindex = _invertindex(rlog, rev)
        except (IOError, error.RevlogError):
            # no shift
            shiftedindex = 0
            oldbranch = ""
    else:
        shiftedindex = 0
        oldbranch = ""

    if not branch:
        if not oldbranch:
            reverseindex = shiftedindex + reverseindex
        # else: previous command was branch undo
        # perform absolute undo (no shift)
    else:
        # check if relative branch
        if (branch != oldbranch) and (oldbranch != ""):
            rootdelta = revsetlang.formatspec(
                'roots(_localbranch(%s)) - roots(_localbranch(%s))',
                branch, oldbranch)
            if repo.revs(rootdelta):
                # different group of commits
                shiftedindex = 0

        # from shifted index, find reverse index # of states that change
        # branch
        # remember that reverseindex can be negative
        sign = reverseindex / abs(reverseindex)
        for count in range(abs(reverseindex)):
            shiftedindex = _findnextdelta(repo, shiftedindex, branch,
                                          direction=sign)
        reverseindex = shiftedindex
    # skip interupted commands
    if sign:
        done = False
        rlog = _getrevlog(repo, 'index.i')
        while not done:
            indexdict = _readindex(repo, reverseindex, rlog)
            if 'True' == indexdict['unfinished']:
                reverseindex += sign
            else:
                done = True
    return reverseindex
Example #21
0
def _undoto(ui, repo, reverseindex, keep=False, branch=None):
    # undo to specific reverseindex
    # requires inhibit extension
    # branch is a changectx hash (potentially short form)
    # which identifies its branch via localbranch revset
    if repo != repo.unfiltered():
        raise error.ProgrammingError(_("_undoto expects unfilterd repo"))
    try:
        nodedict = _readindex(repo, reverseindex)
    except IndexError:
        raise error.Abort(_("index out of bounds"))

    # bookmarks
    bookstring = _readnode(repo, "bookmarks.i", nodedict["bookmarks"])
    booklist = bookstring.split("\n")
    if branch:
        spec = revsetlang.formatspec('_localbranch(%s)', branch)
        branchcommits = tohexnode(repo, spec)
    else:
        branchcommits = False

    # copy implementation for bookmarks
    itercopy = []
    for mark in repo._bookmarks.iteritems():
        itercopy.append(mark)
    bmremove = []
    for mark in itercopy:
        if not branchcommits or hex(mark[1]) in branchcommits:
            bmremove.append((mark[0], None))
    repo._bookmarks.applychanges(repo, repo.currenttransaction(), bmremove)
    bmchanges = []
    for mark in booklist:
        if mark:
            kv = mark.rsplit(" ", 1)
            if not branchcommits or\
                kv[1] in branchcommits or\
                (kv[0], None) in bmremove:
                bmchanges.append((kv[0], bin(kv[1])))
    repo._bookmarks.applychanges(repo, repo.currenttransaction(), bmchanges)

    # working copy parent
    workingcopyparent = _readnode(repo, "workingparent.i",
                                  nodedict["workingparent"])
    if not keep:
        if not branchcommits or workingcopyparent in branchcommits:
            # bailifchanged is run, so this should be safe
            hg.clean(repo, workingcopyparent, show_stats=False)
    elif not branchcommits or workingcopyparent in branchcommits:
        # keeps working copy files
        prednode = bin(workingcopyparent)
        predctx = repo[prednode]

        changedfiles = []
        wctx = repo[None]
        wctxmanifest = wctx.manifest()
        predctxmanifest = predctx.manifest()
        dirstate = repo.dirstate
        diff = predctxmanifest.diff(wctxmanifest)
        changedfiles.extend(diff.iterkeys())

        with dirstate.parentchange():
            dirstate.rebuild(prednode, predctxmanifest, changedfiles)
            # we want added and removed files to be shown
            # properly, not with ? and ! prefixes
            for filename, data in diff.iteritems():
                if data[0][0] is None:
                    dirstate.add(filename)
                if data[1][0] is None:
                    dirstate.remove(filename)

    # visible changesets
    addedrevs = revsetlang.formatspec('olddraft(0) - olddraft(%d)',
                                      reverseindex)
    removedrevs = revsetlang.formatspec('olddraft(%d) - olddraft(0)',
                                        reverseindex)
    if not branch:
        smarthide(repo, addedrevs, removedrevs)
        revealcommits(repo, removedrevs)
    else:
        localadds = revsetlang.formatspec('(olddraft(0) - olddraft(%d)) and'
                                          ' _localbranch(%s)',
                                          reverseindex, branch)
        localremoves = revsetlang.formatspec('(olddraft(%d) - olddraft(0)) and'
                                          ' _localbranch(%s)',
                                          reverseindex, branch)
        smarthide(repo, localadds, removedrevs)
        smarthide(repo, addedrevs, localremoves, local=True)
        revealcommits(repo, localremoves)

    # informative output
    time = _readnode(repo, "date.i", nodedict["date"])
    time = util.datestr([float(x) for x in time.split(" ")])

    nodedict = _readindex(repo, reverseindex - 1)
    commandstr = _readnode(repo, "command.i", nodedict["command"])
    commandlist = commandstr.split("\0")[1:]
    commandstr = " ".join(commandlist)
    uimessage = _('undone to %s, before %s\n') % (time, commandstr)
    repo.ui.status((uimessage))
Example #22
0
def _donehexnodes(repo, reverseindex):
    repo = repo.unfiltered()
    revstring = revsetlang.formatspec('olddraft(%d)', reverseindex)
    revs = repo.revs(revstring)
    tonode = repo.changelog.node
    return [tonode(x) for x in revs]