Beispiel #1
0
def _dounshelve(ui, repo, *shelved, **opts):
    opts = pycompat.byteskwargs(opts)
    abortf = opts.get('abort')
    continuef = opts.get('continue')
    if not abortf and not continuef:
        cmdutil.checkunfinished(repo)
    shelved = list(shelved)
    if opts.get("name"):
        shelved.append(opts["name"])

    if abortf or continuef:
        if abortf and continuef:
            raise error.Abort(_('cannot use both abort and continue'))
        if shelved:
            raise error.Abort(_('cannot combine abort/continue with '
                               'naming a shelved change'))
        if abortf and opts.get('tool', False):
            ui.warn(_('tool option will be ignored\n'))

        try:
            state = shelvedstate.load(repo)
            if opts.get('keep') is None:
                opts['keep'] = state.keep
        except IOError as err:
            if err.errno != errno.ENOENT:
                raise
            cmdutil.wrongtooltocontinue(repo, _('unshelve'))
        except error.CorruptedState as err:
            ui.debug(pycompat.bytestr(err) + '\n')
            if continuef:
                msg = _('corrupted shelved state file')
                hint = _('please run hg unshelve --abort to abort unshelve '
                         'operation')
                raise error.Abort(msg, hint=hint)
            elif abortf:
                msg = _('could not read shelved state file, your working copy '
                        'may be in an unexpected state\nplease update to some '
                        'commit\n')
                ui.warn(msg)
                shelvedstate.clear(repo)
            return

        if abortf:
            return unshelveabort(ui, repo, state, opts)
        elif continuef:
            return unshelvecontinue(ui, repo, state, opts)
    elif len(shelved) > 1:
        raise error.Abort(_('can only unshelve one change at a time'))
    elif not shelved:
        shelved = listshelves(repo)
        if not shelved:
            raise error.Abort(_('no shelved changes to apply!'))
        basename = util.split(shelved[0][1])[1]
        ui.status(_("unshelving change '%s'\n") % basename)
    else:
        basename = shelved[0]

    if not shelvedfile(repo, basename, patchextension).exists():
        raise error.Abort(_("shelved change '%s' not found") % basename)

    lock = tr = None
    try:
        lock = repo.lock()
        tr = repo.transaction('unshelve', report=lambda x: None)
        oldtiprev = len(repo)

        pctx = repo['.']
        tmpwctx = pctx
        # The goal is to have a commit structure like so:
        # ...-> pctx -> tmpwctx -> shelvectx
        # where tmpwctx is an optional commit with the user's pending changes
        # and shelvectx is the unshelved changes. Then we merge it all down
        # to the original pctx.

        activebookmark = _backupactivebookmark(repo)
        tmpwctx, addedbefore = _commitworkingcopychanges(ui, repo, opts,
                                                         tmpwctx)
        repo, shelvectx = _unshelverestorecommit(ui, repo, basename)
        _checkunshelveuntrackedproblems(ui, repo, shelvectx)
        branchtorestore = ''
        if shelvectx.branch() != shelvectx.p1().branch():
            branchtorestore = shelvectx.branch()

        shelvectx = _rebaserestoredcommit(ui, repo, opts, tr, oldtiprev,
                                          basename, pctx, tmpwctx,
                                          shelvectx, branchtorestore,
                                          activebookmark)
        overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
        with ui.configoverride(overrides, 'unshelve'):
            mergefiles(ui, repo, pctx, shelvectx)
        restorebranch(ui, repo, branchtorestore)
        _forgetunknownfiles(repo, shelvectx, addedbefore)

        shelvedstate.clear(repo)
        _finishunshelve(repo, oldtiprev, tr, activebookmark)
        unshelvecleanup(ui, repo, basename, opts)
    finally:
        if tr:
            tr.release()
        lockmod.release(lock)
Beispiel #2
0
def _dounshelve(ui, repo, *shelved, **opts):
    abortf = opts.get('abort')
    continuef = opts.get('continue')
    if not abortf and not continuef:
        cmdutil.checkunfinished(repo)
    shelved = list(shelved)
    if opts.get("name"):
        shelved.append(opts["name"])

    if abortf or continuef:
        if abortf and continuef:
            raise error.Abort(_('cannot use both abort and continue'))
        if shelved:
            raise error.Abort(_('cannot combine abort/continue with '
                               'naming a shelved change'))
        if abortf and opts.get('tool', False):
            ui.warn(_('tool option will be ignored\n'))

        try:
            state = shelvedstate.load(repo)
            if opts.get('keep') is None:
                opts['keep'] = state.keep
        except IOError as err:
            if err.errno != errno.ENOENT:
                raise
            cmdutil.wrongtooltocontinue(repo, _('unshelve'))
        except error.CorruptedState as err:
            ui.debug(str(err) + '\n')
            if continuef:
                msg = _('corrupted shelved state file')
                hint = _('please run hg unshelve --abort to abort unshelve '
                         'operation')
                raise error.Abort(msg, hint=hint)
            elif abortf:
                msg = _('could not read shelved state file, your working copy '
                        'may be in an unexpected state\nplease update to some '
                        'commit\n')
                ui.warn(msg)
                shelvedstate.clear(repo)
            return

        if abortf:
            return unshelveabort(ui, repo, state, opts)
        elif continuef:
            return unshelvecontinue(ui, repo, state, opts)
    elif len(shelved) > 1:
        raise error.Abort(_('can only unshelve one change at a time'))
    elif not shelved:
        shelved = listshelves(repo)
        if not shelved:
            raise error.Abort(_('no shelved changes to apply!'))
        basename = util.split(shelved[0][1])[1]
        ui.status(_("unshelving change '%s'\n") % basename)
    else:
        basename = shelved[0]

    if not shelvedfile(repo, basename, patchextension).exists():
        raise error.Abort(_("shelved change '%s' not found") % basename)

    lock = tr = None
    obsshelve = True
    obsshelvedfile = shelvedfile(repo, basename, 'oshelve')
    if not obsshelvedfile.exists():
        # although we can unshelve a obs-based shelve technically,
        # this particular shelve was created using a traditional way
        obsshelve = False
        ui.note(_("falling back to traditional unshelve since "
                  "shelve was traditional"))
    try:
        lock = repo.lock()
        tr = repo.transaction('unshelve', report=lambda x: None)
        oldtiprev = len(repo)

        pctx = repo['.']
        tmpwctx = pctx
        # The goal is to have a commit structure like so:
        # ...-> pctx -> tmpwctx -> shelvectx
        # where tmpwctx is an optional commit with the user's pending changes
        # and shelvectx is the unshelved changes. Then we merge it all down
        # to the original pctx.

        activebookmark = _backupactivebookmark(repo)
        tmpwctx, addedbefore = _commitworkingcopychanges(ui, repo, opts,
                                                         tmpwctx)
        repo, shelvectx = _unshelverestorecommit(ui, repo, basename, obsshelve)
        _checkunshelveuntrackedproblems(ui, repo, shelvectx)
        branchtorestore = ''
        if shelvectx.branch() != shelvectx.p1().branch():
            branchtorestore = shelvectx.branch()

        rebaseconfigoverrides = {('ui', 'forcemerge'): opts.get('tool', ''),
                                 ('experimental', 'rebaseskipobsolete'): 'off'}
        with ui.configoverride(rebaseconfigoverrides, 'unshelve'):
            shelvectx = _rebaserestoredcommit(ui, repo, opts, tr, oldtiprev,
                                              basename, pctx, tmpwctx,
                                              shelvectx, branchtorestore,
                                              activebookmark, obsshelve)
            mergefiles(ui, repo, pctx, shelvectx)
            restorebranch(ui, repo, branchtorestore)
            _forgetunknownfiles(repo, shelvectx, addedbefore)

        if obsshelve:
            _obsoleteredundantnodes(repo, tr, pctx, shelvectx, tmpwctx)

        shelvedstate.clear(repo)
        _finishunshelve(repo, oldtiprev, tr, activebookmark, obsshelve)
        unshelvecleanup(ui, repo, basename, opts)
    finally:
        if tr:
            tr.release()
        lockmod.release(lock)
Beispiel #3
0
def _dounshelve(ui, repo, *shelved, **opts):
    abortf = opts.get('abort')
    continuef = opts.get('continue')
    if not abortf and not continuef:
        cmdutil.checkunfinished(repo)

    if abortf or continuef:
        if abortf and continuef:
            raise error.Abort(_('cannot use both abort and continue'))
        if shelved:
            raise error.Abort(
                _('cannot combine abort/continue with '
                  'naming a shelved change'))
        if abortf and opts.get('tool', False):
            ui.warn(_('tool option will be ignored\n'))

        try:
            state = shelvedstate.load(repo)
        except IOError as err:
            if err.errno != errno.ENOENT:
                raise
            cmdutil.wrongtooltocontinue(repo, _('unshelve'))
        except error.CorruptedState as err:
            ui.debug(str(err) + '\n')
            if continuef:
                msg = _('corrupted shelved state file')
                hint = _('please run hg unshelve --abort to abort unshelve '
                         'operation')
                raise error.Abort(msg, hint=hint)
            elif abortf:
                msg = _('could not read shelved state file, your working copy '
                        'may be in an unexpected state\nplease update to some '
                        'commit\n')
                ui.warn(msg)
                shelvedstate.clear(repo)
            return

        if abortf:
            return unshelveabort(ui, repo, state, opts)
        elif continuef:
            return unshelvecontinue(ui, repo, state, opts)
    elif len(shelved) > 1:
        raise error.Abort(_('can only unshelve one change at a time'))
    elif not shelved:
        shelved = listshelves(repo)
        if not shelved:
            raise error.Abort(_('no shelved changes to apply!'))
        basename = util.split(shelved[0][1])[1]
        ui.status(_("unshelving change '%s'\n") % basename)
    else:
        basename = shelved[0]

    if not shelvedfile(repo, basename, 'patch').exists():
        raise error.Abort(_("shelved change '%s' not found") % basename)

    oldquiet = ui.quiet
    lock = tr = None
    forcemerge = ui.backupconfig('ui', 'forcemerge')
    try:
        ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'unshelve')
        lock = repo.lock()

        tr = repo.transaction('unshelve', report=lambda x: None)
        oldtiprev = len(repo)

        pctx = repo['.']
        tmpwctx = pctx
        # The goal is to have a commit structure like so:
        # ...-> pctx -> tmpwctx -> shelvectx
        # where tmpwctx is an optional commit with the user's pending changes
        # and shelvectx is the unshelved changes. Then we merge it all down
        # to the original pctx.

        # Store pending changes in a commit and remember added in case a shelve
        # contains unknown files that are part of the pending change
        s = repo.status()
        addedbefore = frozenset(s.added)
        if s.modified or s.added or s.removed or s.deleted:
            ui.status(
                _("temporarily committing pending changes "
                  "(restore with 'hg unshelve --abort')\n"))

            def commitfunc(ui, repo, message, match, opts):
                hasmq = util.safehasattr(repo, 'mq')
                if hasmq:
                    saved, repo.mq.checkapplied = repo.mq.checkapplied, False

                backup = repo.ui.backupconfig('phases', 'new-commit')
                try:
                    repo.ui.setconfig('phases', 'new-commit', phases.secret)
                    return repo.commit(message, 'shelve@localhost',
                                       opts.get('date'), match)
                finally:
                    repo.ui.restoreconfig(backup)
                    if hasmq:
                        repo.mq.checkapplied = saved

            tempopts = {}
            tempopts['message'] = "pending changes temporary commit"
            tempopts['date'] = opts.get('date')
            ui.quiet = True
            node = cmdutil.commit(ui, repo, commitfunc, [], tempopts)
            tmpwctx = repo[node]

        ui.quiet = True
        shelvedfile(repo, basename, 'hg').applybundle()

        ui.quiet = oldquiet

        shelvectx = repo['tip']

        branchtorestore = ''
        if shelvectx.branch() != shelvectx.p1().branch():
            branchtorestore = shelvectx.branch()

        # If the shelve is not immediately on top of the commit
        # we'll be merging with, rebase it to be on top.
        if tmpwctx.node() != shelvectx.parents()[0].node():
            ui.status(_('rebasing shelved changes\n'))
            try:
                rebase.rebase(
                    ui, repo, **{
                        'rev': [shelvectx.rev()],
                        'dest': str(tmpwctx.rev()),
                        'keep': True,
                        'tool': opts.get('tool', ''),
                    })
            except error.InterventionRequired:
                tr.close()

                stripnodes = [
                    repo.changelog.node(rev)
                    for rev in xrange(oldtiprev, len(repo))
                ]
                shelvedstate.save(repo, basename, pctx, tmpwctx, stripnodes,
                                  branchtorestore)

                util.rename(repo.join('rebasestate'),
                            repo.join('unshelverebasestate'))
                raise error.InterventionRequired(
                    _("unresolved conflicts (see 'hg resolve', then "
                      "'hg unshelve --continue')"))

            # refresh ctx after rebase completes
            shelvectx = repo['tip']

            if not shelvectx in tmpwctx.children():
                # rebase was a no-op, so it produced no child commit
                shelvectx = tmpwctx

        mergefiles(ui, repo, pctx, shelvectx)
        restorebranch(ui, repo, branchtorestore)

        # Forget any files that were unknown before the shelve, unknown before
        # unshelve started, but are now added.
        shelveunknown = shelvectx.extra().get('shelve_unknown')
        if shelveunknown:
            shelveunknown = frozenset(shelveunknown.split('\0'))
            addedafter = frozenset(repo.status().added)
            toforget = (addedafter & shelveunknown) - addedbefore
            repo[None].forget(toforget)

        shelvedstate.clear(repo)

        # The transaction aborting will strip all the commits for us,
        # but it doesn't update the inmemory structures, so addchangegroup
        # hooks still fire and try to operate on the missing commits.
        # Clean up manually to prevent this.
        repo.unfiltered().changelog.strip(oldtiprev, tr)

        unshelvecleanup(ui, repo, basename, opts)

        _aborttransaction(repo)
    finally:
        ui.quiet = oldquiet
        if tr:
            tr.release()
        lockmod.release(lock)
        ui.restoreconfig(forcemerge)
Beispiel #4
0
def _dounshelve(ui, repo, *shelved, **opts):
    abortf = opts.get('abort')
    continuef = opts.get('continue')
    if not abortf and not continuef:
        cmdutil.checkunfinished(repo)

    if abortf or continuef:
        if abortf and continuef:
            raise error.Abort(_('cannot use both abort and continue'))
        if shelved:
            raise error.Abort(_('cannot combine abort/continue with '
                               'naming a shelved change'))
        if abortf and opts.get('tool', False):
            ui.warn(_('tool option will be ignored\n'))

        try:
            state = shelvedstate.load(repo)
        except IOError as err:
            if err.errno != errno.ENOENT:
                raise
            cmdutil.wrongtooltocontinue(repo, _('unshelve'))
        except error.CorruptedState as err:
            ui.debug(str(err) + '\n')
            if continuef:
                msg = _('corrupted shelved state file')
                hint = _('please run hg unshelve --abort to abort unshelve '
                         'operation')
                raise error.Abort(msg, hint=hint)
            elif abortf:
                msg = _('could not read shelved state file, your working copy '
                        'may be in an unexpected state\nplease update to some '
                        'commit\n')
                ui.warn(msg)
                shelvedstate.clear(repo)
            return

        if abortf:
            return unshelveabort(ui, repo, state, opts)
        elif continuef:
            return unshelvecontinue(ui, repo, state, opts)
    elif len(shelved) > 1:
        raise error.Abort(_('can only unshelve one change at a time'))
    elif not shelved:
        shelved = listshelves(repo)
        if not shelved:
            raise error.Abort(_('no shelved changes to apply!'))
        basename = util.split(shelved[0][1])[1]
        ui.status(_("unshelving change '%s'\n") % basename)
    else:
        basename = shelved[0]

    if not shelvedfile(repo, basename, 'patch').exists():
        raise error.Abort(_("shelved change '%s' not found") % basename)

    oldquiet = ui.quiet
    lock = tr = None
    forcemerge = ui.backupconfig('ui', 'forcemerge')
    try:
        ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'unshelve')
        lock = repo.lock()

        tr = repo.transaction('unshelve', report=lambda x: None)
        oldtiprev = len(repo)

        pctx = repo['.']
        tmpwctx = pctx
        # The goal is to have a commit structure like so:
        # ...-> pctx -> tmpwctx -> shelvectx
        # where tmpwctx is an optional commit with the user's pending changes
        # and shelvectx is the unshelved changes. Then we merge it all down
        # to the original pctx.

        # Store pending changes in a commit and remember added in case a shelve
        # contains unknown files that are part of the pending change
        s = repo.status()
        addedbefore = frozenset(s.added)
        if s.modified or s.added or s.removed or s.deleted:
            ui.status(_("temporarily committing pending changes "
                        "(restore with 'hg unshelve --abort')\n"))
            def commitfunc(ui, repo, message, match, opts):
                hasmq = util.safehasattr(repo, 'mq')
                if hasmq:
                    saved, repo.mq.checkapplied = repo.mq.checkapplied, False

                backup = repo.ui.backupconfig('phases', 'new-commit')
                try:
                    repo.ui.setconfig('phases', 'new-commit', phases.secret)
                    return repo.commit(message, 'shelve@localhost',
                                       opts.get('date'), match)
                finally:
                    repo.ui.restoreconfig(backup)
                    if hasmq:
                        repo.mq.checkapplied = saved

            tempopts = {}
            tempopts['message'] = "pending changes temporary commit"
            tempopts['date'] = opts.get('date')
            ui.quiet = True
            node = cmdutil.commit(ui, repo, commitfunc, [], tempopts)
            tmpwctx = repo[node]

        ui.quiet = True
        shelvedfile(repo, basename, 'hg').applybundle()

        ui.quiet = oldquiet

        shelvectx = repo['tip']

        branchtorestore = ''
        if shelvectx.branch() != shelvectx.p1().branch():
            branchtorestore = shelvectx.branch()

        # If the shelve is not immediately on top of the commit
        # we'll be merging with, rebase it to be on top.
        if tmpwctx.node() != shelvectx.parents()[0].node():
            ui.status(_('rebasing shelved changes\n'))
            try:
                rebase.rebase(ui, repo, **{
                    'rev' : [shelvectx.rev()],
                    'dest' : str(tmpwctx.rev()),
                    'keep' : True,
                    'tool' : opts.get('tool', ''),
                })
            except error.InterventionRequired:
                tr.close()

                stripnodes = [repo.changelog.node(rev)
                              for rev in xrange(oldtiprev, len(repo))]
                shelvedstate.save(repo, basename, pctx, tmpwctx, stripnodes,
                                  branchtorestore)

                util.rename(repo.join('rebasestate'),
                            repo.join('unshelverebasestate'))
                raise error.InterventionRequired(
                    _("unresolved conflicts (see 'hg resolve', then "
                      "'hg unshelve --continue')"))

            # refresh ctx after rebase completes
            shelvectx = repo['tip']

            if not shelvectx in tmpwctx.children():
                # rebase was a no-op, so it produced no child commit
                shelvectx = tmpwctx

        mergefiles(ui, repo, pctx, shelvectx)
        restorebranch(ui, repo, branchtorestore)

        # Forget any files that were unknown before the shelve, unknown before
        # unshelve started, but are now added.
        shelveunknown = shelvectx.extra().get('shelve_unknown')
        if shelveunknown:
            shelveunknown = frozenset(shelveunknown.split('\0'))
            addedafter = frozenset(repo.status().added)
            toforget = (addedafter & shelveunknown) - addedbefore
            repo[None].forget(toforget)

        shelvedstate.clear(repo)

        # The transaction aborting will strip all the commits for us,
        # but it doesn't update the inmemory structures, so addchangegroup
        # hooks still fire and try to operate on the missing commits.
        # Clean up manually to prevent this.
        repo.unfiltered().changelog.strip(oldtiprev, tr)

        unshelvecleanup(ui, repo, basename, opts)

        _aborttransaction(repo)
    finally:
        ui.quiet = oldquiet
        if tr:
            tr.release()
        lockmod.release(lock)
        ui.restoreconfig(forcemerge)