Exemplo n.º 1
0
def strip(ui,
          repo,
          revs,
          update=True,
          backup="all",
          force=None,
          bookmark=None):
    wlock = lock = None
    try:
        wlock = repo.wlock()
        lock = repo.lock()

        if update:
            checklocalchanges(repo, force=force)
            urev, p2 = repo.changelog.parents(revs[0])
            if (util.safehasattr(repo, 'mq') and p2 != nullid
                    and p2 in [x.node for x in repo.mq.applied]):
                urev = p2
            hg.clean(repo, urev)
            repo.dirstate.write()

        repair.strip(ui, repo, revs, backup)

        marks = repo._bookmarks
        if bookmark:
            if bookmark == repo._bookmarkcurrent:
                bookmarks.unsetcurrent(repo)
            del marks[bookmark]
            marks.write()
            ui.write(_("bookmark '%s' deleted\n") % bookmark)
    finally:
        release(lock, wlock)
Exemplo n.º 2
0
 def test_push_executable_file(self):
     self.test_push_to_default(commit=True)
     repo = self.repo
     def file_callback(repo, memctx, path):
         if path == 'gamma':
             return context.memfilectx(path=path,
                                       data='foo',
                                       islink=False,
                                       isexec=True,
                                       copied=False)
         raise IOError(errno.EINVAL, 'Invalid operation: ' + path)
     ctx = context.memctx(repo,
                          (repo['tip'].node(), node.nullid),
                          'message',
                          ['gamma', ],
                          file_callback,
                          'author',
                          '2008-10-29 21:26:00 -0500',
                          {'branch': 'default', })
     new_hash = repo.commitctx(ctx)
     hg.clean(repo, repo['tip'].node())
     self.pushrevisions()
     tip = self.repo['tip']
     self.assertNotEqual(tip.node(), new_hash)
     self.assert_('@' in self.repo['tip'].user())
     self.assertEqual(tip['gamma'].flags(), 'x')
     self.assertEqual(tip['gamma'].data(), 'foo')
     self.assertEqual([x for x in tip.manifest().keys() if 'x' not in
                       tip[x].flags()], ['alpha', 'beta', 'adding_file', ])
Exemplo n.º 3
0
Arquivo: hg.py Projeto: dahool/vertaal
 def cleanup(self):
     try:
         commands.revert(self.repo.ui, self.repo, date=None, rev=None, 
                         all=True, no_backup=True)
         hg.clean(self.repo, self.branch, show_stats=False)
     except Exception, e:
         logger.error(e)
Exemplo n.º 4
0
Arquivo: strip.py Projeto: motlin/cyg
def strip(ui, repo, revs, update=True, backup=True, force=None, bookmarks=None):
    wlock = lock = None
    try:
        wlock = repo.wlock()
        lock = repo.lock()

        if update:
            checklocalchanges(repo, force=force)
            urev, p2 = repo.changelog.parents(revs[0])
            if (util.safehasattr(repo, 'mq') and
                p2 != nullid
                and p2 in [x.node for x in repo.mq.applied]):
                urev = p2
            hg.clean(repo, urev)
            repo.dirstate.write(repo.currenttransaction())

        repair.strip(ui, repo, revs, backup)

        repomarks = repo._bookmarks
        if bookmarks:
            with repo.transaction('strip') as tr:
                if repo._activebookmark in bookmarks:
                    bookmarksmod.deactivate(repo)
                for bookmark in bookmarks:
                    del repomarks[bookmark]
                repomarks.recordchange(tr)
            for bookmark in sorted(bookmarks):
                ui.write(_("bookmark '%s' deleted\n") % bookmark)
    finally:
        release(lock, wlock)
Exemplo n.º 5
0
def harvest(ui, repo, branch, dest="default", **opts):
    """Close and merge a named branch into the destination branch"""
    if branch not in repo.branchtags():
        ui.warn("Branch %s does not exist! (use 'hg branches' to get a list of branches)\n" % branch)
        return

    if dest not in repo.branchtags():
        ui.warn("Destination branch %s does not exist! (use 'hg branches' to get a list of branches)\n" % branch)
        return

    heads = repo.branchheads(branch)
    if len(heads) == 0:
        ui.warn("Cannot harvest branch %s because it is currently closed. \nUse 'hg merge' to merge it manually.\n" % branch)
        return

    if len(heads) > 1:
        ui.warn("Branch %s has multiple heads. \nUse 'hg merge' to merge it manually.\n" % branch)
        return

    rev = repo.branchtip(branch)
    newrev = context.memctx(repo, [rev, None], "Closed branch %s" % branch, [], None, opts.get('user'), opts.get('date'), extra={'close':1, 'branch':branch})
    newrev.commit()

    #don't need to switch if already on destination branch
    curr = repo[None].branch()
    if dest != curr:
        hg.clean(repo, dest, False)
        ui.status("Switched to branch %s before merging\n" % dest)

    failed = hg.merge(repo, branch, remind = False)
    if not failed:
        repo.commit("Merged %s" % branch, opts.get('user'), opts.get('date'), None)
        ui.status("Completed merge of %s into %s\n" % (branch, dest))
Exemplo n.º 6
0
def strip(ui,
          repo,
          revs,
          update=True,
          backup=True,
          force=None,
          bookmarks=None):
    with repo.wlock(), repo.lock():

        if update:
            checklocalchanges(repo, force=force)
            urev = _findupdatetarget(repo, revs)
            hg.clean(repo, urev)
            repo.dirstate.write(repo.currenttransaction())

        repair.strip(ui, repo, revs, backup)

        repomarks = repo._bookmarks
        if bookmarks:
            with repo.transaction('strip') as tr:
                if repo._activebookmark in bookmarks:
                    bookmarksmod.deactivate(repo)
                repomarks.applychanges(repo, tr,
                                       [(b, None) for b in bookmarks])
            for bookmark in sorted(bookmarks):
                ui.write(_("bookmark '%s' deleted\n") % bookmark)
Exemplo n.º 7
0
def strip(ui, repo, revs, update=True, backup=True, force=None, bookmark=None):
    wlock = lock = None
    try:
        wlock = repo.wlock()
        lock = repo.lock()

        if update:
            checklocalchanges(repo, force=force)
            urev, p2 = repo.changelog.parents(revs[0])
            if (util.safehasattr(repo, 'mq') and
                p2 != nullid
                and p2 in [x.node for x in repo.mq.applied]):
                urev = p2
            hg.clean(repo, urev)
            repo.dirstate.write()

        repair.strip(ui, repo, revs, backup)

        marks = repo._bookmarks
        if bookmark:
            if bookmark == repo._bookmarkcurrent:
                bookmarks.unsetcurrent(repo)
            del marks[bookmark]
            marks.write()
            ui.write(_("bookmark '%s' deleted\n") % bookmark)
    finally:
        release(lock, wlock)
Exemplo n.º 8
0
def strip(ui,
          repo,
          revs,
          update=True,
          backup=True,
          force=None,
          bookmarks=None):
    wlock = lock = None
    try:
        wlock = repo.wlock()
        lock = repo.lock()

        if update:
            checklocalchanges(repo, force=force)
            urev, p2 = repo.changelog.parents(revs[0])
            if (util.safehasattr(repo, 'mq') and p2 != nullid
                    and p2 in [x.node for x in repo.mq.applied]):
                urev = p2
            hg.clean(repo, urev)
            repo.dirstate.write(repo.currenttransaction())

        repair.strip(ui, repo, revs, backup)

        repomarks = repo._bookmarks
        if bookmarks:
            with repo.transaction('strip') as tr:
                if repo._activebookmark in bookmarks:
                    bookmarksmod.deactivate(repo)
                for bookmark in bookmarks:
                    del repomarks[bookmark]
                repomarks.recordchange(tr)
            for bookmark in sorted(bookmarks):
                ui.write(_("bookmark '%s' deleted\n") % bookmark)
    finally:
        release(lock, wlock)
Exemplo n.º 9
0
def switch_branch(ui, repo, branch, **opts):
    """Switch to the named branch"""
    if branch not in repo.branchtags():
        ui.warn("Branch %s does not exist! (use 'hg branches' to get a list of branches)\n" % branch)
        return
    curr = repo[None].branch()
    if branch == curr:
        ui.status("Already on branch %s\n" % branch)
        return
    hg.clean(repo, branch)
Exemplo n.º 10
0
    def clean(self, rev=None):
        '''Bring workspace up to REV (or tip) forcefully (discarding in
        progress changes)'''

        if rev != None:
            rev = self.repo.lookup(rev)
        else:
            rev = self.repo.changelog.tip()

        hg.clean(self.repo, rev, show_stats=False)
Exemplo n.º 11
0
    def clean(self, rev=None):
        '''Bring workspace up to REV (or tip) forcefully (discarding in
        progress changes)'''
        if rev != None:
            rev = self.repo.lookup(rev)
        else:
            rev = self.repo.changelog.tip()

        wlock = self.repo.wlock()
        hg.clean(self.repo, rev, show_stats=False)
Exemplo n.º 12
0
    def commitchanges(self, changes, parent='tip', message='automated test'):
        """Commit changes to mercurial directory

        'changes' is a sequence of tuples (source, dest, data). It can look
        like:
        - (source, source, data) to set source content to data
        - (source, dest, None) to set dest content to source one, and mark it as
        copied from source.
        - (source, dest, data) to set dest content to data, and mark it as copied
        from source.
        - (source, None, None) to remove source.
        """
        repo = self.repo
        if isinstance(parent, int):
            parentctx = repo[parent]
        else:
            parentctx = revsymbol(repo, parent)

        changed, removed = [], []
        for source, dest, newdata in changes:
            if dest is None:
                removed.append(source)
            else:
                changed.append(dest)

        def filectxfn(repo, memctx, path):
            if path in removed:
                return compathacks.filectxfn_deleted(memctx, path)
            entry = [e for e in changes if path == e[1]][0]
            source, dest, newdata = entry
            if newdata is None:
                newdata = parentctx[source].data()
            copied = None
            if source != dest:
                copied = source
            return compathacks.makememfilectx(repo,
                                              memctx=memctx,
                                              path=dest,
                                              data=newdata,
                                              islink=False,
                                              isexec=False,
                                              copied=copied)

        ctx = context.memctx(repo,
                             (parentctx.node(), node.nullid),
                             message,
                             changed + removed,
                             filectxfn,
                             'an_author',
                             '2008-10-07 20:59:48 -0500',
                             {'branch': parentctx.branch()})
        nodeid = repo.commitctx(ctx)
        repo = self.repo
        hg.clean(repo, nodeid)
        return nodeid
Exemplo n.º 13
0
 def cleanup(self, repo, pats=[], opts={}):
     '''removes all changes from the working copy and makes it so
     there isn't a patch applied'''
     node = repo.dirstate.parents()[0]
     if not pats and not opts.get('include') and not opts.get('exclude'):
         hg.clean(repo, node, False)
     else:
         opts['date'] = None
         opts['all'] = True # Just to trick revert
         opts['rev'] = node
         commands.revert(self.ui, repo, *pats, **opts)
     self.applied = ''
     self.persiststate()
Exemplo n.º 14
0
def dosplit(ui, repo, tr, ctx, opts):
    committed = []  # [ctx]

    # Set working parent to ctx.p1(), and keep working copy as ctx's content
    if ctx.node() != repo.dirstate.p1():
        hg.clean(repo, ctx.node(), show_stats=False)
    with repo.dirstate.parentchange():
        scmutil.movedirstate(repo, ctx.p1())

    # Any modified, added, removed, deleted result means split is incomplete
    def incomplete(repo):
        st = repo.status()
        return any((st.modified, st.added, st.removed, st.deleted))

    # Main split loop
    while incomplete(repo):
        if committed:
            header = _(b'HG: Splitting %s. So far it has been split into:\n'
                       ) % short(ctx.node())
            # We don't want color codes in the commit message template, so
            # disable the label() template function while we render it.
            with ui.configoverride({(b'templatealias', b'label(l,x)'): b"x"},
                                   b'split'):
                for c in committed:
                    summary = cmdutil.format_changeset_summary(ui, c, b'split')
                    header += _(b'HG: - %s\n') % summary
            header += _(
                b'HG: Write commit message for the next split changeset.\n')
        else:
            header = _(b'HG: Splitting %s. Write commit message for the '
                       b'first split changeset.\n') % short(ctx.node())
        opts.update({
            b'edit': True,
            b'interactive': True,
            b'message': header + ctx.description(),
        })
        commands.commit(ui, repo, **pycompat.strkwargs(opts))
        newctx = repo[b'.']
        committed.append(newctx)

    if not committed:
        raise error.InputError(_(b'cannot split an empty revision'))

    scmutil.cleanupnodes(
        repo,
        {ctx.node(): [c.node() for c in committed]},
        operation=b'split',
        fixphase=True,
    )

    return committed[-1]
Exemplo n.º 15
0
    def commitchanges(self, changes, parent='tip', message='automated test'):
        """Commit changes to mercurial directory

        'changes' is a sequence of tuples (source, dest, data). It can look
        like:
        - (source, source, data) to set source content to data
        - (source, dest, None) to set dest content to source one, and mark it as
        copied from source.
        - (source, dest, data) to set dest content to data, and mark it as copied
        from source.
        - (source, None, None) to remove source.
        """
        repo = self.repo
        parentctx = repo[parent]

        changed, removed = [], []
        for source, dest, newdata in changes:
            if dest is None:
                removed.append(source)
            else:
                changed.append(dest)

        def filectxfn(repo, memctx, path):
            if path in removed:
                return compathacks.filectxfn_deleted(memctx, path)
            entry = [e for e in changes if path == e[1]][0]
            source, dest, newdata = entry
            if newdata is None:
                newdata = parentctx[source].data()
            copied = None
            if source != dest:
                copied = source
            return compathacks.makememfilectx(repo,
                                              path=dest,
                                              data=newdata,
                                              islink=False,
                                              isexec=False,
                                              copied=copied)

        ctx = context.memctx(repo,
                             (parentctx.node(), node.nullid),
                             message,
                             changed + removed,
                             filectxfn,
                             'an_author',
                             '2008-10-07 20:59:48 -0500')
        nodeid = repo.commitctx(ctx)
        repo = self.repo
        hg.clean(repo, nodeid)
        return nodeid
Exemplo n.º 16
0
    def strip(self, repo, revs, update=True, backup="all", force=None):
        wlock = lock = None
        try:
            wlock = repo.wlock()
            lock = repo.lock()

            if update:
                self.checklocalchanges(repo, force=force, refresh=False)
                urev = self.qparents(repo, revs[0])
                hg.clean(repo, urev)
                repo.dirstate.write()

            repair.strip(self.ui, repo, revs, backup)
        finally:
            release(lock, wlock)
Exemplo n.º 17
0
def update(ui, args, repo, clean=False, **opts):
    """update to a specified Subversion revision number
    """

    assert len(args) == 1
    rev = int(args[0])
    meta = repo.svnmeta()

    answers = []
    for k, v in meta.revmap.iteritems():
        if k[0] == rev:
            answers.append((v, k[1]))

    if len(answers) == 1:
        if clean:
            return hg.clean(repo, answers[0][0])
        return hg.update(repo, answers[0][0])
    elif len(answers) == 0:
        ui.status('revision %s did not produce an hg revision\n' % rev)
        return 1
    else:
        ui.status('ambiguous revision!\n')
        revs = ['%s on %s' % (node.hex(a[0]), a[1]) for a in answers] + ['']
        ui.status('\n'.join(revs))
    return 1
Exemplo n.º 18
0
    def process_revision(revision):
        # change to revision and create metrics
        print 'Processing revision : %s' % revision
        # change repository to revision
        hg.clean(repo, revision)

        # collect files to process
        exclude = re.compile('|'.join([translate(ep) 
            for ep in exclude_pattern]))
        files = [os.path.relpath(os.path.join(dp, name), base) for
            (dp, dn, fn) in os.walk(base)
            for name in fn 
            if not exclude.match(os.path.relpath(os.path.join(dp, name), base))]
        print 'Number of files to process : %d' % len(files)

        return create_metrics(files)
Exemplo n.º 19
0
def update(ui, args, repo, clean=False, **opts):
    """update to a specified Subversion revision number
    """

    try:
        rev = int(args[0])
    except IndexError:
        raise error.CommandError('svn',
                                 "no revision number specified for 'update'")
    except ValueError:
        raise error.Abort("'%s' is not a valid Subversion revision number"
                          % args[0])

    meta = repo.svnmeta()

    answers = []
    for k, v in meta.revmap.iteritems():
        if k[0] == rev:
            answers.append((v, k[1]))

    if len(answers) == 1:
        if clean:
            return hg.clean(repo, answers[0][0])
        return hg.update(repo, answers[0][0])
    elif len(answers) == 0:
        ui.status('revision %s did not produce an hg revision\n' % rev)
        return 1
    else:
        ui.status('ambiguous revision!\n')
        revs = ['%s on %s' % (node.hex(a[0]), a[1]) for a in answers] + ['']
        ui.status('\n'.join(revs))
    return 1
Exemplo n.º 20
0
def update(ui, args, repo, clean=False, **opts):
    """update to a specified Subversion revision number
    """

    try:
        rev = int(args[0])
    except IndexError:
        raise error.CommandError('svn',
                                 "no revision number specified for 'update'")
    except ValueError:
        raise error.Abort("'%s' is not a valid Subversion revision number"
                          % args[0])

    meta = repo.svnmeta()

    answers = []
    for k, v in meta.revmap.iteritems():
        if k[0] == rev:
            answers.append((v, k[1]))

    if len(answers) == 1:
        if clean:
            return hg.clean(repo, answers[0][0])
        return hg.update(repo, answers[0][0])
    elif len(answers) == 0:
        ui.status('revision %s did not produce an hg revision\n' % rev)
        return 1
    else:
        ui.status('ambiguous revision!\n')
        revs = ['%s on %s' % (node.hex(a[0]), a[1]) for a in answers] + ['']
        ui.status('\n'.join(revs))
    return 1
Exemplo n.º 21
0
def strip(ui, repo, revs, update=True, backup="all", force=None):
    wlock = lock = None
    try:
        wlock = repo.wlock()
        lock = repo.lock()

        if update:
            checklocalchanges(repo, force=force)
            urev, p2 = repo.changelog.parents(revs[0])
            if p2 != nullid and p2 in [x.node for x in repo.mq.applied]:
                urev = p2
            hg.clean(repo, urev)
            repo.dirstate.write()

        repair.strip(ui, repo, revs, backup)
    finally:
        release(lock, wlock)
Exemplo n.º 22
0
 def postincoming(other, modheads):
     if modheads == 0:
         return 0
     if modheads == 1:
         return hg.clean(repo, repo.changelog.tip())
     newheads = repo.heads(parent)
     newchildren = [n for n in repo.heads(parent) if n != parent]
     newparent = parent
     if newchildren:
         newparent = newchildren[0]
         hg.clean(repo, newparent)
     newheads = [n for n in repo.heads() if n != newparent]
     if len(newheads) > 1:
         ui.status(_('not merging with %d other new heads '
                     '(use "hg heads" and "hg merge" to merge them)') %
                   (len(newheads) - 1))
         return
     err = False
     if newheads:
         # By default, we consider the repository we're pulling
         # *from* as authoritative, so we merge our changes into
         # theirs.
         if opts['switch_parent']:
             firstparent, secondparent = newparent, newheads[0]
         else:
             firstparent, secondparent = newheads[0], newparent
             ui.status(_('updating to %d:%s\n') %
                       (repo.changelog.rev(firstparent),
                        short(firstparent)))
         hg.clean(repo, firstparent)
         ui.status(_('merging with %d:%s\n') %
                   (repo.changelog.rev(secondparent), short(secondparent)))
         err = hg.merge(repo, secondparent, remind=False)
     if not err:
         mod, add, rem = repo.status()[:3]
         message = (cmdutil.logmessage(opts) or
                    (_('Automated merge with %s') %
                     util.removeauth(other.url())))
         force_editor = opts.get('force_editor') or opts.get('edit')
         n = repo.commit(mod + add + rem, message,
                         opts['user'], opts['date'], force=True,
                         force_editor=force_editor)
         ui.status(_('new changeset %d:%s merges remote changes '
                     'with local\n') % (repo.changelog.rev(n),
                                        short(n)))
Exemplo n.º 23
0
def dosplit(ui, repo, tr, ctx, opts):
    committed = []  # [ctx]

    # Set working parent to ctx.p1(), and keep working copy as ctx's content
    # NOTE: if we can have "update without touching working copy" API, the
    # revert step could be cheaper.
    hg.clean(repo, ctx.p1().node(), show_stats=False)
    parents = repo.changelog.parents(ctx.node())
    ui.pushbuffer()
    cmdutil.revert(ui, repo, ctx, parents)
    ui.popbuffer()  # discard "reverting ..." messages

    # Any modified, added, removed, deleted result means split is incomplete
    incomplete = lambda repo: any(repo.status()[:4])

    # Main split loop
    while incomplete(repo):
        if committed:
            header = (_('HG: Splitting %s. So far it has been split into:\n') %
                      short(ctx.node()))
            for c in committed:
                firstline = c.description().split('\n', 1)[0]
                header += _('HG: - %s: %s\n') % (short(c.node()), firstline)
            header += _('HG: Write commit message for the next split '
                        'changeset.\n')
        else:
            header = _('HG: Splitting %s. Write commit message for the '
                       'first split changeset.\n') % short(ctx.node())
        opts.update({
            'edit': True,
            'interactive': True,
            'message': header + ctx.description(),
        })
        commands.commit(ui, repo, **pycompat.strkwargs(opts))
        newctx = repo['.']
        committed.append(newctx)

    if not committed:
        raise error.Abort(_('cannot split an empty revision'))

    scmutil.cleanupnodes(repo, {ctx.node(): [c.node() for c in committed]},
                         operation='split',
                         fixphase=True)

    return committed[-1]
Exemplo n.º 24
0
def dosplit(ui, repo, tr, ctx, opts):
    committed = []  # [ctx]

    # Set working parent to ctx.p1(), and keep working copy as ctx's content
    if ctx.node() != repo.dirstate.p1():
        hg.clean(repo, ctx.node(), show_stats=False)
    with repo.dirstate.parentchange():
        scmutil.movedirstate(repo, ctx.p1())

    # Any modified, added, removed, deleted result means split is incomplete
    incomplete = lambda repo: any(repo.status()[:4])

    # Main split loop
    while incomplete(repo):
        if committed:
            header = _(b'HG: Splitting %s. So far it has been split into:\n'
                       ) % short(ctx.node())
            for c in committed:
                firstline = c.description().split(b'\n', 1)[0]
                header += _(b'HG: - %s: %s\n') % (short(c.node()), firstline)
            header += _(
                b'HG: Write commit message for the next split changeset.\n')
        else:
            header = _(b'HG: Splitting %s. Write commit message for the '
                       b'first split changeset.\n') % short(ctx.node())
        opts.update({
            b'edit': True,
            b'interactive': True,
            b'message': header + ctx.description(),
        })
        commands.commit(ui, repo, **pycompat.strkwargs(opts))
        newctx = repo[b'.']
        committed.append(newctx)

    if not committed:
        raise error.Abort(_(b'cannot split an empty revision'))

    scmutil.cleanupnodes(
        repo,
        {ctx.node(): [c.node() for c in committed]},
        operation=b'split',
        fixphase=True,
    )

    return committed[-1]
Exemplo n.º 25
0
    def load(self, source):
        wlock = self.im.repo.wlock()
        lock = self.im.repo.lock()

        tf = tarfile.open(source, 'r')
        contents = tf.getnames()
        # tarfile normalizes path separators to '/'
        statusfile = '.hg/imerge/status'
        if statusfile not in contents:
            raise InvalidStateFileException('no status file')

        tf.extract(statusfile, self.im.repo.root)
        p1, p2 = self.im.load()
        if self.im.repo.dirstate.parents()[0] != p1.node():
            hg.clean(self.im.repo, p1.node())
        self.im.start(p2.node())
        for tarinfo in tf:
            tf.extract(tarinfo, self.im.repo.root)
        self.im.load()
Exemplo n.º 26
0
def strip(ui, repo, revs, update=True, backup="all", force=None):
    wlock = lock = None
    try:
        wlock = repo.wlock()
        lock = repo.lock()

        if update:
            checklocalchanges(repo, force=force)
            urev, p2 = repo.changelog.parents(revs[0])
            if (util.safehasattr(repo, 'mq') and
                p2 != nullid
                and p2 in [x.node for x in repo.mq.applied]):
                urev = p2
            hg.clean(repo, urev)
            repo.dirstate.write()

        repair.strip(ui, repo, revs, backup)
    finally:
        release(lock, wlock)
Exemplo n.º 27
0
    def test_push_executable_file(self):
        self.test_push_to_default(commit=True)
        repo = self.repo

        def file_callback(repo, memctx, path):
            if path == 'gamma':
                return compathacks.makememfilectx(repo,
                                                  memctx=memctx,
                                                  path=path,
                                                  data='foo',
                                                  islink=False,
                                                  isexec=True,
                                                  copied=False)
            raise IOError(errno.EINVAL, 'Invalid operation: ' + path)

        ctx = context.memctx(repo,
                             (revsymbol(repo, 'tip').node(), node.nullid),
                             'message', [
                                 'gamma',
                             ], file_callback, 'author',
                             '2008-10-29 21:26:00 -0500', {
                                 'branch': 'default',
                             })
        new_hash = repo.commitctx(ctx)
        hg.clean(repo, revsymbol(repo, 'tip').node())
        self.pushrevisions()
        tip = revsymbol(self.repo, 'tip')
        self.assertNotEqual(tip.node(), new_hash)
        self.assert_('@' in revsymbol(self.repo, 'tip').user())
        self.assertEqual(tip['gamma'].flags(), 'x')
        self.assertEqual(tip['gamma'].data(), 'foo')
        self.assertEqual(
            sorted([
                x for x in tip.manifest().keys() if 'x' not in tip[x].flags()
            ]), [
                'adding_file',
                'alpha',
                'beta',
            ])
Exemplo n.º 28
0
    def mergeone(self, repo, mergeq, head, patch, rev, diffopts):
        # first try just applying the patch
        (err, n) = self.apply(repo, [patch], update_status=False,
                              strict=True, merge=rev)

        if err == 0:
            return (err, n)

        if n is None:
            raise util.Abort(_("apply failed for patch %s") % patch)

        self.ui.warn(_("patch didn't work out, merging %s\n") % patch)

        # apply failed, strip away that rev and merge.
        hg.clean(repo, head)
        self.strip(repo, [n], update=False, backup='strip')

        ctx = repo[rev]
        ret = hg.merge(repo, rev)
        if ret:
            raise util.Abort(_("update returned %d") % ret)
        n = newcommit(repo, None, ctx.description(), ctx.user(), force=True)
        if n is None:
            raise util.Abort(_("repo commit failed"))
        try:
            ph = patchheader(mergeq.join(patch), self.plainmode)
        except Exception:
            raise util.Abort(_("unable to read %s") % patch)

        diffopts = self.patchopts(diffopts, patch)
        patchf = self.opener(patch, "w")
        comments = str(ph)
        if comments:
            patchf.write(comments)
        self.printdiff(repo, diffopts, head, n, fp=patchf)
        patchf.close()
        self.removeundo(repo)
        return (0, n)
Exemplo n.º 29
0
Arquivo: hg.py Projeto: lelit/tailor
    def _getRepo(self):
        try:
            return self._hg
        except AttributeError:
            # dirstate walker uses simple string comparison between
            # repo root and os.getcwd, so root should be canonified.
            from os.path import realpath

            ui = self._getUI()
            self._hg = hg.repository(ui=ui, path=realpath(self.repository.basedir),
                                     create=False)
            # Pick up repository-specific UI settings.
            self._ui = self._hg.ui

            # 0.9.5 repos does not have update()...
            if not hasattr(self._hg, 'update'):
                # Use clean(), to force a clean merge clobbering local changes
                self._hg.update = lambda n: hg.clean(self._hg, n)

            return self._hg
Exemplo n.º 30
0
def doMerge(ui, repo, branch):
  """ Merge from the given branch into the working directory. """

  # Try the merge. Don't hide the output as merge sometimes needs to ask the user questions.
  if tryCommand(ui, "merge %s" % quoteBranch(branch), lambda:hg.merge(repo, revsymbol(repo, branch)), showOutput = True):
    res = ui.prompt("Merge failed! Do you want to fix it manually? (if not, will return to clean state):", default="y")
    if res.lower() != "y" and res.lower() != "yes":
      ui.status("Getting back to clean state...\n")
      tryCommand(ui, "update --clean", lambda:hg.clean(repo, repo.dirstate.branch()))
    else:
      ui.status("Ok, leaving directory in partly merged state. To finish:\n")
      ui.status("  $ hg resolve --list        # list conflicting files\n")
      ui.status("  ...fix fix fix...\n")
      ui.status("  $ hg resolve --mark --all  # shortcut: resolve -am\n")
      ui.status("  $ hg commit\n")
      ui.status("Or, to abandon the merge:\n")
      ui.status("  $ hg update --clean\n")
    return 1

  return 0
Exemplo n.º 31
0
    def _getRepo(self):
        try:
            return self._hg
        except AttributeError:
            # dirstate walker uses simple string comparison between
            # repo root and os.getcwd, so root should be canonified.
            from os.path import realpath

            ui = self._getUI()
            self._hg = hg.repository(ui=ui,
                                     path=realpath(self.repository.basedir),
                                     create=False)
            # Pick up repository-specific UI settings.
            self._ui = self._hg.ui

            # 0.9.5 repos does not have update()...
            if not hasattr(self._hg, 'update'):
                # Use clean(), to force a clean merge clobbering local changes
                self._hg.update = lambda n: hg.clean(self._hg, n)

            return self._hg
Exemplo n.º 32
0
def fetch(ui, repo, source="default", **opts):
    """pull changes from a remote repository, merge new changes if needed.

    This finds all changes from the repository at the specified path
    or URL and adds them to the local repository.

    If the pulled changes add a new branch head, the head is
    automatically merged, and the result of the merge is committed.
    Otherwise, the working directory is updated to include the new
    changes.

    When a merge is needed, the working directory is first updated to
    the newly pulled changes. Local changes are then merged into the
    pulled changes. To switch the merge order, use --switch-parent.

    See :hg:`help dates` for a list of formats valid for -d/--date.

    Returns 0 on success.
    """

    date = opts.get("date")
    if date:
        opts["date"] = util.parsedate(date)

    parent, p2 = repo.dirstate.parents()
    branch = repo.dirstate.branch()
    try:
        branchnode = repo.branchtip(branch)
    except error.RepoLookupError:
        branchnode = None
    if parent != branchnode:
        raise util.Abort(_("working dir not at branch tip " '(use "hg update" to check out branch tip)'))

    if p2 != nullid:
        raise util.Abort(_("outstanding uncommitted merge"))

    wlock = lock = None
    try:
        wlock = repo.wlock()
        lock = repo.lock()
        mod, add, rem, del_ = repo.status()[:4]

        if mod or add or rem:
            raise util.Abort(_("outstanding uncommitted changes"))
        if del_:
            raise util.Abort(_("working directory is missing some files"))
        bheads = repo.branchheads(branch)
        bheads = [head for head in bheads if len(repo[head].children()) == 0]
        if len(bheads) > 1:
            raise util.Abort(_("multiple heads in this branch " '(use "hg heads ." and "hg merge" to merge)'))

        other = hg.peer(repo, opts, ui.expandpath(source))
        ui.status(_("pulling from %s\n") % util.hidepassword(ui.expandpath(source)))
        revs = None
        if opts["rev"]:
            try:
                revs = [other.lookup(rev) for rev in opts["rev"]]
            except error.CapabilityError:
                err = _("other repository doesn't support revision lookup, " "so a rev cannot be specified.")
                raise util.Abort(err)

        # Are there any changes at all?
        modheads = repo.pull(other, heads=revs)
        if modheads == 0:
            return 0

        # Is this a simple fast-forward along the current branch?
        newheads = repo.branchheads(branch)
        newchildren = repo.changelog.nodesbetween([parent], newheads)[2]
        if len(newheads) == 1 and len(newchildren):
            if newchildren[0] != parent:
                return hg.update(repo, newchildren[0])
            else:
                return 0

        # Are there more than one additional branch heads?
        newchildren = [n for n in newchildren if n != parent]
        newparent = parent
        if newchildren:
            newparent = newchildren[0]
            hg.clean(repo, newparent)
        newheads = [n for n in newheads if n != newparent]
        if len(newheads) > 1:
            ui.status(
                _("not merging with %d other new branch heads " '(use "hg heads ." and "hg merge" to merge them)\n')
                % (len(newheads) - 1)
            )
            return 1

        if not newheads:
            return 0

        # Otherwise, let's merge.
        err = False
        if newheads:
            # By default, we consider the repository we're pulling
            # *from* as authoritative, so we merge our changes into
            # theirs.
            if opts["switch_parent"]:
                firstparent, secondparent = newparent, newheads[0]
            else:
                firstparent, secondparent = newheads[0], newparent
                ui.status(_("updating to %d:%s\n") % (repo.changelog.rev(firstparent), short(firstparent)))
            hg.clean(repo, firstparent)
            ui.status(_("merging with %d:%s\n") % (repo.changelog.rev(secondparent), short(secondparent)))
            err = hg.merge(repo, secondparent, remind=False)

        if not err:
            # we don't translate commit messages
            message = cmdutil.logmessage(ui, opts) or ("Automated merge with %s" % util.removeauth(other.url()))
            editor = cmdutil.commiteditor
            if opts.get("force_editor") or opts.get("edit"):
                editor = cmdutil.commitforceeditor
            n = repo.commit(message, opts["user"], opts["date"], editor=editor)
            ui.status(
                _("new changeset %d:%s merges remote changes " "with local\n") % (repo.changelog.rev(n), short(n))
            )

        return err

    finally:
        release(lock, wlock)
Exemplo n.º 33
0
def histedit(ui, repo, *parent, **opts):
    """hg histedit <parent>
    """
    # TODO only abort if we try and histedit mq patches, not just
    # blanket if mq patches are applied somewhere
    mq = getattr(repo, 'mq', None)
    if mq and mq.applied:
        raise util.Abort(_('source has mq patches applied'))

    parent = list(parent) + opts.get('rev', [])
    if opts.get('outgoing'):
        if len(parent) > 1:
            raise util.Abort('only one repo argument allowed with --outgoing')
        elif parent:
            parent = parent[0]

        dest = ui.expandpath(parent or 'default-push', parent or 'default')
        dest, revs = hg.parseurl(dest, None)[:2]
        if isinstance(revs, tuple):
            # hg >= 1.6
            revs, checkout = hg.addbranchrevs(repo, repo, revs, None)
            other = hg.repository(hg.remoteui(repo, opts), dest)
            # hg >= 1.9
            findoutgoing = getattr(discovery, 'findoutgoing', None)
            if findoutgoing is None:
                if getattr(discovery, 'outgoing', None) is not None:

                    def findoutgoing(repo, other, force=False):
                        out = discovery.findcommonoutgoing(repo,
                                                           other, [],
                                                           force=force)
                        return out.missing[0:1]
                else:
                    # hg 1.9 and 2.0
                    def findoutgoing(repo, other, force=False):
                        common, outheads = discovery.findcommonoutgoing(
                            repo, other, [], force=force)
                        return repo.changelog.findmissing(common,
                                                          outheads)[0:1]
        else:
            other = hg.repository(ui, dest)

            def findoutgoing(repo, other, force=False):
                return repo.findoutgoing(other, force=force)

        if revs:
            revs = [repo.lookup(rev) for rev in revs]

        ui.status(_('comparing with %s\n') % hidepassword(dest))
        parent = findoutgoing(repo, other, force=opts.get('force'))
    else:
        if opts.get('force'):
            raise util.Abort('--force only allowed with --outgoing')

    if opts.get('continue', False):
        if len(parent) != 0:
            raise util.Abort('no arguments allowed with --continue')
        (
            parentctxnode,
            created,
            replaced,
            tmpnodes,
            existing,
            rules,
            keep,
            tip,
        ) = readstate(repo)
        currentparent, wantnull = repo.dirstate.parents()
        parentctx = repo[parentctxnode]
        # discover any nodes the user has added in the interim
        newchildren = [
            c for c in parentctx.children() if c.node() not in existing
        ]
        action, currentnode = rules.pop(0)
        while newchildren:
            if action in [
                    'f',
                    'fold',
            ]:
                tmpnodes.extend([n.node() for n in newchildren])
            else:
                created.extend([n.node() for n in newchildren])
            newchildren = filter(
                lambda x: x.node() not in existing,
                reduce(lambda x, y: x + y,
                       map(lambda r: r.children(), newchildren)))
        m, a, r, d = repo.status()[:4]
        oldctx = repo[currentnode]
        message = oldctx.description()
        if action in ('e', 'edit', 'm', 'mess'):
            message = ui.edit(message, ui.username())
        elif action in (
                'f',
                'fold',
        ):
            message = 'fold-temp-revision %s' % currentnode
        new = None
        if m or a or r or d:
            new = repo.commit(text=message,
                              user=oldctx.user(),
                              date=oldctx.date(),
                              extra=oldctx.extra())

        if action in ('f', 'fold'):
            if new:
                tmpnodes.append(new)
            else:
                new = newchildren[-1]
            (
                parentctx,
                created_,
                replaced_,
                tmpnodes_,
            ) = finishfold(ui, repo, parentctx, oldctx, new, opts, newchildren)
            replaced.extend(replaced_)
            created.extend(created_)
            tmpnodes.extend(tmpnodes_)
        elif action not in ('d', 'drop'):
            if new != oldctx.node():
                replaced.append(oldctx.node())
            if new:
                if new != oldctx.node():
                    created.append(new)
                parentctx = repo[new]

    elif opts.get('abort', False):
        if len(parent) != 0:
            raise util.Abort('no arguments allowed with --abort')
        (
            parentctxnode,
            created,
            replaced,
            tmpnodes,
            existing,
            rules,
            keep,
            tip,
        ) = readstate(repo)
        ui.debug('restore wc to old tip %s\n' % node.hex(tip))
        hg.clean(repo, tip)
        ui.debug('should strip created nodes %s\n' %
                 ', '.join([node.hex(n)[:12] for n in created]))
        ui.debug('should strip temp nodes %s\n' %
                 ', '.join([node.hex(n)[:12] for n in tmpnodes]))
        for nodes in (
                created,
                tmpnodes,
        ):
            for n in reversed(nodes):
                try:
                    repair.strip(ui, repo, n)
                except error.LookupError:
                    pass
        os.unlink(os.path.join(repo.path, 'histedit-state'))
        return
    else:
        bailifchanged(repo)
        if os.path.exists(os.path.join(repo.path, 'histedit-state')):
            raise util.Abort('history edit already in progress, try '
                             '--continue or --abort')

        tip, empty = repo.dirstate.parents()

        if len(parent) != 1:
            raise util.Abort('requires exactly one parent revision')
        parent = _revsingle(repo, parent[0]).node()

        keep = opts.get('keep', False)
        revs = between(repo, parent, tip, keep)

        ctxs = [repo[r] for r in revs]
        existing = [r.node() for r in ctxs]
        rules = opts.get('commands', '')
        if not rules:
            rules = '\n'.join([makedesc(c) for c in ctxs])
            rules += editcomment % (
                node.hex(parent)[:12],
                node.hex(tip)[:12],
            )
            rules = ui.edit(rules, ui.username())
            # Save edit rules in .hg/histedit-last-edit.txt in case
            # the user needs to ask for help after something
            # surprising happens.
            f = open(repo.join('histedit-last-edit.txt'), 'w')
            f.write(rules)
            f.close()
        else:
            f = open(rules)
            rules = f.read()
            f.close()
        rules = [
            l for l in (r.strip() for r in rules.splitlines())
            if l and not l[0] == '#'
        ]
        rules = verifyrules(rules, repo, ctxs)

        parentctx = repo[parent].parents()[0]
        keep = opts.get('keep', False)
        replaced = []
        tmpnodes = []
        created = []

    while rules:
        writestate(repo, parentctx.node(), created, replaced, tmpnodes,
                   existing, rules, keep, tip)
        action, ha = rules.pop(0)
        (
            parentctx,
            created_,
            replaced_,
            tmpnodes_,
        ) = actiontable[action](ui, repo, parentctx, ha, opts)
        created.extend(created_)
        replaced.extend(replaced_)
        tmpnodes.extend(tmpnodes_)

    hg.update(repo, parentctx.node())

    if not keep:
        ui.debug('should strip replaced nodes %s\n' %
                 ', '.join([node.hex(n)[:12] for n in replaced]))
        for n in sorted(replaced,
                        lambda x, y: cmp(repo[x].rev(), repo[y].rev())):
            try:
                repair.strip(ui, repo, n)
            except error.LookupError:
                pass

    ui.debug('should strip temp nodes %s\n' %
             ', '.join([node.hex(n)[:12] for n in tmpnodes]))
    for n in reversed(tmpnodes):
        try:
            repair.strip(ui, repo, n)
        except error.LookupError:
            pass
    os.unlink(os.path.join(repo.path, 'histedit-state'))
Exemplo n.º 34
0
 def use_version(self, version):
     if self.has_changed():
         raise UncommittedModificationsError(self.status())
     hg.clean(self.repository._repository, version)
Exemplo n.º 35
0
def histedit(ui, repo, *parent, **opts):
    """hg histedit <parent>
    """
    if opts.get('outgoing'):
        if len(parent) > 1:
            raise util.Abort('only one repo argument allowed with --outgoing')
        elif parent:
            parent = parent[0]

        dest, revs, checkout = hg.parseurl(
            ui.expandpath(parent or 'default-push', parent or 'default'), ['tip'])
        if revs:
            revs = [repo.lookup(rev) for rev in revs]

        other = hg.repository(ui, dest)
        ui.status(_('comparing with %s\n') % url.hidepassword(dest))
        parent = repo.findoutgoing(other, force=opts.get('force'))
    else:
        if opts.get('force'):
            raise util.Abort('--force only allowed with --outgoing')

    if opts.get('continue', False):
        if len(parent) != 0:
            raise util.Abort('no arguments allowed with --continue')
        (parentctxnode, created, replaced,
         tmpnodes, existing, rules, keep, tip, ) = readstate(repo)
        currentparent, wantnull = repo.dirstate.parents()
        parentctx = repo[parentctxnode]
        # discover any nodes the user has added in the interim
        newchildren = [c for c in parentctx.children()
                       if c.node() not in existing]
        action, currentnode = rules.pop(0)
        while newchildren:
            if action in ['f', 'fold', ]:
                tmpnodes.extend([n.node() for n in newchildren])
            else:
                created.extend([n.node() for n in newchildren])
            newchildren = filter(lambda x: x.node() not in existing,
                                 reduce(lambda x, y: x + y,
                                        map(lambda r: r.children(),
                                            newchildren)))
        m, a, r, d = repo.status()[:4]
        oldctx = repo[currentnode]
        message = oldctx.description()
        if action in ('e', 'edit', ):
            message = ui.edit(message, ui.username())
        elif action in ('f', 'fold', ):
            message = 'fold-temp-revision %s' % currentnode
        new = None
        if m or a or r or d:
            new = repo.commit(text=message, user=oldctx.user(), date=oldctx.date(),
                              extra=oldctx.extra())

        if action in ('e', 'edit', 'p', 'pick', ):
            replaced.append(oldctx.node())
            if new:
                created.append(new)
                parentctx = repo[new]
        else: # fold
            if new:
                tmpnodes.append(new)
            else:
                new = newchildren[-1]
            (parentctx, created_,
             replaced_, tmpnodes_, ) = finishfold(ui, repo,
                                                  parentctx, oldctx, new,
                                                  opts, newchildren)
            replaced.extend(replaced_)
            created.extend(created_)
            tmpnodes.extend(tmpnodes_)

    elif opts.get('abort', False):
        if len(parent) != 0:
            raise util.Abort('no arguments allowed with --abort')
        (parentctxnode, created, replaced, tmpnodes,
         existing, rules, keep, tip, ) = readstate(repo)
        ui.debug('restore wc to old tip %s\n' % node.hex(tip))
        hg.clean(repo, tip)
        ui.debug('should strip created nodes %s\n' %
                 ', '.join([node.hex(n)[:12] for n in created]))
        ui.debug('should strip temp nodes %s\n' %
                 ', '.join([node.hex(n)[:12] for n in tmpnodes]))
        for nodes in (created, tmpnodes, ):
            for n in reversed(nodes):
                try:
                    repair.strip(ui, repo, n)
                except error.LookupError:
                    pass
        os.unlink(os.path.join(repo.path, 'histedit-state'))
        return
    else:
        cmdutil.bail_if_changed(repo)
        if os.path.exists(os.path.join(repo.path, 'histedit-state')):
            raise util.Abort('history edit already in progress, try --continue or --abort')

        tip, empty = repo.dirstate.parents()


        if len(parent) != 1:
            raise util.Abort('requires exactly one parent revision')
        parent = parent[0]

        revs = between(repo, parent, tip)

        ctxs = [repo[r] for r in revs]
        existing = [r.node() for r in ctxs]
        rules = '\n'.join([('pick %s %s' % (c.hex()[:12],
                                         c.description().splitlines()[0]))[:80]
                           for c in ctxs])

        rules += editcomment % (node.hex(parent)[:12], node.hex(tip)[:12], )

        rules = ui.edit(rules, ui.username())

        parentctx = repo[parent].parents()[0]

        rules = [l for l in (r.strip() for r in rules.splitlines()) if l and not l[0] == '#']
        rules = verifyrules(rules, repo, ctxs)
        keep = opts.get('keep', False)
        replaced = []
        tmpnodes = []
        created = []


    while rules:
        writestate(repo, parentctx.node(), created, replaced, tmpnodes, existing,
                   rules, keep, tip)
        action, ha = rules.pop(0)
        (parentctx, created_,
         replaced_, tmpnodes_, ) = actiontable[action](ui, repo,
                                                       parentctx, ha,
                                                       opts)
        created.extend(created_)
        replaced.extend(replaced_)
        tmpnodes.extend(tmpnodes_)

    hg.update(repo, parentctx.node())

    if not keep:
        ui.debug('should strip replaced nodes %s\n' %
                 ', '.join([node.hex(n)[:12] for n in replaced]))
        for n in sorted(replaced, lambda x, y: cmp(repo[x].rev(), repo[y].rev())):
            try:
                repair.strip(ui, repo, n)
            except error.LookupError:
                pass

    ui.debug('should strip temp nodes %s\n' %
             ', '.join([node.hex(n)[:12] for n in tmpnodes]))
    for n in reversed(tmpnodes):
        try:
            repair.strip(ui, repo, n)
        except error.LookupError:
            pass
    os.unlink(os.path.join(repo.path, 'histedit-state'))
Exemplo n.º 36
0
def histedit(ui, repo, *freeargs, **opts):
    """interactively edit changeset history

    This command edits changesets between ANCESTOR and the parent of
    the working directory.

    With --outgoing, this edits changesets not found in the
    destination repository. If URL of the destination is omitted, the
    'default-push' (or 'default') path will be used.

    For safety, this command is aborted, also if there are ambiguous
    outgoing revisions which may confuse users: for example, there are
    multiple branches containing outgoing revisions.

    Use "min(outgoing() and ::.)" or similar revset specification
    instead of --outgoing to specify edit target revision exactly in
    such ambiguous situation. See :hg:`help revsets` for detail about
    selecting revisions.
    """
    # TODO only abort if we try and histedit mq patches, not just
    # blanket if mq patches are applied somewhere
    mq = getattr(repo, "mq", None)
    if mq and mq.applied:
        raise util.Abort(_("source has mq patches applied"))

    # basic argument incompatibility processing
    outg = opts.get("outgoing")
    cont = opts.get("continue")
    abort = opts.get("abort")
    force = opts.get("force")
    rules = opts.get("commands", "")
    revs = opts.get("rev", [])
    goal = "new"  # This invocation goal, in new, continue, abort
    if force and not outg:
        raise util.Abort(_("--force only allowed with --outgoing"))
    if cont:
        if util.any((outg, abort, revs, freeargs, rules)):
            raise util.Abort(_("no arguments allowed with --continue"))
        goal = "continue"
    elif abort:
        if util.any((outg, revs, freeargs, rules)):
            raise util.Abort(_("no arguments allowed with --abort"))
        goal = "abort"
    else:
        if os.path.exists(os.path.join(repo.path, "histedit-state")):
            raise util.Abort(_("history edit already in progress, try " "--continue or --abort"))
        if outg:
            if revs:
                raise util.Abort(_("no revisions allowed with --outgoing"))
            if len(freeargs) > 1:
                raise util.Abort(_("only one repo argument allowed with --outgoing"))
        else:
            revs.extend(freeargs)
            if len(revs) != 1:
                raise util.Abort(_("histedit requires exactly one ancestor revision"))

    if goal == "continue":
        (parentctxnode, rules, keep, topmost, replacements) = readstate(repo)
        parentctx = repo[parentctxnode]
        parentctx, repl = bootstrapcontinue(ui, repo, parentctx, rules, opts)
        replacements.extend(repl)
    elif goal == "abort":
        (parentctxnode, rules, keep, topmost, replacements) = readstate(repo)
        mapping, tmpnodes, leafs, _ntm = processreplacement(repo, replacements)
        ui.debug("restore wc to old parent %s\n" % node.short(topmost))
        # check whether we should update away
        parentnodes = [c.node() for c in repo[None].parents()]
        for n in leafs | set([parentctxnode]):
            if n in parentnodes:
                hg.clean(repo, topmost)
                break
        else:
            pass
        cleanupnode(ui, repo, "created", tmpnodes)
        cleanupnode(ui, repo, "temp", leafs)
        os.unlink(os.path.join(repo.path, "histedit-state"))
        return
    else:
        cmdutil.checkunfinished(repo)
        cmdutil.bailifchanged(repo)

        topmost, empty = repo.dirstate.parents()
        if outg:
            if freeargs:
                remote = freeargs[0]
            else:
                remote = None
            root = findoutgoing(ui, repo, remote, force, opts)
        else:
            root = revs[0]
            root = scmutil.revsingle(repo, root).node()

        keep = opts.get("keep", False)
        revs = between(repo, root, topmost, keep)
        if not revs:
            raise util.Abort(_("%s is not an ancestor of working directory") % node.short(root))

        ctxs = [repo[r] for r in revs]
        if not rules:
            rules = "\n".join([makedesc(c) for c in ctxs])
            rules += "\n\n"
            rules += editcomment % (node.short(root), node.short(topmost))
            rules = ui.edit(rules, ui.username())
            # Save edit rules in .hg/histedit-last-edit.txt in case
            # the user needs to ask for help after something
            # surprising happens.
            f = open(repo.join("histedit-last-edit.txt"), "w")
            f.write(rules)
            f.close()
        else:
            if rules == "-":
                f = sys.stdin
            else:
                f = open(rules)
            rules = f.read()
            f.close()
        rules = [l for l in (r.strip() for r in rules.splitlines()) if l and not l[0] == "#"]
        rules = verifyrules(rules, repo, ctxs)

        parentctx = repo[root].parents()[0]
        keep = opts.get("keep", False)
        replacements = []

    while rules:
        writestate(repo, parentctx.node(), rules, keep, topmost, replacements)
        action, ha = rules.pop(0)
        ui.debug("histedit: processing %s %s\n" % (action, ha))
        actfunc = actiontable[action]
        parentctx, replacement_ = actfunc(ui, repo, parentctx, ha, opts)
        replacements.extend(replacement_)

    hg.update(repo, parentctx.node())

    mapping, tmpnodes, created, ntm = processreplacement(repo, replacements)
    if mapping:
        for prec, succs in mapping.iteritems():
            if not succs:
                ui.debug("histedit: %s is dropped\n" % node.short(prec))
            else:
                ui.debug("histedit: %s is replaced by %s\n" % (node.short(prec), node.short(succs[0])))
                if len(succs) > 1:
                    m = "histedit:                            %s"
                    for n in succs[1:]:
                        ui.debug(m % node.short(n))

    if not keep:
        if mapping:
            movebookmarks(ui, repo, mapping, topmost, ntm)
            # TODO update mq state
        if obsolete._enabled:
            markers = []
            # sort by revision number because it sound "right"
            for prec in sorted(mapping, key=repo.changelog.rev):
                succs = mapping[prec]
                markers.append((repo[prec], tuple(repo[s] for s in succs)))
            if markers:
                obsolete.createmarkers(repo, markers)
        else:
            cleanupnode(ui, repo, "replaced", mapping)

    cleanupnode(ui, repo, "temp", tmpnodes)
    os.unlink(os.path.join(repo.path, "histedit-state"))
    if os.path.exists(repo.sjoin("undo")):
        os.unlink(repo.sjoin("undo"))
Exemplo n.º 37
0
 def use_version(self, version):
     if self.has_changed():
         raise UncommittedModificationsError(self.status())
     hg.clean(self.repository._repository, version)
Exemplo n.º 38
0
def _histedit(ui, repo, state, *freeargs, **opts):
    # TODO only abort if we try and histedit mq patches, not just
    # blanket if mq patches are applied somewhere
    mq = getattr(repo, 'mq', None)
    if mq and mq.applied:
        raise util.Abort(_('source has mq patches applied'))

    # basic argument incompatibility processing
    outg = opts.get('outgoing')
    cont = opts.get('continue')
    abort = opts.get('abort')
    force = opts.get('force')
    rules = opts.get('commands', '')
    revs = opts.get('rev', [])
    goal = 'new' # This invocation goal, in new, continue, abort
    if force and not outg:
        raise util.Abort(_('--force only allowed with --outgoing'))
    if cont:
        if util.any((outg, abort, revs, freeargs, rules)):
            raise util.Abort(_('no arguments allowed with --continue'))
        goal = 'continue'
    elif abort:
        if util.any((outg, revs, freeargs, rules)):
            raise util.Abort(_('no arguments allowed with --abort'))
        goal = 'abort'
    else:
        if os.path.exists(os.path.join(repo.path, 'histedit-state')):
            raise util.Abort(_('history edit already in progress, try '
                               '--continue or --abort'))
        if outg:
            if revs:
                raise util.Abort(_('no revisions allowed with --outgoing'))
            if len(freeargs) > 1:
                raise util.Abort(
                    _('only one repo argument allowed with --outgoing'))
        else:
            revs.extend(freeargs)
            if len(revs) != 1:
                raise util.Abort(
                    _('histedit requires exactly one ancestor revision'))


    replacements = []
    keep = opts.get('keep', False)

    # rebuild state
    if goal == 'continue':
        state = histeditstate(repo)
        state.read()
        state = bootstrapcontinue(ui, state, opts)
    elif goal == 'abort':
        state = histeditstate(repo)
        state.read()
        mapping, tmpnodes, leafs, _ntm = processreplacement(state)
        ui.debug('restore wc to old parent %s\n' % node.short(state.topmost))
        # check whether we should update away
        parentnodes = [c.node() for c in repo[None].parents()]
        for n in leafs | set([state.parentctx.node()]):
            if n in parentnodes:
                hg.clean(repo, state.topmost)
                break
        else:
            pass
        cleanupnode(ui, repo, 'created', tmpnodes)
        cleanupnode(ui, repo, 'temp', leafs)
        state.clear()
        return
    else:
        cmdutil.checkunfinished(repo)
        cmdutil.bailifchanged(repo)

        topmost, empty = repo.dirstate.parents()
        if outg:
            if freeargs:
                remote = freeargs[0]
            else:
                remote = None
            root = findoutgoing(ui, repo, remote, force, opts)
        else:
            rr = list(repo.set('roots(%ld)', scmutil.revrange(repo, revs)))
            if len(rr) != 1:
                raise util.Abort(_('The specified revisions must have '
                    'exactly one common root'))
            root = rr[0].node()

        revs = between(repo, root, topmost, keep)
        if not revs:
            raise util.Abort(_('%s is not an ancestor of working directory') %
                             node.short(root))

        ctxs = [repo[r] for r in revs]
        if not rules:
            rules = '\n'.join([makedesc(c) for c in ctxs])
            rules += '\n\n'
            rules += editcomment % (node.short(root), node.short(topmost))
            rules = ui.edit(rules, ui.username())
            # Save edit rules in .hg/histedit-last-edit.txt in case
            # the user needs to ask for help after something
            # surprising happens.
            f = open(repo.join('histedit-last-edit.txt'), 'w')
            f.write(rules)
            f.close()
        else:
            if rules == '-':
                f = sys.stdin
            else:
                f = open(rules)
            rules = f.read()
            f.close()
        rules = [l for l in (r.strip() for r in rules.splitlines())
                 if l and not l.startswith('#')]
        rules = verifyrules(rules, repo, ctxs)

        parentctx = repo[root].parents()[0]

        state.parentctx = parentctx
        state.rules = rules
        state.keep = keep
        state.topmost = topmost
        state.replacements = replacements

    while state.rules:
        state.write()
        action, ha = state.rules.pop(0)
        ui.debug('histedit: processing %s %s\n' % (action, ha))
        actfunc = actiontable[action]
        state.parentctx, replacement_ = actfunc(ui, state, ha, opts)
        state.replacements.extend(replacement_)

    hg.update(repo, state.parentctx.node())

    mapping, tmpnodes, created, ntm = processreplacement(state)
    if mapping:
        for prec, succs in mapping.iteritems():
            if not succs:
                ui.debug('histedit: %s is dropped\n' % node.short(prec))
            else:
                ui.debug('histedit: %s is replaced by %s\n' % (
                    node.short(prec), node.short(succs[0])))
                if len(succs) > 1:
                    m = 'histedit:                            %s'
                    for n in succs[1:]:
                        ui.debug(m % node.short(n))

    if not keep:
        if mapping:
            movebookmarks(ui, repo, mapping, state.topmost, ntm)
            # TODO update mq state
        if obsolete.isenabled(repo, obsolete.createmarkersopt):
            markers = []
            # sort by revision number because it sound "right"
            for prec in sorted(mapping, key=repo.changelog.rev):
                succs = mapping[prec]
                markers.append((repo[prec],
                                tuple(repo[s] for s in succs)))
            if markers:
                obsolete.createmarkers(repo, markers)
        else:
            cleanupnode(ui, repo, 'replaced', mapping)

    cleanupnode(ui, repo, 'temp', tmpnodes)
    state.clear()
    if os.path.exists(repo.sjoin('undo')):
        os.unlink(repo.sjoin('undo'))
Exemplo n.º 39
0
def histedit(ui, repo, *parent, **opts):
    """hg histedit <parent>
    """
    # TODO only abort if we try and histedit mq patches, not just
    # blanket if mq patches are applied somewhere
    mq = getattr(repo, 'mq', None)
    if mq and mq.applied:
        raise util.Abort(_('source has mq patches applied'))

    parent = list(parent) + opts.get('rev', [])
    if opts.get('outgoing'):
        if len(parent) > 1:
            raise util.Abort('only one repo argument allowed with --outgoing')
        elif parent:
            parent = parent[0]

        dest = ui.expandpath(parent or 'default-push', parent or 'default')
        dest, revs = hg.parseurl(dest, None)[:2]
        if isinstance(revs, tuple):
            # hg >= 1.6
            revs, checkout = hg.addbranchrevs(repo, repo, revs, None)
            other = hg.repository(hg.remoteui(repo, opts), dest)
            # hg >= 1.9
            findoutgoing = getattr(discovery, 'findoutgoing', None)
            if findoutgoing is None:
                if getattr(discovery, 'outgoing', None) is not None:

                    def findoutgoing(repo, other, force=False):
                        out = discovery.findcommonoutgoing(repo,
                                                           other, [],
                                                           force=force)
                        return out.missing[0:1]
                else:
                    # hg 1.9 and 2.0
                    def findoutgoing(repo, other, force=False):
                        common, outheads = discovery.findcommonoutgoing(
                            repo, other, [], force=force)
                        return repo.changelog.findmissing(common,
                                                          outheads)[0:1]
        else:
            other = hg.repository(ui, dest)

            def findoutgoing(repo, other, force=False):
                return repo.findoutgoing(other, force=force)

        if revs:
            revs = [repo.lookup(rev) for rev in revs]

        ui.status(_('comparing with %s\n') % hidepassword(dest))
        parent = findoutgoing(repo, other, force=opts.get('force'))
    else:
        if opts.get('force'):
            raise util.Abort('--force only allowed with --outgoing')

    if opts.get('continue', False):
        if len(parent) != 0:
            raise util.Abort('no arguments allowed with --continue')
        (parentctxnode, created, replaced, tmpnodes, existing, rules, keep,
         tip, replacemap) = readstate(repo)
        currentparent, wantnull = repo.dirstate.parents()
        parentctx = repo[parentctxnode]
        # discover any nodes the user has added in the interim
        newchildren = [
            c for c in parentctx.children() if c.node() not in existing
        ]
        action, currentnode = rules.pop(0)
        while newchildren:
            if action in [
                    'f',
                    'fold',
            ]:
                tmpnodes.extend([n.node() for n in newchildren])
            else:
                created.extend([n.node() for n in newchildren])
            newchildren = filter(
                lambda x: x.node() not in existing,
                reduce(lambda x, y: x + y,
                       map(lambda r: r.children(), newchildren)))
        m, a, r, d = repo.status()[:4]
        oldctx = repo[currentnode]
        message = oldctx.description()
        if action in ('e', 'edit', 'm', 'mess'):
            message = ui.edit(message, ui.username())
        elif action in (
                'f',
                'fold',
        ):
            message = 'fold-temp-revision %s' % currentnode
        new = None
        if m or a or r or d:
            new = repo.commit(text=message,
                              user=oldctx.user(),
                              date=oldctx.date(),
                              extra=oldctx.extra())

        if action in ('f', 'fold'):
            if new:
                tmpnodes.append(new)
            else:
                new = newchildren[-1]
            (
                parentctx,
                created_,
                replaced_,
                tmpnodes_,
            ) = finishfold(ui, repo, parentctx, oldctx, new, opts, newchildren)
            replaced.extend(replaced_)
            created.extend(created_)
            tmpnodes.extend(tmpnodes_)
        elif action not in ('d', 'drop'):
            if new != oldctx.node():
                replaced.append(oldctx.node())
            if new:
                if new != oldctx.node():
                    created.append(new)
                parentctx = repo[new]

    elif opts.get('abort', False):
        if len(parent) != 0:
            raise util.Abort('no arguments allowed with --abort')
        (parentctxnode, created, replaced, tmpnodes, existing, rules, keep,
         tip, replacemap) = readstate(repo)
        ui.debug('restore wc to old tip %s\n' % node.hex(tip))
        hg.clean(repo, tip)
        ui.debug('should strip created nodes %s\n' %
                 ', '.join([node.hex(n)[:12] for n in created]))
        ui.debug('should strip temp nodes %s\n' %
                 ', '.join([node.hex(n)[:12] for n in tmpnodes]))
        for nodes in (
                created,
                tmpnodes,
        ):
            for n in reversed(nodes):
                try:
                    repair.strip(ui, repo, n)
                except error.LookupError:
                    pass
        os.unlink(os.path.join(repo.path, 'histedit-state'))
        return
    else:
        bailifchanged(repo)
        if os.path.exists(os.path.join(repo.path, 'histedit-state')):
            raise util.Abort('history edit already in progress, try '
                             '--continue or --abort')

        tip, empty = repo.dirstate.parents()

        if len(parent) != 1:
            raise util.Abort('requires exactly one parent revision')
        parent = _revsingle(repo, parent[0]).node()

        keep = opts.get('keep', False)
        revs = between(repo, parent, tip, keep)

        ctxs = [repo[r] for r in revs]
        existing = [r.node() for r in ctxs]
        rules = opts.get('commands', '')
        if not rules:
            rules = '\n'.join([makedesc(c) for c in ctxs])
            rules += editcomment % (
                node.hex(parent)[:12],
                node.hex(tip)[:12],
            )
            rules = ui.edit(rules, ui.username())
            # Save edit rules in .hg/histedit-last-edit.txt in case
            # the user needs to ask for help after something
            # surprising happens.
            f = open(repo.join('histedit-last-edit.txt'), 'w')
            f.write(rules)
            f.close()
        else:
            f = open(rules)
            rules = f.read()
            f.close()
        rules = [
            l for l in (r.strip() for r in rules.splitlines())
            if l and not l[0] == '#'
        ]
        rules = verifyrules(rules, repo, ctxs)

        parentctx = repo[parent].parents()[0]
        keep = opts.get('keep', False)
        replaced = []
        replacemap = {}
        tmpnodes = []
        created = []

    while rules:
        writestate(repo, parentctx.node(), created, replaced, tmpnodes,
                   existing, rules, keep, tip, replacemap)
        action, ha = rules.pop(0)
        (
            parentctx,
            created_,
            replaced_,
            tmpnodes_,
        ) = actiontable[action](ui, repo, parentctx, ha, opts)

        hexshort = lambda x: node.hex(x)[:12]

        if replaced_:
            clen, rlen = len(created_), len(replaced_)
            if clen == rlen == 1:
                ui.debug('histedit: exact replacement of %s with %s\n' %
                         (hexshort(replaced_[0]), hexshort(created_[0])))

                replacemap[replaced_[0]] = created_[0]
            elif clen > rlen:
                assert rlen == 1, ('unexpected replacement of '
                                   '%d changes with %d changes' % (rlen, clen))
                # made more changesets than we're replacing
                # TODO synthesize patch names for created patches
                replacemap[replaced_[0]] = created_[-1]
                ui.debug('histedit: created many, assuming %s replaced by %s' %
                         (hexshort(replaced_[0]), hexshort(created_[-1])))
            elif rlen > clen:
                if not created_:
                    # This must be a drop. Try and put our metadata on
                    # the parent change.
                    assert rlen == 1
                    r = replaced_[0]
                    ui.debug('histedit: %s seems replaced with nothing, '
                             'finding a parent\n' % (hexshort(r)))
                    pctx = repo[r].parents()[0]
                    if pctx.node() in replacemap:
                        ui.debug('histedit: parent is already replaced\n')
                        replacemap[r] = replacemap[pctx.node()]
                    else:
                        replacemap[r] = pctx.node()
                    ui.debug('histedit: %s best replaced by %s\n' %
                             (hexshort(r), hexshort(replacemap[r])))
                else:
                    assert len(created_) == 1
                    for r in replaced_:
                        ui.debug('histedit: %s replaced by %s\n' %
                                 (hexshort(r), hexshort(created_[0])))
                        replacemap[r] = created_[0]
            else:
                assert False, ('Unhandled case in replacement mapping! '
                               'replacing %d changes with %d changes' %
                               (rlen, clen))
        created.extend(created_)
        replaced.extend(replaced_)
        tmpnodes.extend(tmpnodes_)

    hg.update(repo, parentctx.node())

    if not keep:
        if replacemap:
            ui.note('histedit: Should update metadata for the following '
                    'changes:\n')
            for old, new in replacemap.iteritems():
                if old in tmpnodes or old in created:
                    # can't have any metadata we'd want to update
                    continue
                while new in replacemap:
                    new = replacemap[new]
                ui.note('histedit:  %s to %s\n' %
                        (hexshort(old), hexshort(new)))
                octx = repo[old]
                if bookmarks is not None:
                    marks = octx.bookmarks()
                    if marks:
                        ui.note('histedit:     moving bookmarks %s\n' %
                                ', '.join(marks))
                        for mark in marks:
                            repo._bookmarks[mark] = new
                        bookmarks.write(repo)
                # TODO update mq state

        ui.debug('should strip replaced nodes %s\n' %
                 ', '.join([node.hex(n)[:12] for n in replaced]))
        for n in sorted(replaced, key=lambda x: repo[x].rev()):
            try:
                repair.strip(ui, repo, n)
            except error.LookupError:
                pass

    ui.debug('should strip temp nodes %s\n' %
             ', '.join([node.hex(n)[:12] for n in tmpnodes]))
    for n in reversed(tmpnodes):
        try:
            repair.strip(ui, repo, n)
        except error.LookupError:
            pass
    os.unlink(os.path.join(repo.path, 'histedit-state'))
    if os.path.exists(repo.sjoin('undo')):
        os.unlink(repo.sjoin('undo'))
Exemplo n.º 40
0
 def updateClean(self, revision):
     self.ui.status(_('updating to %d:%s\n') %
                    (self.repo.changelog.rev(revision),
                     short(revision)))
     hg.clean(self.repo, revision)
Exemplo n.º 41
0
def cleanup(repo):
    '''removes all changes from the working copy and makes it so
    there isn't a patch applied; copied from attic'''
    node = repo.dirstate.parents()[0]
    hg.clean(repo, node, False)
Exemplo n.º 42
0
def _narrow(ui, repo, remote, commoninc, oldincludes, oldexcludes,
            newincludes, newexcludes, force):
    oldmatch = narrowspec.match(repo.root, oldincludes, oldexcludes)
    newmatch = narrowspec.match(repo.root, newincludes, newexcludes)

    # This is essentially doing "hg outgoing" to find all local-only
    # commits. We will then check that the local-only commits don't
    # have any changes to files that will be untracked.
    unfi = repo.unfiltered()
    outgoing = discovery.findcommonoutgoing(unfi, remote,
                                            commoninc=commoninc)
    ui.status(_('looking for local changes to affected paths\n'))
    localnodes = []
    for n in itertools.chain(outgoing.missing, outgoing.excluded):
        if any(oldmatch(f) and not newmatch(f) for f in unfi[n].files()):
            localnodes.append(n)
    revstostrip = unfi.revs('descendants(%ln)', localnodes)
    hiddenrevs = repoview.filterrevs(repo, 'visible')
    visibletostrip = list(repo.changelog.node(r)
                          for r in (revstostrip - hiddenrevs))
    if visibletostrip:
        ui.status(_('The following changeset(s) or their ancestors have '
                    'local changes not on the remote:\n'))
        maxnodes = 10
        if ui.verbose or len(visibletostrip) <= maxnodes:
            for n in visibletostrip:
                ui.status('%s\n' % node.short(n))
        else:
            for n in visibletostrip[:maxnodes]:
                ui.status('%s\n' % node.short(n))
            ui.status(_('...and %d more, use --verbose to list all\n') %
                      (len(visibletostrip) - maxnodes))
        if not force:
            raise error.Abort(_('local changes found'),
                              hint=_('use --force-delete-local-changes to '
                                     'ignore'))

    with ui.uninterruptable():
        if revstostrip:
            tostrip = [unfi.changelog.node(r) for r in revstostrip]
            if repo['.'].node() in tostrip:
                # stripping working copy, so move to a different commit first
                urev = max(repo.revs('(::%n) - %ln + null',
                                     repo['.'].node(), visibletostrip))
                hg.clean(repo, urev)
            overrides = {('devel', 'strip-obsmarkers'): False}
            with ui.configoverride(overrides, 'narrow'):
                repair.strip(ui, unfi, tostrip, topic='narrow')

        todelete = []
        for f, f2, size in repo.store.datafiles():
            if f.startswith('data/'):
                file = f[5:-2]
                if not newmatch(file):
                    todelete.append(f)
            elif f.startswith('meta/'):
                dir = f[5:-13]
                dirs = ['.'] + sorted(util.dirs({dir})) + [dir]
                include = True
                for d in dirs:
                    visit = newmatch.visitdir(d)
                    if not visit:
                        include = False
                        break
                    if visit == 'all':
                        break
                if not include:
                    todelete.append(f)

        repo.destroying()

        with repo.transaction("narrowing"):
            for f in todelete:
                ui.status(_('deleting %s\n') % f)
                util.unlinkpath(repo.svfs.join(f))
                repo.store.markremoved(f)

            _narrowcleanupwdir(repo, oldincludes, oldexcludes, newincludes,
                               newexcludes, oldmatch, newmatch)
            repo.setnarrowpats(newincludes, newexcludes)

        repo.destroyed()
Exemplo n.º 43
0
def _histedit(ui, repo, *freeargs, **opts):
    # TODO only abort if we try and histedit mq patches, not just
    # blanket if mq patches are applied somewhere
    mq = getattr(repo, 'mq', None)
    if mq and mq.applied:
        raise util.Abort(_('source has mq patches applied'))

    # basic argument incompatibility processing
    outg = opts.get('outgoing')
    cont = opts.get('continue')
    abort = opts.get('abort')
    force = opts.get('force')
    rules = opts.get('commands', '')
    revs = opts.get('rev', [])
    goal = 'new' # This invocation goal, in new, continue, abort
    if force and not outg:
        raise util.Abort(_('--force only allowed with --outgoing'))
    if cont:
        if util.any((outg, abort, revs, freeargs, rules)):
            raise util.Abort(_('no arguments allowed with --continue'))
        goal = 'continue'
    elif abort:
        if util.any((outg, revs, freeargs, rules)):
            raise util.Abort(_('no arguments allowed with --abort'))
        goal = 'abort'
    else:
        if os.path.exists(os.path.join(repo.path, 'histedit-state')):
            raise util.Abort(_('history edit already in progress, try '
                               '--continue or --abort'))
        if outg:
            if revs:
                raise util.Abort(_('no revisions allowed with --outgoing'))
            if len(freeargs) > 1:
                raise util.Abort(
                    _('only one repo argument allowed with --outgoing'))
        else:
            revs.extend(freeargs)
            if len(revs) != 1:
                raise util.Abort(
                    _('histedit requires exactly one ancestor revision'))


    if goal == 'continue':
        (parentctxnode, rules, keep, topmost, replacements) = readstate(repo)
        parentctx = repo[parentctxnode]
        parentctx, repl = bootstrapcontinue(ui, repo, parentctx, rules, opts)
        replacements.extend(repl)
    elif goal == 'abort':
        (parentctxnode, rules, keep, topmost, replacements) = readstate(repo)
        mapping, tmpnodes, leafs, _ntm = processreplacement(repo, replacements)
        ui.debug('restore wc to old parent %s\n' % node.short(topmost))
        # check whether we should update away
        parentnodes = [c.node() for c in repo[None].parents()]
        for n in leafs | set([parentctxnode]):
            if n in parentnodes:
                hg.clean(repo, topmost)
                break
        else:
            pass
        cleanupnode(ui, repo, 'created', tmpnodes)
        cleanupnode(ui, repo, 'temp', leafs)
        os.unlink(os.path.join(repo.path, 'histedit-state'))
        return
    else:
        cmdutil.checkunfinished(repo)
        cmdutil.bailifchanged(repo)

        topmost, empty = repo.dirstate.parents()
        if outg:
            if freeargs:
                remote = freeargs[0]
            else:
                remote = None
            root = findoutgoing(ui, repo, remote, force, opts)
        else:
            rootrevs = list(repo.set('roots(%lr)', revs))
            if len(rootrevs) != 1:
                raise util.Abort(_('The specified revisions must have '
                    'exactly one common root'))
            root = rootrevs[0].node()

        keep = opts.get('keep', False)
        revs = between(repo, root, topmost, keep)
        if not revs:
            raise util.Abort(_('%s is not an ancestor of working directory') %
                             node.short(root))

        ctxs = [repo[r] for r in revs]
        if not rules:
            rules = '\n'.join([makedesc(c) for c in ctxs])
            rules += '\n\n'
            rules += editcomment % (node.short(root), node.short(topmost))
            rules = ui.edit(rules, ui.username())
            # Save edit rules in .hg/histedit-last-edit.txt in case
            # the user needs to ask for help after something
            # surprising happens.
            f = open(repo.join('histedit-last-edit.txt'), 'w')
            f.write(rules)
            f.close()
        else:
            if rules == '-':
                f = sys.stdin
            else:
                f = open(rules)
            rules = f.read()
            f.close()
        rules = [l for l in (r.strip() for r in rules.splitlines())
                 if l and not l[0] == '#']
        rules = verifyrules(rules, repo, ctxs)

        parentctx = repo[root].parents()[0]
        keep = opts.get('keep', False)
        replacements = []


    while rules:
        writestate(repo, parentctx.node(), rules, keep, topmost, replacements)
        action, ha = rules.pop(0)
        ui.debug('histedit: processing %s %s\n' % (action, ha))
        actfunc = actiontable[action]
        parentctx, replacement_ = actfunc(ui, repo, parentctx, ha, opts)
        replacements.extend(replacement_)

    hg.update(repo, parentctx.node())

    mapping, tmpnodes, created, ntm = processreplacement(repo, replacements)
    if mapping:
        for prec, succs in mapping.iteritems():
            if not succs:
                ui.debug('histedit: %s is dropped\n' % node.short(prec))
            else:
                ui.debug('histedit: %s is replaced by %s\n' % (
                    node.short(prec), node.short(succs[0])))
                if len(succs) > 1:
                    m = 'histedit:                            %s'
                    for n in succs[1:]:
                        ui.debug(m % node.short(n))

    if not keep:
        if mapping:
            movebookmarks(ui, repo, mapping, topmost, ntm)
            # TODO update mq state
        if obsolete._enabled:
            markers = []
            # sort by revision number because it sound "right"
            for prec in sorted(mapping, key=repo.changelog.rev):
                succs = mapping[prec]
                markers.append((repo[prec],
                                tuple(repo[s] for s in succs)))
            if markers:
                obsolete.createmarkers(repo, markers)
        else:
            cleanupnode(ui, repo, 'replaced', mapping)

    cleanupnode(ui, repo, 'temp', tmpnodes)
    os.unlink(os.path.join(repo.path, 'histedit-state'))
    if os.path.exists(repo.sjoin('undo')):
        os.unlink(repo.sjoin('undo'))
Exemplo n.º 44
0
def _histedit(ui, repo, state, *freeargs, **opts):
    # TODO only abort if we try and histedit mq patches, not just
    # blanket if mq patches are applied somewhere
    mq = getattr(repo, 'mq', None)
    if mq and mq.applied:
        raise error.Abort(_('source has mq patches applied'))

    # basic argument incompatibility processing
    outg = opts.get('outgoing')
    cont = opts.get('continue')
    editplan = opts.get('edit_plan')
    abort = opts.get('abort')
    force = opts.get('force')
    rules = opts.get('commands', '')
    revs = opts.get('rev', [])
    goal = 'new' # This invocation goal, in new, continue, abort
    if force and not outg:
        raise error.Abort(_('--force only allowed with --outgoing'))
    if cont:
        if any((outg, abort, revs, freeargs, rules, editplan)):
            raise error.Abort(_('no arguments allowed with --continue'))
        goal = 'continue'
    elif abort:
        if any((outg, revs, freeargs, rules, editplan)):
            raise error.Abort(_('no arguments allowed with --abort'))
        goal = 'abort'
    elif editplan:
        if any((outg, revs, freeargs)):
            raise error.Abort(_('only --commands argument allowed with '
                               '--edit-plan'))
        goal = 'edit-plan'
    else:
        if os.path.exists(os.path.join(repo.path, 'histedit-state')):
            raise error.Abort(_('history edit already in progress, try '
                               '--continue or --abort'))
        if outg:
            if revs:
                raise error.Abort(_('no revisions allowed with --outgoing'))
            if len(freeargs) > 1:
                raise error.Abort(
                    _('only one repo argument allowed with --outgoing'))
        else:
            revs.extend(freeargs)
            if len(revs) == 0:
                # experimental config: histedit.defaultrev
                histeditdefault = ui.config('histedit', 'defaultrev')
                if histeditdefault:
                    revs.append(histeditdefault)
            if len(revs) != 1:
                raise error.Abort(
                    _('histedit requires exactly one ancestor revision'))


    replacements = []
    state.keep = opts.get('keep', False)
    supportsmarkers = obsolete.isenabled(repo, obsolete.createmarkersopt)

    # rebuild state
    if goal == 'continue':
        state.read()
        state = bootstrapcontinue(ui, state, opts)
    elif goal == 'edit-plan':
        state.read()
        if not rules:
            comment = editcomment % (node.short(state.parentctxnode),
                                     node.short(state.topmost))
            rules = ruleeditor(repo, ui, state.rules, comment)
        else:
            if rules == '-':
                f = sys.stdin
            else:
                f = open(rules)
            rules = f.read()
            f.close()
        rules = [l for l in (r.strip() for r in rules.splitlines())
                 if l and not l.startswith('#')]
        rules = verifyrules(rules, repo, [repo[c] for [_a, c] in state.rules])
        state.rules = rules
        state.write()
        return
    elif goal == 'abort':
        try:
            state.read()
            tmpnodes, leafs = newnodestoabort(state)
            ui.debug('restore wc to old parent %s\n'
                    % node.short(state.topmost))

            # Recover our old commits if necessary
            if not state.topmost in repo and state.backupfile:
                backupfile = repo.join(state.backupfile)
                f = hg.openpath(ui, backupfile)
                gen = exchange.readbundle(ui, f, backupfile)
                tr = repo.transaction('histedit.abort')
                try:
                    if not isinstance(gen, bundle2.unbundle20):
                        gen.apply(repo, 'histedit', 'bundle:' + backupfile)
                    if isinstance(gen, bundle2.unbundle20):
                        bundle2.applybundle(repo, gen, tr,
                                            source='histedit',
                                            url='bundle:' + backupfile)
                    tr.close()
                finally:
                    tr.release()

                os.remove(backupfile)

            # check whether we should update away
            if repo.unfiltered().revs('parents() and (%n  or %ln::)',
                                    state.parentctxnode, leafs | tmpnodes):
                hg.clean(repo, state.topmost)
            cleanupnode(ui, repo, 'created', tmpnodes)
            cleanupnode(ui, repo, 'temp', leafs)
        except Exception:
            if state.inprogress():
                ui.warn(_('warning: encountered an exception during histedit '
                    '--abort; the repository may not have been completely '
                    'cleaned up\n'))
            raise
        finally:
                state.clear()
        return
    else:
        cmdutil.checkunfinished(repo)
        cmdutil.bailifchanged(repo)

        topmost, empty = repo.dirstate.parents()
        if outg:
            if freeargs:
                remote = freeargs[0]
            else:
                remote = None
            root = findoutgoing(ui, repo, remote, force, opts)
        else:
            rr = list(repo.set('roots(%ld)', scmutil.revrange(repo, revs)))
            if len(rr) != 1:
                raise error.Abort(_('The specified revisions must have '
                    'exactly one common root'))
            root = rr[0].node()

        revs = between(repo, root, topmost, state.keep)
        if not revs:
            raise error.Abort(_('%s is not an ancestor of working directory') %
                             node.short(root))

        ctxs = [repo[r] for r in revs]
        if not rules:
            comment = editcomment % (node.short(root), node.short(topmost))
            rules = ruleeditor(repo, ui, [['pick', c] for c in ctxs], comment)
        else:
            if rules == '-':
                f = sys.stdin
            else:
                f = open(rules)
            rules = f.read()
            f.close()
        rules = [l for l in (r.strip() for r in rules.splitlines())
                 if l and not l.startswith('#')]
        rules = verifyrules(rules, repo, ctxs)

        parentctxnode = repo[root].parents()[0].node()

        state.parentctxnode = parentctxnode
        state.rules = rules
        state.topmost = topmost
        state.replacements = replacements

        # Create a backup so we can always abort completely.
        backupfile = None
        if not obsolete.isenabled(repo, obsolete.createmarkersopt):
            backupfile = repair._bundle(repo, [parentctxnode], [topmost], root,
                                        'histedit')
        state.backupfile = backupfile

    # preprocess rules so that we can hide inner folds from the user
    # and only show one editor
    rules = state.rules[:]
    for idx, ((action, ha), (nextact, unused)) in enumerate(
            zip(rules, rules[1:] + [(None, None)])):
        if action == 'fold' and nextact == 'fold':
            state.rules[idx] = '_multifold', ha

    while state.rules:
        state.write()
        action, ha = state.rules.pop(0)
        ui.debug('histedit: processing %s %s\n' % (action, ha[:12]))
        actobj = actiontable[action].fromrule(state, ha)
        parentctx, replacement_ = actobj.run()
        state.parentctxnode = parentctx.node()
        state.replacements.extend(replacement_)
    state.write()

    hg.update(repo, state.parentctxnode)

    mapping, tmpnodes, created, ntm = processreplacement(state)
    if mapping:
        for prec, succs in mapping.iteritems():
            if not succs:
                ui.debug('histedit: %s is dropped\n' % node.short(prec))
            else:
                ui.debug('histedit: %s is replaced by %s\n' % (
                    node.short(prec), node.short(succs[0])))
                if len(succs) > 1:
                    m = 'histedit:                            %s'
                    for n in succs[1:]:
                        ui.debug(m % node.short(n))

    if supportsmarkers:
        # Only create markers if the temp nodes weren't already removed.
        obsolete.createmarkers(repo, ((repo[t],()) for t in sorted(tmpnodes)
                                       if t in repo))
    else:
        cleanupnode(ui, repo, 'temp', tmpnodes)

    if not state.keep:
        if mapping:
            movebookmarks(ui, repo, mapping, state.topmost, ntm)
            # TODO update mq state
        if supportsmarkers:
            markers = []
            # sort by revision number because it sound "right"
            for prec in sorted(mapping, key=repo.changelog.rev):
                succs = mapping[prec]
                markers.append((repo[prec],
                                tuple(repo[s] for s in succs)))
            if markers:
                obsolete.createmarkers(repo, markers)
        else:
            cleanupnode(ui, repo, 'replaced', mapping)

    state.clear()
    if os.path.exists(repo.sjoin('undo')):
        os.unlink(repo.sjoin('undo'))
Exemplo n.º 45
0
def cancel_merge(ui, repo, **opts):
    """Cancel a merge"""
    #TODO: check that merge is in progress
    curr = repo[None].branch()
    hg.clean(repo, curr)
Exemplo n.º 46
0
    def _applymerge(self,
                    repo,
                    patchfile,
                    sim,
                    name,
                    parent,
                    force=False,
                    **opts):
        """applies a patch using fancy merge technology."""
        reverse = opts.get('reverse')
        opts['reverse'] = False

        def smwrapper(orig, *args, **opts):
            shelf = 'shelf:%s' % name
            if reverse:
                shelf += ' --reverse'
            opts['label'] = ['local', shelf]
            return orig(*args, **opts)

        def savediff():
            opts = {'git': True}
            fp = opener('.saved', 'w')
            for chunk in patch.diff(repo,
                                    head,
                                    None,
                                    opts=patch.diffopts(self.ui, opts)):
                fp.write(chunk)
            fp.close()

        def applydiff(name):
            files = {}
            patch.patch(self.join(patchfile), self.ui, strip=1, files=files)
            files2 = {}
            for k in files.keys():
                files2[k.strip('\r')] = files[k]
            updatedir(self.ui, repo, files2, similarity=sim / 100.)

        opener = util.opener('.hg/attic')
        smo = extensions.wrapfunction(simplemerge, 'simplemerge', smwrapper)
        quiet = self.ui.quiet
        self.ui.quiet = True
        whead, phead = None, None
        success = False
        try:
            head = repo.dirstate.parents()[0]
            # Save the open changes
            self.ui.note(_("saving open changes\n"))
            n = repo.commit('working', 'hgattic', None, force=1)
            savediff()
            whead = repo.heads(None)[0]
            # Set the workspace to match the base version for patching
            self.ui.note(_("applying diff to version specified in patch\n"))
            hg.clean(repo, parent)
            applydiff(self.join(patchfile))
            n = repo.commit('patched', 'hgattic', None, force=1)
            phead = repo.heads(None)[0]
            if reverse:
                # Merge, using the working copy to avoid conflicts
                self.ui.note(_("applying reverse\n"))
                hgmerge = os.environ.get('HGMERGE')
                os.environ['HGMERGE'] = 'internal:other'
                hg.merge(repo, whead, force=True)
                os.environ['HGMERGE'] = hgmerge
                # Backout the patched version, this is where we want conflicts
                repo.commit('merge', 'hgattic', None, force=1)
                backout_opts = {
                    'rev': phead,
                    'merge': True,
                    'message': 'backout'
                }
                commands.backout(self.ui, repo, **backout_opts)
            else:
                # Merge the working copy with the patched copy
                self.ui.note(_("merging patch forward\n"))
                hg.merge(repo, whead, force=True)
            savediff()
            success = True
        finally:
            simplemerge.simplemerge = smo
            self.ui.note(_("cleanup\n"))
            hg.clean(repo, head)
            strip_opts = {'backup': False, 'nobackup': True, 'force': False}
            if phead and head != phead:
                self.strip(repo, phead)
            if whead and head != whead:
                self.strip(repo, whead)
            if not success:
                applydiff('.saved')
            self.ui.quiet = quiet
        if success:
            self.ui.note(_("applying updated patch\n"))
            success = self._applypatch(repo, '.saved', sim, force, **opts)
        return success
Exemplo n.º 47
0
def histedit(ui, repo, *parent, **opts):
    """hg histedit <parent>
    """
    # TODO only abort if we try and histedit mq patches, not just
    # blanket if mq patches are applied somewhere
    mq = getattr(repo, 'mq', None)
    if mq and mq.applied:
        raise util.Abort(_('source has mq patches applied'))

    parent = list(parent) + opts.get('rev', [])
    if opts.get('outgoing'):
        if len(parent) > 1:
            raise util.Abort('only one repo argument allowed with --outgoing')
        elif parent:
            parent = parent[0]

        dest = ui.expandpath(parent or 'default-push', parent or 'default')
        dest, revs = hg.parseurl(dest, None)[:2]
        if isinstance(revs, tuple):
            # hg >= 1.6
            revs, checkout = hg.addbranchrevs(repo, repo, revs, None)
            other = hg.repository(hg.remoteui(repo, opts), dest)
            # hg >= 1.9
            findoutgoing = getattr(discovery, 'findoutgoing', None)
            if findoutgoing is None:
                if getattr(discovery, 'outgoing', None) is not None:
                    def findoutgoing(repo, other, force=False):
                        out = discovery.findcommonoutgoing(
                            repo, other, [], force=force)
                        return out.missing[0:1]
                else:
                    # hg 1.9 and 2.0
                    def findoutgoing(repo, other, force=False):
                        common, outheads = discovery.findcommonoutgoing(
                            repo, other, [], force=force)
                        return repo.changelog.findmissing(common, outheads)[0:1]
        else:
            other = hg.repository(ui, dest)
            def findoutgoing(repo, other, force=False):
                return repo.findoutgoing(other, force=force)

        if revs:
            revs = [repo.lookup(rev) for rev in revs]

        ui.status(_('comparing with %s\n') % hidepassword(dest))
        parent = findoutgoing(repo, other, force=opts.get('force'))
    else:
        if opts.get('force'):
            raise util.Abort('--force only allowed with --outgoing')

    if opts.get('continue', False):
        if len(parent) != 0:
            raise util.Abort('no arguments allowed with --continue')
        (parentctxnode, created, replaced,
         tmpnodes, existing, rules, keep, tip, replacemap ) = readstate(repo)
        currentparent, wantnull = repo.dirstate.parents()
        parentctx = repo[parentctxnode]
        # discover any nodes the user has added in the interim
        newchildren = [c for c in parentctx.children()
                       if c.node() not in existing]
        action, currentnode = rules.pop(0)
        while newchildren:
            if action in ['f', 'fold', ]:
                tmpnodes.extend([n.node() for n in newchildren])
            else:
                created.extend([n.node() for n in newchildren])
            newchildren = filter(lambda x: x.node() not in existing,
                                 reduce(lambda x, y: x + y,
                                        map(lambda r: r.children(),
                                            newchildren)))
        m, a, r, d = repo.status()[:4]
        oldctx = repo[currentnode]
        message = oldctx.description()
        if action in ('e', 'edit', 'm', 'mess'):
            message = ui.edit(message, ui.username())
        elif action in ('f', 'fold', ):
            message = 'fold-temp-revision %s' % currentnode
        new = None
        if m or a or r or d:
            new = repo.commit(text=message, user=oldctx.user(), date=oldctx.date(),
                              extra=oldctx.extra())

        if action in ('f', 'fold'):
            if new:
                tmpnodes.append(new)
            else:
                new = newchildren[-1]
            (parentctx, created_,
             replaced_, tmpnodes_, ) = finishfold(ui, repo,
                                                  parentctx, oldctx, new,
                                                  opts, newchildren)
            replaced.extend(replaced_)
            created.extend(created_)
            tmpnodes.extend(tmpnodes_)
        elif action not in ('d', 'drop'):
            if new != oldctx.node():
                replaced.append(oldctx.node())
            if new:
                if new != oldctx.node():
                    created.append(new)
                parentctx = repo[new]

    elif opts.get('abort', False):
        if len(parent) != 0:
            raise util.Abort('no arguments allowed with --abort')
        (parentctxnode, created, replaced, tmpnodes,
         existing, rules, keep, tip, replacemap) = readstate(repo)
        ui.debug('restore wc to old tip %s\n' % node.hex(tip))
        hg.clean(repo, tip)
        ui.debug('should strip created nodes %s\n' %
                 ', '.join([node.hex(n)[:12] for n in created]))
        ui.debug('should strip temp nodes %s\n' %
                 ', '.join([node.hex(n)[:12] for n in tmpnodes]))
        for nodes in (created, tmpnodes, ):
            for n in reversed(nodes):
                try:
                    repair.strip(ui, repo, n)
                except error.LookupError:
                    pass
        os.unlink(os.path.join(repo.path, 'histedit-state'))
        return
    else:
        bailifchanged(repo)
        if os.path.exists(os.path.join(repo.path, 'histedit-state')):
            raise util.Abort('history edit already in progress, try '
                             '--continue or --abort')

        tip, empty = repo.dirstate.parents()


        if len(parent) != 1:
            raise util.Abort('requires exactly one parent revision')
        parent = _revsingle(repo, parent[0]).node()

        keep = opts.get('keep', False)
        revs = between(repo, parent, tip, keep)

        ctxs = [repo[r] for r in revs]
        existing = [r.node() for r in ctxs]
        rules = opts.get('commands', '')
        if not rules:
            rules = '\n'.join([makedesc(c) for c in ctxs])
            rules += editcomment % (node.hex(parent)[:12], node.hex(tip)[:12], )
            rules = ui.edit(rules, ui.username())
            # Save edit rules in .hg/histedit-last-edit.txt in case
            # the user needs to ask for help after something
            # surprising happens.
            f = open(repo.join('histedit-last-edit.txt'), 'w')
            f.write(rules)
            f.close()
        else:
            f = open(rules)
            rules = f.read()
            f.close()
        rules = [l for l in (r.strip() for r in rules.splitlines())
                 if l and not l[0] == '#']
        rules = verifyrules(rules, repo, ctxs)

        parentctx = repo[parent].parents()[0]
        keep = opts.get('keep', False)
        replaced = []
        replacemap = {}
        tmpnodes = []
        created = []


    while rules:
        writestate(repo, parentctx.node(), created, replaced, tmpnodes, existing,
                   rules, keep, tip, replacemap)
        action, ha = rules.pop(0)
        (parentctx, created_,
         replaced_, tmpnodes_, ) = actiontable[action](ui, repo,
                                                       parentctx, ha,
                                                       opts)

        hexshort = lambda x: node.hex(x)[:12]

        if replaced_:
            clen, rlen = len(created_), len(replaced_)
            if clen == rlen == 1:
                ui.debug('histedit: exact replacement of %s with %s\n' % (
                    hexshort(replaced_[0]), hexshort(created_[0])))

                replacemap[replaced_[0]] = created_[0]
            elif clen > rlen:
                assert rlen == 1, ('unexpected replacement of '
                                   '%d changes with %d changes' % (rlen, clen))
                # made more changesets than we're replacing
                # TODO synthesize patch names for created patches
                replacemap[replaced_[0]] = created_[-1]
                ui.debug('histedit: created many, assuming %s replaced by %s' % (
                    hexshort(replaced_[0]), hexshort(created_[-1])))
            elif rlen > clen:
                if not created_:
                    # This must be a drop. Try and put our metadata on
                    # the parent change.
                    assert rlen == 1
                    r = replaced_[0]
                    ui.debug('histedit: %s seems replaced with nothing, '
                            'finding a parent\n' % (hexshort(r)))
                    pctx = repo[r].parents()[0]
                    if pctx.node() in replacemap:
                        ui.debug('histedit: parent is already replaced\n')
                        replacemap[r] = replacemap[pctx.node()]
                    else:
                        replacemap[r] = pctx.node()
                    ui.debug('histedit: %s best replaced by %s\n' % (
                        hexshort(r), hexshort(replacemap[r])))
                else:
                    assert len(created_) == 1
                    for r in replaced_:
                        ui.debug('histedit: %s replaced by %s\n' % (
                            hexshort(r), hexshort(created_[0])))
                        replacemap[r] = created_[0]
            else:
                assert False, (
                    'Unhandled case in replacement mapping! '
                    'replacing %d changes with %d changes' % (rlen, clen))
        created.extend(created_)
        replaced.extend(replaced_)
        tmpnodes.extend(tmpnodes_)

    hg.update(repo, parentctx.node())

    if not keep:
        if replacemap:
            ui.note('histedit: Should update metadata for the following '
                    'changes:\n')
            for old, new in replacemap.iteritems():
                if old in tmpnodes or old in created:
                    # can't have any metadata we'd want to update
                    continue
                while new in replacemap:
                    new = replacemap[new]
                ui.note('histedit:  %s to %s\n' % (hexshort(old), hexshort(new)))
                octx = repo[old]
                if bookmarks is not None:
                    marks = octx.bookmarks()
                    if marks:
                        ui.note('histedit:     moving bookmarks %s\n' %
                                ', '.join(marks))
                        for mark in marks:
                            repo._bookmarks[mark] = new
                        bookmarks.write(repo)
                # TODO update mq state

        ui.debug('should strip replaced nodes %s\n' %
                 ', '.join([node.hex(n)[:12] for n in replaced]))
        for n in sorted(replaced, key=lambda x: repo[x].rev()):
            try:
                repair.strip(ui, repo, n)
            except error.LookupError:
                pass

    ui.debug('should strip temp nodes %s\n' %
             ', '.join([node.hex(n)[:12] for n in tmpnodes]))
    for n in reversed(tmpnodes):
        try:
            repair.strip(ui, repo, n)
        except error.LookupError:
            pass
    os.unlink(os.path.join(repo.path, 'histedit-state'))
    if os.path.exists(repo.sjoin('undo')):
        os.unlink(repo.sjoin('undo'))
Exemplo n.º 48
0
def _histedit(ui, repo, state, *freeargs, **opts):
    # TODO only abort if we try and histedit mq patches, not just
    # blanket if mq patches are applied somewhere
    mq = getattr(repo, 'mq', None)
    if mq and mq.applied:
        raise util.Abort(_('source has mq patches applied'))

    # basic argument incompatibility processing
    outg = opts.get('outgoing')
    cont = opts.get('continue')
    editplan = opts.get('edit_plan')
    abort = opts.get('abort')
    force = opts.get('force')
    rules = opts.get('commands', '')
    revs = opts.get('rev', [])
    goal = 'new' # This invocation goal, in new, continue, abort
    if force and not outg:
        raise util.Abort(_('--force only allowed with --outgoing'))
    if cont:
        if util.any((outg, abort, revs, freeargs, rules, editplan)):
            raise util.Abort(_('no arguments allowed with --continue'))
        goal = 'continue'
    elif abort:
        if util.any((outg, revs, freeargs, rules, editplan)):
            raise util.Abort(_('no arguments allowed with --abort'))
        goal = 'abort'
    elif editplan:
        if util.any((outg, revs, freeargs)):
            raise util.Abort(_('only --commands argument allowed with '
                               '--edit-plan'))
        goal = 'edit-plan'
    else:
        if os.path.exists(os.path.join(repo.path, 'histedit-state')):
            raise util.Abort(_('history edit already in progress, try '
                               '--continue or --abort'))
        if outg:
            if revs:
                raise util.Abort(_('no revisions allowed with --outgoing'))
            if len(freeargs) > 1:
                raise util.Abort(
                    _('only one repo argument allowed with --outgoing'))
        else:
            revs.extend(freeargs)
            if len(revs) == 0:
                histeditdefault = ui.config('histedit', 'defaultrev')
                if histeditdefault:
                    revs.append(histeditdefault)
            if len(revs) != 1:
                raise util.Abort(
                    _('histedit requires exactly one ancestor revision'))


    replacements = []
    keep = opts.get('keep', False)

    # rebuild state
    if goal == 'continue':
        state.read()
        state = bootstrapcontinue(ui, state, opts)
    elif goal == 'edit-plan':
        state.read()
        if not rules:
            comment = editcomment % (state.parentctx, node.short(state.topmost))
            rules = ruleeditor(repo, ui, state.rules, comment)
        else:
            if rules == '-':
                f = sys.stdin
            else:
                f = open(rules)
            rules = f.read()
            f.close()
        rules = [l for l in (r.strip() for r in rules.splitlines())
                 if l and not l.startswith('#')]
        rules = verifyrules(rules, repo, [repo[c] for [_a, c] in state.rules])
        state.rules = rules
        state.write()
        return
    elif goal == 'abort':
        state.read()
        mapping, tmpnodes, leafs, _ntm = processreplacement(state)
        ui.debug('restore wc to old parent %s\n' % node.short(state.topmost))

        # Recover our old commits if necessary
        if not state.topmost in repo and state.backupfile:
            backupfile = repo.join(state.backupfile)
            f = hg.openpath(ui, backupfile)
            gen = exchange.readbundle(ui, f, backupfile)
            changegroup.addchangegroup(repo, gen, 'histedit',
                                       'bundle:' + backupfile)
            os.remove(backupfile)

        # check whether we should update away
        parentnodes = [c.node() for c in repo[None].parents()]
        for n in leafs | set([state.parentctxnode]):
            if n in parentnodes:
                hg.clean(repo, state.topmost)
                break
        else:
            pass
        cleanupnode(ui, repo, 'created', tmpnodes)
        cleanupnode(ui, repo, 'temp', leafs)
        state.clear()
        return
    else:
        cmdutil.checkunfinished(repo)
        cmdutil.bailifchanged(repo)

        topmost, empty = repo.dirstate.parents()
        if outg:
            if freeargs:
                remote = freeargs[0]
            else:
                remote = None
            root = findoutgoing(ui, repo, remote, force, opts)
        else:
            rr = list(repo.set('roots(%ld)', scmutil.revrange(repo, revs)))
            if len(rr) != 1:
                raise util.Abort(_('The specified revisions must have '
                    'exactly one common root'))
            root = rr[0].node()

        revs = between(repo, root, topmost, keep)
        if not revs:
            raise util.Abort(_('%s is not an ancestor of working directory') %
                             node.short(root))

        ctxs = [repo[r] for r in revs]
        if not rules:
            comment = editcomment % (node.short(root), node.short(topmost))
            rules = ruleeditor(repo, ui, [['pick', c] for c in ctxs], comment)
        else:
            if rules == '-':
                f = sys.stdin
            else:
                f = open(rules)
            rules = f.read()
            f.close()
        rules = [l for l in (r.strip() for r in rules.splitlines())
                 if l and not l.startswith('#')]
        rules = verifyrules(rules, repo, ctxs)

        parentctxnode = repo[root].parents()[0].node()

        state.parentctxnode = parentctxnode
        state.rules = rules
        state.keep = keep
        state.topmost = topmost
        state.replacements = replacements

        # Create a backup so we can always abort completely.
        backupfile = None
        if not obsolete.isenabled(repo, obsolete.createmarkersopt):
            backupfile = repair._bundle(repo, [parentctxnode], [topmost], root,
                                        'histedit')
        state.backupfile = backupfile

    while state.rules:
        state.write()
        action, ha = state.rules.pop(0)
        ui.debug('histedit: processing %s %s\n' % (action, ha[:12]))
        actobj = actiontable[action].fromrule(state, ha)
        parentctx, replacement_ = actobj.run()
        state.parentctxnode = parentctx.node()
        state.replacements.extend(replacement_)
    state.write()

    hg.update(repo, state.parentctxnode)

    mapping, tmpnodes, created, ntm = processreplacement(state)
    if mapping:
        for prec, succs in mapping.iteritems():
            if not succs:
                ui.debug('histedit: %s is dropped\n' % node.short(prec))
            else:
                ui.debug('histedit: %s is replaced by %s\n' % (
                    node.short(prec), node.short(succs[0])))
                if len(succs) > 1:
                    m = 'histedit:                            %s'
                    for n in succs[1:]:
                        ui.debug(m % node.short(n))

    if not keep:
        if mapping:
            movebookmarks(ui, repo, mapping, state.topmost, ntm)
            # TODO update mq state
        if obsolete.isenabled(repo, obsolete.createmarkersopt):
            markers = []
            # sort by revision number because it sound "right"
            for prec in sorted(mapping, key=repo.changelog.rev):
                succs = mapping[prec]
                markers.append((repo[prec],
                                tuple(repo[s] for s in succs)))
            if markers:
                obsolete.createmarkers(repo, markers)
        else:
            cleanupnode(ui, repo, 'replaced', mapping)

    cleanupnode(ui, repo, 'temp', tmpnodes)
    state.clear()
    if os.path.exists(repo.sjoin('undo')):
        os.unlink(repo.sjoin('undo'))
Exemplo n.º 49
0
    def _applymerge(self, repo, patchfile, sim, name, parent, force=False, **opts):
        """applies a patch using fancy merge technology."""
        reverse = opts.get('reverse')
        opts['reverse'] = False

        def smwrapper(orig, *args, **opts):
            shelf = 'shelf:%s' % name
            if reverse:
                shelf += ' --reverse'
            opts['label'] = ['local', shelf]
            return orig(*args, **opts)

        def savediff():
            opts = {'git': True}
            fp = opener('.saved', 'w')
            for chunk in patch.diff(repo, head, None,
                                     opts=patch.diffopts(self.ui, opts)):
                fp.write(chunk)
            fp.close()

        def applydiff(name):
            files = {}
            patch.patch(self.join(patchfile), self.ui, strip=1, files=files)
            files2 = {}
            for k in files.keys():
                files2[k.strip('\r')]=files[k]
            updatedir(self.ui, repo, files2, similarity=sim/100.)
        opener = util.opener('.hg/attic')
        smo = extensions.wrapfunction(simplemerge, 'simplemerge', smwrapper)
        quiet = self.ui.quiet
        self.ui.quiet = True
        whead, phead = None, None
        success = False
        try:
            head = repo.dirstate.parents()[0]
            # Save the open changes
            self.ui.note(_("saving open changes\n"))
            n = repo.commit('working', 'hgattic', None, force=1)
            savediff()
            whead = repo.heads(None)[0]
            # Set the workspace to match the base version for patching
            self.ui.note(_("applying diff to version specified in patch\n"))
            hg.clean(repo, parent)
            applydiff(self.join(patchfile))
            n = repo.commit('patched', 'hgattic', None, force=1)
            phead = repo.heads(None)[0]
            if reverse:
                # Merge, using the working copy to avoid conflicts
                self.ui.note(_("applying reverse\n"))
                hgmerge = os.environ.get('HGMERGE')
                os.environ['HGMERGE'] = 'internal:other'
                hg.merge(repo, whead, force=True)
                os.environ['HGMERGE'] = hgmerge
                # Backout the patched version, this is where we want conflicts
                repo.commit('merge', 'hgattic', None, force=1)
                backout_opts = {'rev': phead, 'merge': True,
                                'message': 'backout'}
                commands.backout(self.ui, repo, **backout_opts)
            else:
                # Merge the working copy with the patched copy
                self.ui.note(_("merging patch forward\n"))
                hg.merge(repo, whead, force=True)
            savediff()
            success = True
        finally:
            simplemerge.simplemerge = smo
            self.ui.note(_("cleanup\n"))
            hg.clean(repo, head)
            strip_opts = {'backup': False, 'nobackup': True, 'force': False}
            if phead and head != phead:
                self.strip(repo, phead)
            if whead and head != whead:
                self.strip(repo, whead)
            if not success:
                applydiff('.saved')
            self.ui.quiet = quiet
        if success:
            self.ui.note(_("applying updated patch\n"))
            success = self._applypatch(repo, '.saved', sim, force, **opts)
        return success
Exemplo n.º 50
0
def histedit(ui, repo, *parent, **opts):
    """hg histedit <parent>
    """
    # TODO only abort if we try and histedit mq patches, not just
    # blanket if mq patches are applied somewhere
    mq = getattr(repo, "mq", None)
    if mq and mq.applied:
        raise util.Abort(_("source has mq patches applied"))

    parent = list(parent) + opts.get("rev", [])
    if opts.get("outgoing"):
        if len(parent) > 1:
            raise util.Abort("only one repo argument allowed with --outgoing")
        elif parent:
            parent = parent[0]

        dest = ui.expandpath(parent or "default-push", parent or "default")
        dest, revs = hg.parseurl(dest, None)[:2]
        if isinstance(revs, tuple):
            # hg >= 1.6
            revs, checkout = hg.addbranchrevs(repo, repo, revs, None)
            other = hg.repository(hg.remoteui(repo, opts), dest)
            # hg >= 1.9
            findoutgoing = getattr(discovery, "findoutgoing", None)
            if findoutgoing is None:

                def findoutgoing(repo, other, force=False):
                    common, outheads = discovery.findcommonoutgoing(repo, other, [], force=force)
                    return repo.changelog.findmissing(common, outheads)[0:1]

        else:
            other = hg.repository(ui, dest)

            def findoutgoing(repo, other, force=False):
                return repo.findoutgoing(other, force=force)

        if revs:
            revs = [repo.lookup(rev) for rev in revs]

        ui.status(_("comparing with %s\n") % hidepassword(dest))
        parent = findoutgoing(repo, other, force=opts.get("force"))
    else:
        if opts.get("force"):
            raise util.Abort("--force only allowed with --outgoing")

    if opts.get("continue", False):
        if len(parent) != 0:
            raise util.Abort("no arguments allowed with --continue")
        (parentctxnode, created, replaced, tmpnodes, existing, rules, keep, tip) = readstate(repo)
        currentparent, wantnull = repo.dirstate.parents()
        parentctx = repo[parentctxnode]
        # discover any nodes the user has added in the interim
        newchildren = [c for c in parentctx.children() if c.node() not in existing]
        action, currentnode = rules.pop(0)
        while newchildren:
            if action in ["f", "fold"]:
                tmpnodes.extend([n.node() for n in newchildren])
            else:
                created.extend([n.node() for n in newchildren])
            newchildren = filter(
                lambda x: x.node() not in existing, reduce(lambda x, y: x + y, map(lambda r: r.children(), newchildren))
            )
        m, a, r, d = repo.status()[:4]
        oldctx = repo[currentnode]
        message = oldctx.description()
        if action in ("e", "edit"):
            message = ui.edit(message, ui.username())
        elif action in ("f", "fold"):
            message = "fold-temp-revision %s" % currentnode
        new = None
        if m or a or r or d:
            new = repo.commit(text=message, user=oldctx.user(), date=oldctx.date(), extra=oldctx.extra())

        if action in ("e", "edit", "p", "pick"):
            if new != oldctx.node():
                replaced.append(oldctx.node())
            if new:
                if new != oldctx.node():
                    created.append(new)
                parentctx = repo[new]
        else:  # fold
            if new:
                tmpnodes.append(new)
            else:
                new = newchildren[-1]
            (parentctx, created_, replaced_, tmpnodes_) = finishfold(
                ui, repo, parentctx, oldctx, new, opts, newchildren
            )
            replaced.extend(replaced_)
            created.extend(created_)
            tmpnodes.extend(tmpnodes_)

    elif opts.get("abort", False):
        if len(parent) != 0:
            raise util.Abort("no arguments allowed with --abort")
        (parentctxnode, created, replaced, tmpnodes, existing, rules, keep, tip) = readstate(repo)
        ui.debug("restore wc to old tip %s\n" % node.hex(tip))
        hg.clean(repo, tip)
        ui.debug("should strip created nodes %s\n" % ", ".join([node.hex(n)[:12] for n in created]))
        ui.debug("should strip temp nodes %s\n" % ", ".join([node.hex(n)[:12] for n in tmpnodes]))
        for nodes in (created, tmpnodes):
            for n in reversed(nodes):
                try:
                    repair.strip(ui, repo, n)
                except error.LookupError:
                    pass
        os.unlink(os.path.join(repo.path, "histedit-state"))
        return
    else:
        bailifchanged(repo)
        if os.path.exists(os.path.join(repo.path, "histedit-state")):
            raise util.Abort("history edit already in progress, try " "--continue or --abort")

        tip, empty = repo.dirstate.parents()

        if len(parent) != 1:
            raise util.Abort("requires exactly one parent revision")
        parent = _revsingle(repo, parent[0]).node()

        keep = opts.get("keep", False)
        revs = between(repo, parent, tip, keep)

        ctxs = [repo[r] for r in revs]
        existing = [r.node() for r in ctxs]
        rules = opts.get("commands", "")
        if not rules:
            rules = "\n".join([("pick %s %s" % (c.hex()[:12], c.description().splitlines()[0]))[:80] for c in ctxs])
            rules += editcomment % (node.hex(parent)[:12], node.hex(tip)[:12])
            rules = ui.edit(rules, ui.username())
        else:
            f = open(rules)
            rules = f.read()
            f.close()
        rules = [l for l in (r.strip() for r in rules.splitlines()) if l and not l[0] == "#"]
        rules = verifyrules(rules, repo, ctxs)

        parentctx = repo[parent].parents()[0]
        keep = opts.get("keep", False)
        replaced = []
        tmpnodes = []
        created = []

    while rules:
        writestate(repo, parentctx.node(), created, replaced, tmpnodes, existing, rules, keep, tip)
        action, ha = rules.pop(0)
        (parentctx, created_, replaced_, tmpnodes_) = actiontable[action](ui, repo, parentctx, ha, opts)
        created.extend(created_)
        replaced.extend(replaced_)
        tmpnodes.extend(tmpnodes_)

    hg.update(repo, parentctx.node())

    if not keep:
        ui.debug("should strip replaced nodes %s\n" % ", ".join([node.hex(n)[:12] for n in replaced]))
        for n in sorted(replaced, lambda x, y: cmp(repo[x].rev(), repo[y].rev())):
            try:
                repair.strip(ui, repo, n)
            except error.LookupError:
                pass

    ui.debug("should strip temp nodes %s\n" % ", ".join([node.hex(n)[:12] for n in tmpnodes]))
    for n in reversed(tmpnodes):
        try:
            repair.strip(ui, repo, n)
        except error.LookupError:
            pass
    os.unlink(os.path.join(repo.path, "histedit-state"))
Exemplo n.º 51
0
def _narrow(
    ui,
    repo,
    remote,
    commoninc,
    oldincludes,
    oldexcludes,
    newincludes,
    newexcludes,
    force,
    backup,
):
    oldmatch = narrowspec.match(repo.root, oldincludes, oldexcludes)
    newmatch = narrowspec.match(repo.root, newincludes, newexcludes)

    # This is essentially doing "hg outgoing" to find all local-only
    # commits. We will then check that the local-only commits don't
    # have any changes to files that will be untracked.
    unfi = repo.unfiltered()
    outgoing = discovery.findcommonoutgoing(unfi, remote, commoninc=commoninc)
    ui.status(_(b'looking for local changes to affected paths\n'))
    progress = ui.makeprogress(
        topic=_(b'changesets'),
        unit=_(b'changesets'),
        total=len(outgoing.missing) + len(outgoing.excluded),
    )
    localnodes = []
    with progress:
        for n in itertools.chain(outgoing.missing, outgoing.excluded):
            progress.increment()
            if any(oldmatch(f) and not newmatch(f) for f in unfi[n].files()):
                localnodes.append(n)
    revstostrip = unfi.revs(b'descendants(%ln)', localnodes)
    hiddenrevs = repoview.filterrevs(repo, b'visible')
    visibletostrip = list(
        repo.changelog.node(r) for r in (revstostrip - hiddenrevs))
    if visibletostrip:
        ui.status(
            _(b'The following changeset(s) or their ancestors have '
              b'local changes not on the remote:\n'))
        maxnodes = 10
        if ui.verbose or len(visibletostrip) <= maxnodes:
            for n in visibletostrip:
                ui.status(b'%s\n' % short(n))
        else:
            for n in visibletostrip[:maxnodes]:
                ui.status(b'%s\n' % short(n))
            ui.status(
                _(b'...and %d more, use --verbose to list all\n') %
                (len(visibletostrip) - maxnodes))
        if not force:
            raise error.StateError(
                _(b'local changes found'),
                hint=_(b'use --force-delete-local-changes to ignore'),
            )

    with ui.uninterruptible():
        if revstostrip:
            tostrip = [unfi.changelog.node(r) for r in revstostrip]
            if repo[b'.'].node() in tostrip:
                # stripping working copy, so move to a different commit first
                urev = max(
                    repo.revs(
                        b'(::%n) - %ln + null',
                        repo[b'.'].node(),
                        visibletostrip,
                    ))
                hg.clean(repo, urev)
            overrides = {(b'devel', b'strip-obsmarkers'): False}
            if backup:
                ui.status(_(b'moving unwanted changesets to backup\n'))
            else:
                ui.status(_(b'deleting unwanted changesets\n'))
            with ui.configoverride(overrides, b'narrow'):
                repair.strip(ui, unfi, tostrip, topic=b'narrow', backup=backup)

        todelete = []
        for t, f, f2, size in repo.store.datafiles():
            if f.startswith(b'data/'):
                file = f[5:-2]
                if not newmatch(file):
                    todelete.append(f)
            elif f.startswith(b'meta/'):
                dir = f[5:-13]
                dirs = sorted(pathutil.dirs({dir})) + [dir]
                include = True
                for d in dirs:
                    visit = newmatch.visitdir(d)
                    if not visit:
                        include = False
                        break
                    if visit == b'all':
                        break
                if not include:
                    todelete.append(f)

        repo.destroying()

        with repo.transaction(b'narrowing'):
            # Update narrowspec before removing revlogs, so repo won't be
            # corrupt in case of crash
            repo.setnarrowpats(newincludes, newexcludes)

            for f in todelete:
                ui.status(_(b'deleting %s\n') % f)
                util.unlinkpath(repo.svfs.join(f))
                repo.store.markremoved(f)

            ui.status(_(b'deleting unwanted files from working copy\n'))
            with repo.dirstate.parentchange():
                narrowspec.updateworkingcopy(repo, assumeclean=True)
                narrowspec.copytoworkingcopy(repo)

        repo.destroyed()
Exemplo n.º 52
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))
Exemplo n.º 53
0
def split(ui, repo, *revs, **opts):
    """split a changeset into smaller ones

    Repeatedly prompt changes and commit message for new changesets until there
    is nothing left in the original changeset.

    If --rev was not given, split the working directory parent.

    By default, rebase connected non-obsoleted descendants onto the new
    changeset. Use --no-rebase to avoid the rebase.
    """
    opts = pycompat.byteskwargs(opts)
    revlist = []
    if opts.get(b'rev'):
        revlist.append(opts.get(b'rev'))
    revlist.extend(revs)
    with repo.wlock(), repo.lock(), repo.transaction(b'split') as tr:
        revs = scmutil.revrange(repo, revlist or [b'.'])
        if len(revs) > 1:
            raise error.Abort(_(b'cannot split multiple revisions'))

        rev = revs.first()
        ctx = repo[rev]
        if rev is None or ctx.node() == nullid:
            ui.status(_(b'nothing to split\n'))
            return 1
        if ctx.node() is None:
            raise error.Abort(_(b'cannot split working directory'))

        # rewriteutil.precheck is not very useful here because:
        # 1. null check is done above and it's more friendly to return 1
        #    instead of abort
        # 2. mergestate check is done below by cmdutil.bailifchanged
        # 3. unstable check is more complex here because of --rebase
        #
        # So only "public" check is useful and it's checked directly here.
        if ctx.phase() == phases.public:
            raise error.Abort(
                _(b'cannot split public changeset'),
                hint=_(b"see 'hg help phases' for details"),
            )

        descendants = list(repo.revs(b'(%d::) - (%d)', rev, rev))
        alloworphaned = obsolete.isenabled(repo, obsolete.allowunstableopt)
        if opts.get(b'rebase'):
            # Skip obsoleted descendants and their descendants so the rebase
            # won't cause conflicts for sure.
            torebase = list(
                repo.revs(b'%ld - (%ld & obsolete())::', descendants,
                          descendants))
            if not alloworphaned and len(torebase) != len(descendants):
                raise error.Abort(
                    _(b'split would leave orphaned changesets behind'))
        else:
            if not alloworphaned and descendants:
                raise error.Abort(
                    _(b'cannot split changeset with children without rebase'))
            torebase = ()

        if len(ctx.parents()) > 1:
            raise error.Abort(_(b'cannot split a merge changeset'))

        cmdutil.bailifchanged(repo)

        # Deactivate bookmark temporarily so it won't get moved unintentionally
        bname = repo._activebookmark
        if bname and repo._bookmarks[bname] != ctx.node():
            bookmarks.deactivate(repo)

        wnode = repo[b'.'].node()
        top = None
        try:
            top = dosplit(ui, repo, tr, ctx, opts)
        finally:
            # top is None: split failed, need update --clean recovery.
            # wnode == ctx.node(): wnode split, no need to update.
            if top is None or wnode != ctx.node():
                hg.clean(repo, wnode, show_stats=False)
            if bname:
                bookmarks.activate(repo, bname)
        if torebase and top:
            dorebase(ui, repo, torebase, top)
Exemplo n.º 54
0
def fetch(ui, repo, source='default', **opts):
    '''pull changes from a remote repository, merge new changes if needed.

    This finds all changes from the repository at the specified path
    or URL and adds them to the local repository.

    If the pulled changes add a new branch head, the head is
    automatically merged, and the result of the merge is committed.
    Otherwise, the working directory is updated to include the new
    changes.

    When a merge occurs, the newly pulled changes are assumed to be
    "authoritative". The head of the new changes is used as the first
    parent, with local changes as the second. To switch the merge
    order, use --switch-parent.

    See 'hg help dates' for a list of formats valid for -d/--date.
    '''

    date = opts.get('date')
    if date:
        opts['date'] = util.parsedate(date)

    parent, p2 = repo.dirstate.parents()
    branch = repo.dirstate.branch()
    branchnode = repo.branchtags().get(branch)
    if parent != branchnode:
        raise util.Abort(_('working dir not at branch tip '
                           '(use "hg update" to check out branch tip)'))

    if p2 != nullid:
        raise util.Abort(_('outstanding uncommitted merge'))

    wlock = lock = None
    try:
        wlock = repo.wlock()
        lock = repo.lock()
        mod, add, rem, del_ = repo.status()[:4]

        if mod or add or rem:
            raise util.Abort(_('outstanding uncommitted changes'))
        if del_:
            raise util.Abort(_('working directory is missing some files'))
        bheads = repo.branchheads(branch)
        bheads = [head for head in bheads if len(repo[head].children()) == 0]
        if len(bheads) > 1:
            raise util.Abort(_('multiple heads in this branch '
                               '(use "hg heads ." and "hg merge" to merge)'))

        other = hg.repository(cmdutil.remoteui(repo, opts),
                              ui.expandpath(source))
        ui.status(_('pulling from %s\n') %
                  url.hidepassword(ui.expandpath(source)))
        revs = None
        if opts['rev']:
            try:
                revs = [other.lookup(rev) for rev in opts['rev']]
            except error.CapabilityError:
                err = _("Other repository doesn't support revision lookup, "
                        "so a rev cannot be specified.")
                raise util.Abort(err)

        # Are there any changes at all?
        modheads = repo.pull(other, heads=revs)
        if modheads == 0:
            return 0

        # Is this a simple fast-forward along the current branch?
        newheads = repo.branchheads(branch)
        newheads = [head for head in newheads if len(repo[head].children()) == 0]
        newchildren = repo.changelog.nodesbetween([parent], newheads)[2]
        if len(newheads) == 1:
            if newchildren[0] != parent:
                return hg.clean(repo, newchildren[0])
            else:
                return

        # Are there more than one additional branch heads?
        newchildren = [n for n in newchildren if n != parent]
        newparent = parent
        if newchildren:
            newparent = newchildren[0]
            hg.clean(repo, newparent)
        newheads = [n for n in newheads if n != newparent]
        if len(newheads) > 1:
            ui.status(_('not merging with %d other new branch heads '
                        '(use "hg heads ." and "hg merge" to merge them)\n') %
                      (len(newheads) - 1))
            return

        # Otherwise, let's merge.
        err = False
        if newheads:
            # By default, we consider the repository we're pulling
            # *from* as authoritative, so we merge our changes into
            # theirs.
            if opts['switch_parent']:
                firstparent, secondparent = newparent, newheads[0]
            else:
                firstparent, secondparent = newheads[0], newparent
                ui.status(_('updating to %d:%s\n') %
                          (repo.changelog.rev(firstparent),
                           short(firstparent)))
            hg.clean(repo, firstparent)
            ui.status(_('merging with %d:%s\n') %
                      (repo.changelog.rev(secondparent), short(secondparent)))
            err = hg.merge(repo, secondparent, remind=False)

        if not err:
            # we don't translate commit messages
            message = (cmdutil.logmessage(opts) or
                       ('Automated merge with %s' %
                        url.removeauth(other.url())))
            editor = cmdutil.commiteditor
            if opts.get('force_editor') or opts.get('edit'):
                editor = cmdutil.commitforceeditor
            n = repo.commit(message, opts['user'], opts['date'], editor=editor)
            ui.status(_('new changeset %d:%s merges remote changes '
                        'with local\n') % (repo.changelog.rev(n),
                                           short(n)))

    finally:
        release(lock, wlock)
Exemplo n.º 55
0
def split(ui, repo, *revs, **opts):
    """split a changeset into smaller ones

    Repeatedly prompt changes and commit message for new changesets until there
    is nothing left in the original changeset.

    If --rev was not given, split the working directory parent.

    By default, rebase connected non-obsoleted descendants onto the new
    changeset. Use --no-rebase to avoid the rebase.
    """
    opts = pycompat.byteskwargs(opts)
    revlist = []
    if opts.get(b'rev'):
        revlist.append(opts.get(b'rev'))
    revlist.extend(revs)
    with repo.wlock(), repo.lock(), repo.transaction(b'split') as tr:
        revs = scmutil.revrange(repo, revlist or [b'.'])
        if len(revs) > 1:
            raise error.InputError(_(b'cannot split multiple revisions'))

        rev = revs.first()
        ctx = repo[rev]
        # Handle nullid specially here (instead of leaving for precheck()
        # below) so we get a nicer message and error code.
        if rev is None or ctx.node() == nullid:
            ui.status(_(b'nothing to split\n'))
            return 1
        if ctx.node() is None:
            raise error.InputError(_(b'cannot split working directory'))

        if opts.get(b'rebase'):
            # Skip obsoleted descendants and their descendants so the rebase
            # won't cause conflicts for sure.
            descendants = list(repo.revs(b'(%d::) - (%d)', rev, rev))
            torebase = list(
                repo.revs(b'%ld - (%ld & obsolete())::', descendants,
                          descendants))
        else:
            torebase = []
        rewriteutil.precheck(repo, [rev] + torebase, b'split')

        if len(ctx.parents()) > 1:
            raise error.InputError(_(b'cannot split a merge changeset'))

        cmdutil.bailifchanged(repo)

        # Deactivate bookmark temporarily so it won't get moved unintentionally
        bname = repo._activebookmark
        if bname and repo._bookmarks[bname] != ctx.node():
            bookmarks.deactivate(repo)

        wnode = repo[b'.'].node()
        top = None
        try:
            top = dosplit(ui, repo, tr, ctx, opts)
        finally:
            # top is None: split failed, need update --clean recovery.
            # wnode == ctx.node(): wnode split, no need to update.
            if top is None or wnode != ctx.node():
                hg.clean(repo, wnode, show_stats=False)
            if bname:
                bookmarks.activate(repo, bname)
        if torebase and top:
            dorebase(ui, repo, torebase, top)
Exemplo n.º 56
0
def fetch(ui, repo, source=b'default', **opts):
    """pull changes from a remote repository, merge new changes if needed.

    This finds all changes from the repository at the specified path
    or URL and adds them to the local repository.

    If the pulled changes add a new branch head, the head is
    automatically merged, and the result of the merge is committed.
    Otherwise, the working directory is updated to include the new
    changes.

    When a merge is needed, the working directory is first updated to
    the newly pulled changes. Local changes are then merged into the
    pulled changes. To switch the merge order, use --switch-parent.

    See :hg:`help dates` for a list of formats valid for -d/--date.

    Returns 0 on success.
    """

    opts = pycompat.byteskwargs(opts)
    date = opts.get(b'date')
    if date:
        opts[b'date'] = dateutil.parsedate(date)

    parent = repo.dirstate.p1()
    branch = repo.dirstate.branch()
    try:
        branchnode = repo.branchtip(branch)
    except error.RepoLookupError:
        branchnode = None
    if parent != branchnode:
        raise error.Abort(
            _(b'working directory not at branch tip'),
            hint=_(b"use 'hg update' to check out branch tip"),
        )

    wlock = lock = None
    try:
        wlock = repo.wlock()
        lock = repo.lock()

        cmdutil.bailifchanged(repo)

        bheads = repo.branchheads(branch)
        bheads = [head for head in bheads if len(repo[head].children()) == 0]
        if len(bheads) > 1:
            raise error.Abort(
                _(b'multiple heads in this branch '
                  b'(use "hg heads ." and "hg merge" to merge)'))

        other = hg.peer(repo, opts, ui.expandpath(source))
        ui.status(
            _(b'pulling from %s\n') % util.hidepassword(ui.expandpath(source)))
        revs = None
        if opts[b'rev']:
            try:
                revs = [other.lookup(rev) for rev in opts[b'rev']]
            except error.CapabilityError:
                err = _(b"other repository doesn't support revision lookup, "
                        b"so a rev cannot be specified.")
                raise error.Abort(err)

        # Are there any changes at all?
        modheads = exchange.pull(repo, other, heads=revs).cgresult
        if modheads == 0:
            return 0

        # Is this a simple fast-forward along the current branch?
        newheads = repo.branchheads(branch)
        newchildren = repo.changelog.nodesbetween([parent], newheads)[2]
        if len(newheads) == 1 and len(newchildren):
            if newchildren[0] != parent:
                return hg.update(repo, newchildren[0])
            else:
                return 0

        # Are there more than one additional branch heads?
        newchildren = [n for n in newchildren if n != parent]
        newparent = parent
        if newchildren:
            newparent = newchildren[0]
            hg.clean(repo, newparent)
        newheads = [n for n in newheads if n != newparent]
        if len(newheads) > 1:
            ui.status(
                _(b'not merging with %d other new branch heads '
                  b'(use "hg heads ." and "hg merge" to merge them)\n') %
                (len(newheads) - 1))
            return 1

        if not newheads:
            return 0

        # Otherwise, let's merge.
        err = False
        if newheads:
            # By default, we consider the repository we're pulling
            # *from* as authoritative, so we merge our changes into
            # theirs.
            if opts[b'switch_parent']:
                firstparent, secondparent = newparent, newheads[0]
            else:
                firstparent, secondparent = newheads[0], newparent
                ui.status(
                    _(b'updating to %d:%s\n') %
                    (repo.changelog.rev(firstparent), short(firstparent)))
            hg.clean(repo, firstparent)
            p2ctx = repo[secondparent]
            ui.status(
                _(b'merging with %d:%s\n') %
                (p2ctx.rev(), short(secondparent)))
            err = hg.merge(p2ctx, remind=False)

        if not err:
            # we don't translate commit messages
            message = cmdutil.logmessage(
                ui, opts) or (b'Automated merge with %s' %
                              util.removeauth(other.url()))
            editopt = opts.get(b'edit') or opts.get(b'force_editor')
            editor = cmdutil.getcommiteditor(edit=editopt, editform=b'fetch')
            n = repo.commit(message,
                            opts[b'user'],
                            opts[b'date'],
                            editor=editor)
            ui.status(
                _(b'new changeset %d:%s merges remote changes with local\n') %
                (repo.changelog.rev(n), short(n)))

        return err

    finally:
        release(lock, wlock)
Exemplo n.º 57
0
def histedit(ui, repo, *parent, **opts):
    """hg histedit <parent>
    """
    # TODO only abort if we try and histedit mq patches, not just
    # blanket if mq patches are applied somewhere
    mq = getattr(repo, 'mq', None)
    if mq and mq.applied:
        raise util.Abort(_('source has mq patches applied'))

    parent = list(parent) + opts.get('rev', [])
    if opts.get('outgoing'):
        if len(parent) > 1:
            raise util.Abort('only one repo argument allowed with --outgoing')
        elif parent:
            parent = parent[0]

        dest = ui.expandpath(parent or 'default-push', parent or 'default')
        dest, revs = hg.parseurl(dest, None)[:2]
        if isinstance(revs, tuple):
            # hg >= 1.6
            revs, checkout = hg.addbranchrevs(repo, repo, revs, None)
            other = hg.repository(hg.remoteui(repo, opts), dest)
            # hg >= 1.9
            findoutgoing = getattr(discovery, 'findoutgoing', None)
            if findoutgoing is None:
                if getattr(discovery, 'outgoing', None) is not None:
                    def findoutgoing(repo, other, force=False):
                        out = discovery.findcommonoutgoing(
                            repo, other, [], force=force)
                        return out.missing[0:1]
                else:
                    # hg 1.9 and 2.0
                    def findoutgoing(repo, other, force=False):
                        common, outheads = discovery.findcommonoutgoing(
                            repo, other, [], force=force)
                        return repo.changelog.findmissing(common, outheads)[0:1]
        else:
            other = hg.repository(ui, dest)
            def findoutgoing(repo, other, force=False):
                return repo.findoutgoing(other, force=force)

        if revs:
            revs = [repo.lookup(rev) for rev in revs]

        ui.status(_('comparing with %s\n') % hidepassword(dest))
        parent = findoutgoing(repo, other, force=opts.get('force'))
    else:
        if opts.get('force'):
            raise util.Abort('--force only allowed with --outgoing')

    if opts.get('continue', False):
        if len(parent) != 0:
            raise util.Abort('no arguments allowed with --continue')
        (parentctxnode, created, replaced,
         tmpnodes, existing, rules, keep, tip, ) = readstate(repo)
        currentparent, wantnull = repo.dirstate.parents()
        parentctx = repo[parentctxnode]
        # discover any nodes the user has added in the interim
        newchildren = [c for c in parentctx.children()
                       if c.node() not in existing]
        action, currentnode = rules.pop(0)
        while newchildren:
            if action in ['f', 'fold', ]:
                tmpnodes.extend([n.node() for n in newchildren])
            else:
                created.extend([n.node() for n in newchildren])
            newchildren = filter(lambda x: x.node() not in existing,
                                 reduce(lambda x, y: x + y,
                                        map(lambda r: r.children(),
                                            newchildren)))
        m, a, r, d = repo.status()[:4]
        oldctx = repo[currentnode]
        message = oldctx.description()
        if action in ('e', 'edit', 'm', 'mess'):
            message = ui.edit(message, ui.username())
        elif action in ('f', 'fold', ):
            message = 'fold-temp-revision %s' % currentnode
        new = None
        if m or a or r or d:
            new = repo.commit(text=message, user=oldctx.user(), date=oldctx.date(),
                              extra=oldctx.extra())

        if action in ('f', 'fold'):
            if new:
                tmpnodes.append(new)
            else:
                new = newchildren[-1]
            (parentctx, created_,
             replaced_, tmpnodes_, ) = finishfold(ui, repo,
                                                  parentctx, oldctx, new,
                                                  opts, newchildren)
            replaced.extend(replaced_)
            created.extend(created_)
            tmpnodes.extend(tmpnodes_)
        elif action not in ('d', 'drop'):
            if new != oldctx.node():
                replaced.append(oldctx.node())
            if new:
                if new != oldctx.node():
                    created.append(new)
                parentctx = repo[new]

    elif opts.get('abort', False):
        if len(parent) != 0:
            raise util.Abort('no arguments allowed with --abort')
        (parentctxnode, created, replaced, tmpnodes,
         existing, rules, keep, tip, ) = readstate(repo)
        ui.debug('restore wc to old tip %s\n' % node.hex(tip))
        hg.clean(repo, tip)
        ui.debug('should strip created nodes %s\n' %
                 ', '.join([node.hex(n)[:12] for n in created]))
        ui.debug('should strip temp nodes %s\n' %
                 ', '.join([node.hex(n)[:12] for n in tmpnodes]))
        for nodes in (created, tmpnodes, ):
            for n in reversed(nodes):
                try:
                    repair.strip(ui, repo, n)
                except error.LookupError:
                    pass
        os.unlink(os.path.join(repo.path, 'histedit-state'))
        return
    else:
        bailifchanged(repo)
        if os.path.exists(os.path.join(repo.path, 'histedit-state')):
            raise util.Abort('history edit already in progress, try '
                             '--continue or --abort')

        tip, empty = repo.dirstate.parents()


        if len(parent) != 1:
            raise util.Abort('requires exactly one parent revision')
        parent = _revsingle(repo, parent[0]).node()

        keep = opts.get('keep', False)
        revs = between(repo, parent, tip, keep)

        ctxs = [repo[r] for r in revs]
        existing = [r.node() for r in ctxs]
        rules = opts.get('commands', '')
        if not rules:
            rules = '\n'.join([makedesc(c) for c in ctxs])
            rules += editcomment % (node.hex(parent)[:12], node.hex(tip)[:12], )
            rules = ui.edit(rules, ui.username())
            # Save edit rules in .hg/histedit-last-edit.txt in case
            # the user needs to ask for help after something
            # surprising happens.
            f = open(repo.join('histedit-last-edit.txt'), 'w')
            f.write(rules)
            f.close()
        else:
            f = open(rules)
            rules = f.read()
            f.close()
        rules = [l for l in (r.strip() for r in rules.splitlines())
                 if l and not l[0] == '#']
        rules = verifyrules(rules, repo, ctxs)

        parentctx = repo[parent].parents()[0]
        keep = opts.get('keep', False)
        replaced = []
        tmpnodes = []
        created = []


    while rules:
        writestate(repo, parentctx.node(), created, replaced, tmpnodes, existing,
                   rules, keep, tip)
        action, ha = rules.pop(0)
        (parentctx, created_,
         replaced_, tmpnodes_, ) = actiontable[action](ui, repo,
                                                       parentctx, ha,
                                                       opts)
        created.extend(created_)
        replaced.extend(replaced_)
        tmpnodes.extend(tmpnodes_)

    hg.update(repo, parentctx.node())

    if not keep:
        ui.debug('should strip replaced nodes %s\n' %
                 ', '.join([node.hex(n)[:12] for n in replaced]))
        for n in sorted(replaced, lambda x, y: cmp(repo[x].rev(), repo[y].rev())):
            try:
                repair.strip(ui, repo, n)
            except error.LookupError:
                pass

    ui.debug('should strip temp nodes %s\n' %
             ', '.join([node.hex(n)[:12] for n in tmpnodes]))
    for n in reversed(tmpnodes):
        try:
            repair.strip(ui, repo, n)
        except error.LookupError:
            pass
    os.unlink(os.path.join(repo.path, 'histedit-state'))