If you don't want to store any backup while rebasing, you can
use history-editing-backup config option.
[ui]
history-editing-backup =      # True or False
Current status of list of commands which supports this config:
- histedit
- rebase
| hg-reviewers | 
If you don't want to store any backup while rebasing, you can
use history-editing-backup config option.
[ui]
history-editing-backup =      # True or False
Current status of list of commands which supports this config:
| Automatic diff as part of commit; lint not applicable. | 
| Automatic diff as part of commit; unit tests not applicable. | 
Added --no-backup option which gives functionality to not save backup copies of files.
Can you elaborate why we want this option?
I'm -0 on this because it's unclear when the --no-backup option makes a
difference. --abort isn't the only way to strip revisions while rebasing.
In D3887#60749, @yuja wrote:Added --no-backup option which gives functionality to not save backup copies of files.Can you elaborate why we want this option?
The idea was to add --no-backup option in all those commands which alter history. For this one, let say if someone wants to abort a rebase in between then a --no-backup option should be available (same as histedit)
I'm -0 on this because it's unclear when the --no-backup option makes a
difference. --abort isn't the only way to strip revisions while rebasing.
Oh, I thought --abort is the only way to strip revisions. Shall I try to cover all other cases also where we strip csets; Or If it is not required I can leave it here.
The idea was to add --no-backup option in all those commands which alter
history. For this one, let say if someone wants to abort a rebase in between
then a --no-backup option should be available (same as histedit)
If he don't want any backup bundle on history editing, it might be better
to add a config knob to turn off the feature than forcing him to always
specify --no-backup.
histedit and rebase are different from strip in that the user doesn't intend
to "remove" changesets.
Oh, I thought --abort is the only way to strip revisions.
Pre-obsmarker rebase will strip rebased revisions.
Shall I try to cover all other cases also where we strip csets; Or If it is
not required I can leave it here.
I don't have strong opinion about that, but it's probably better to add a
test with some comment saying --no-backup doesn't work and should be fixed
later.
In D3887#60752, @yuja wrote:The idea was to add --no-backup option in all those commands which alter
history. For this one, let say if someone wants to abort a rebase in between
then a --no-backup option should be available (same as histedit)If he don't want any backup bundle on history editing, it might be better
to add a config knob to turn off the feature than forcing him to always
specify --no-backup.
I agree with Yuya here that a config option is better here.
@yuja @pulkit Definitely, adding a config option is better than any other alternative. Can I start to work on this? (I mean adding config option which will work for all history editing commands)
Sounds good to me, though I don't have any good name for the config option.
To be clear, I think hg strip should be out of the control of the config
option to be added, because the strip in that case isn't a side effect of
history editing.
Queued, thanks.
@@ -829,6 +833,8 @@
userrevs = list(repo.revs(opts.get('auto_orphans'))) opts['rev'] = [revsetlang.formatspec('%ld and orphan()', userrevs)] opts['dest'] = '_destautoorphanrebase(SRC)'+ backup = ui.configbool('ui', 'history-editing-backup')
+ opts['backup'] = backup
This seems getting ugly. Maybe the option can be carried by rbsrt instead?
self.backupf = ui.configbool('ui', 'history-editing-backup')In D3887#62825, @yuja wrote:Queued, thanks.
@@ -829,6 +833,8 @@
userrevs = list(repo.revs(opts.get('auto_orphans'))) opts['rev'] = [revsetlang.formatspec('%ld and orphan()', userrevs)] opts['dest'] = '_destautoorphanrebase(SRC)'+ backup = ui.configbool('ui', 'history-editing-backup')
+ opts['backup'] = backupThis seems getting ugly. Maybe the option can be carried by rbsrt instead?
self.backupf = ui.configbool('ui', 'history-editing-backup')
I like Yuya's suggestion here. @khanchi97 can you please follow-up?
In D3887#62850, @pulkit wrote:In D3887#62825, @yuja wrote:Queued, thanks.
@@ -829,6 +833,8 @@
userrevs = list(repo.revs(opts.get('auto_orphans'))) opts['rev'] = [revsetlang.formatspec('%ld and orphan()', userrevs)] opts['dest'] = '_destautoorphanrebase(SRC)'+ backup = ui.configbool('ui', 'history-editing-backup')
+ opts['backup'] = backupThis seems getting ugly. Maybe the option can be carried by rbsrt instead?
self.backupf = ui.configbool('ui', 'history-editing-backup')I like Yuya's suggestion here. @khanchi97 can you please follow-up?
Okay, I will send a follow-up.
| Path | Packages | |||
|---|---|---|---|---|
| M | hgext/rebase.py (25 lines) | |||
| M | mercurial/repair.py (10 lines) | |||
| M | mercurial/scmutil.py (5 lines) | |||
| A | M | tests/test-rebase-backup.t (150 lines) | 
| (desc, repo[self.state[rev]])) | (desc, repo[self.state[rev]])) | ||||
| if not tr: | if not tr: | ||||
| # When not using single transaction, store state after each | # When not using single transaction, store state after each | ||||
| # commit is completely done. On InterventionRequired, we thus | # commit is completely done. On InterventionRequired, we thus | ||||
| # won't store the status. Instead, we'll hit the "len(parents) == 2" | # won't store the status. Instead, we'll hit the "len(parents) == 2" | ||||
| # case and realize that the commit was in progress. | # case and realize that the commit was in progress. | ||||
| self.storestatus() | self.storestatus() | ||||
| def _finishrebase(self): | def _finishrebase(self, backup=True): | ||||
| """ | |||||
| backup: if False, no backup will be stored when stripping rebased | |||||
| revisions | |||||
| """ | |||||
| repo, ui, opts = self.repo, self.ui, self.opts | repo, ui, opts = self.repo, self.ui, self.opts | ||||
| fm = ui.formatter('rebase', opts) | fm = ui.formatter('rebase', opts) | ||||
| fm.startitem() | fm.startitem() | ||||
| if self.collapsef: | if self.collapsef: | ||||
| p1, p2, _base = defineparents(repo, min(self.state), self.destmap, | p1, p2, _base = defineparents(repo, min(self.state), self.destmap, | ||||
| self.state, self.skipped, | self.state, self.skipped, | ||||
| self.obsoletenotrebased) | self.obsoletenotrebased) | ||||
| editopt = opts.get('edit') | editopt = opts.get('edit') | ||||
| if newwd not in [c.rev() for c in repo[None].parents()]: | if newwd not in [c.rev() for c in repo[None].parents()]: | ||||
| ui.note(_("update back to initial working directory parent\n")) | ui.note(_("update back to initial working directory parent\n")) | ||||
| hg.updaterepo(repo, newwd, overwrite=False) | hg.updaterepo(repo, newwd, overwrite=False) | ||||
| collapsedas = None | collapsedas = None | ||||
| if self.collapsef and not self.keepf: | if self.collapsef and not self.keepf: | ||||
| collapsedas = newnode | collapsedas = newnode | ||||
| clearrebased(ui, repo, self.destmap, self.state, self.skipped, | clearrebased(ui, repo, self.destmap, self.state, self.skipped, | ||||
| collapsedas, self.keepf, fm=fm) | collapsedas, self.keepf, fm=fm, backup=backup) | ||||
| clearstatus(repo) | clearstatus(repo) | ||||
| clearcollapsemsg(repo) | clearcollapsemsg(repo) | ||||
| ui.note(_("rebase completed\n")) | ui.note(_("rebase completed\n")) | ||||
| util.unlinkpath(repo.sjoin('undo'), ignoremissing=True) | util.unlinkpath(repo.sjoin('undo'), ignoremissing=True) | ||||
| if self.skipped: | if self.skipped: | ||||
| skippedlen = len(self.skipped) | skippedlen = len(self.skipped) | ||||
| if opts.get('auto_orphans'): | if opts.get('auto_orphans'): | ||||
| for key in opts: | for key in opts: | ||||
| if key != 'auto_orphans' and opts.get(key): | if key != 'auto_orphans' and opts.get(key): | ||||
| raise error.Abort(_('--auto-orphans is incompatible with %s') % | raise error.Abort(_('--auto-orphans is incompatible with %s') % | ||||
| ('--' + key)) | ('--' + key)) | ||||
| userrevs = list(repo.revs(opts.get('auto_orphans'))) | userrevs = list(repo.revs(opts.get('auto_orphans'))) | ||||
| opts['rev'] = [revsetlang.formatspec('%ld and orphan()', userrevs)] | opts['rev'] = [revsetlang.formatspec('%ld and orphan()', userrevs)] | ||||
| opts['dest'] = '_destautoorphanrebase(SRC)' | opts['dest'] = '_destautoorphanrebase(SRC)' | ||||
| backup = ui.configbool('ui', 'history-editing-backup') | |||||
| opts['backup'] = backup | |||||
| if dryrun: | if dryrun: | ||||
| return _dryrunrebase(ui, repo, opts) | return _dryrunrebase(ui, repo, opts) | ||||
| elif inmemory: | elif inmemory: | ||||
| try: | try: | ||||
| # in-memory merge doesn't support conflicts, so if we hit any, abort | # in-memory merge doesn't support conflicts, so if we hit any, abort | ||||
| # and re-run as an on-disk merge. | # and re-run as an on-disk merge. | ||||
| overrides = {('rebase', 'singletransaction'): True} | overrides = {('rebase', 'singletransaction'): True} | ||||
| with ui.configoverride(overrides, 'rebase'): | with ui.configoverride(overrides, 'rebase'): | ||||
| return _dorebase(ui, repo, opts, inmemory=inmemory) | return _dorebase(ui, repo, opts, inmemory=inmemory) | ||||
| except error.InMemoryMergeConflictsError: | except error.InMemoryMergeConflictsError: | ||||
| ui.warn(_('hit merge conflicts; re-running rebase without in-memory' | ui.warn(_('hit merge conflicts; re-running rebase without in-memory' | ||||
| ' merge\n')) | ' merge\n')) | ||||
| _dorebase(ui, repo, {'abort': True}) | _dorebase(ui, repo, {'abort': True}) | ||||
| return _dorebase(ui, repo, opts, inmemory=False) | return _dorebase(ui, repo, opts, inmemory=False) | ||||
| else: | else: | ||||
| return _dorebase(ui, repo, opts) | return _dorebase(ui, repo, opts) | ||||
| def _dryrunrebase(ui, repo, opts): | def _dryrunrebase(ui, repo, opts): | ||||
| rbsrt = rebaseruntime(repo, ui, inmemory=True, opts=opts) | rbsrt = rebaseruntime(repo, ui, inmemory=True, opts=opts) | ||||
| confirm = opts.get('confirm') | confirm = opts.get('confirm') | ||||
| backup = opts.get('backup') | |||||
| if confirm: | if confirm: | ||||
| ui.status(_('starting in-memory rebase\n')) | ui.status(_('starting in-memory rebase\n')) | ||||
| else: | else: | ||||
| ui.status(_('starting dry-run rebase; repository will not be ' | ui.status(_('starting dry-run rebase; repository will not be ' | ||||
| 'changed\n')) | 'changed\n')) | ||||
| with repo.wlock(), repo.lock(): | with repo.wlock(), repo.lock(): | ||||
| needsabort = True | needsabort = True | ||||
| try: | try: | ||||
| overrides = {('rebase', 'singletransaction'): True} | overrides = {('rebase', 'singletransaction'): True} | ||||
| with ui.configoverride(overrides, 'rebase'): | with ui.configoverride(overrides, 'rebase'): | ||||
| _origrebase(ui, repo, opts, rbsrt, inmemory=True, | _origrebase(ui, repo, opts, rbsrt, inmemory=True, | ||||
| leaveunfinished=True) | leaveunfinished=True) | ||||
| except error.InMemoryMergeConflictsError: | except error.InMemoryMergeConflictsError: | ||||
| ui.status(_('hit a merge conflict\n')) | ui.status(_('hit a merge conflict\n')) | ||||
| return 1 | return 1 | ||||
| else: | else: | ||||
| if confirm: | if confirm: | ||||
| ui.status(_('rebase completed successfully\n')) | ui.status(_('rebase completed successfully\n')) | ||||
| if not ui.promptchoice(_(b'apply changes (yn)?' | if not ui.promptchoice(_(b'apply changes (yn)?' | ||||
| b'$$ &Yes $$ &No')): | b'$$ &Yes $$ &No')): | ||||
| # finish unfinished rebase | # finish unfinished rebase | ||||
| rbsrt._finishrebase() | rbsrt._finishrebase(backup=backup) | ||||
| else: | else: | ||||
| rbsrt._prepareabortorcontinue(isabort=True, backup=False, | rbsrt._prepareabortorcontinue(isabort=True, backup=False, | ||||
| suppwarns=True) | suppwarns=True) | ||||
| needsabort = False | needsabort = False | ||||
| else: | else: | ||||
| ui.status(_('dry-run rebase completed successfully; run without' | ui.status(_('dry-run rebase completed successfully; run without' | ||||
| ' -n/--dry-run to perform this rebase\n')) | ' -n/--dry-run to perform this rebase\n')) | ||||
| return 0 | return 0 | ||||
| srcf = opts.get('source', None) | srcf = opts.get('source', None) | ||||
| basef = opts.get('base', None) | basef = opts.get('base', None) | ||||
| revf = opts.get('rev', []) | revf = opts.get('rev', []) | ||||
| # search default destination in this space | # search default destination in this space | ||||
| # used in the 'hg pull --rebase' case, see issue 5214. | # used in the 'hg pull --rebase' case, see issue 5214. | ||||
| destspace = opts.get('_destspace') | destspace = opts.get('_destspace') | ||||
| contf = opts.get('continue') | contf = opts.get('continue') | ||||
| abortf = opts.get('abort') | abortf = opts.get('abort') | ||||
| backup = opts.get('backup') | |||||
| if opts.get('interactive'): | if opts.get('interactive'): | ||||
| try: | try: | ||||
| if extensions.find('histedit'): | if extensions.find('histedit'): | ||||
| enablehistedit = '' | enablehistedit = '' | ||||
| except KeyError: | except KeyError: | ||||
| enablehistedit = " --config extensions.histedit=" | enablehistedit = " --config extensions.histedit=" | ||||
| help = "hg%s help -e histedit" % enablehistedit | help = "hg%s help -e histedit" % enablehistedit | ||||
| msg = _("interactive history editing is supported by the " | msg = _("interactive history editing is supported by the " | ||||
| raise error.Abort( | raise error.Abort( | ||||
| _('abort and continue do not allow specifying revisions')) | _('abort and continue do not allow specifying revisions')) | ||||
| if abortf and opts.get('tool', False): | if abortf and opts.get('tool', False): | ||||
| ui.warn(_('tool option will be ignored\n')) | ui.warn(_('tool option will be ignored\n')) | ||||
| if contf: | if contf: | ||||
| ms = mergemod.mergestate.read(repo) | ms = mergemod.mergestate.read(repo) | ||||
| mergeutil.checkunresolved(ms) | mergeutil.checkunresolved(ms) | ||||
| retcode = rbsrt._prepareabortorcontinue(abortf) | retcode = rbsrt._prepareabortorcontinue(abortf, backup=backup) | ||||
| if retcode is not None: | if retcode is not None: | ||||
| return retcode | return retcode | ||||
| else: | else: | ||||
| destmap = _definedestmap(ui, repo, inmemory, destf, srcf, basef, | destmap = _definedestmap(ui, repo, inmemory, destf, srcf, basef, | ||||
| revf, destspace=destspace) | revf, destspace=destspace) | ||||
| retcode = rbsrt._preparenewrebase(destmap) | retcode = rbsrt._preparenewrebase(destmap) | ||||
| if retcode is not None: | if retcode is not None: | ||||
| return retcode | return retcode | ||||
| # Same logic for the dirstate guard, except we don't create one when | # Same logic for the dirstate guard, except we don't create one when | ||||
| # rebasing in-memory (it's not needed). | # rebasing in-memory (it's not needed). | ||||
| dsguard = None | dsguard = None | ||||
| if singletr and not inmemory: | if singletr and not inmemory: | ||||
| dsguard = dirstateguard.dirstateguard(repo, 'rebase') | dsguard = dirstateguard.dirstateguard(repo, 'rebase') | ||||
| with util.acceptintervention(dsguard): | with util.acceptintervention(dsguard): | ||||
| rbsrt._performrebase(tr) | rbsrt._performrebase(tr) | ||||
| if not leaveunfinished: | if not leaveunfinished: | ||||
| rbsrt._finishrebase() | rbsrt._finishrebase(backup=backup) | ||||
| def _definedestmap(ui, repo, inmemory, destf=None, srcf=None, basef=None, | def _definedestmap(ui, repo, inmemory, destf=None, srcf=None, basef=None, | ||||
| revf=None, destspace=None): | revf=None, destspace=None): | ||||
| """use revisions argument to define destmap {srcrev: destrev}""" | """use revisions argument to define destmap {srcrev: destrev}""" | ||||
| if revf is None: | if revf is None: | ||||
| revf = [] | revf = [] | ||||
| # destspace is here to work around issues with `hg pull --rebase` see | # destspace is here to work around issues with `hg pull --rebase` see | ||||
| for rev in sorted(state): | for rev in sorted(state): | ||||
| parents = [p for p in repo.changelog.parentrevs(rev) if p != nullrev] | parents = [p for p in repo.changelog.parentrevs(rev) if p != nullrev] | ||||
| # if all parents of this revision are done, then so is this revision | # if all parents of this revision are done, then so is this revision | ||||
| if parents and all((state.get(p) == p for p in parents)): | if parents and all((state.get(p) == p for p in parents)): | ||||
| state[rev] = rev | state[rev] = rev | ||||
| return originalwd, destmap, state | return originalwd, destmap, state | ||||
| def clearrebased(ui, repo, destmap, state, skipped, collapsedas=None, | def clearrebased(ui, repo, destmap, state, skipped, collapsedas=None, | ||||
| keepf=False, fm=None): | keepf=False, fm=None, backup=True): | ||||
| """dispose of rebased revision at the end of the rebase | """dispose of rebased revision at the end of the rebase | ||||
| If `collapsedas` is not None, the rebase was a collapse whose result if the | If `collapsedas` is not None, the rebase was a collapse whose result if the | ||||
| `collapsedas` node. | `collapsedas` node. | ||||
| If `keepf` is not True, the rebase has --keep set and no nodes should be | If `keepf` is not True, the rebase has --keep set and no nodes should be | ||||
| removed (but bookmarks still need to be moved). | removed (but bookmarks still need to be moved). | ||||
| If `backup` is False, no backup will be stored when stripping rebased | |||||
| revisions. | |||||
| """ | """ | ||||
| tonode = repo.changelog.node | tonode = repo.changelog.node | ||||
| replacements = {} | replacements = {} | ||||
| moves = {} | moves = {} | ||||
| for rev, newrev in sorted(state.items()): | for rev, newrev in sorted(state.items()): | ||||
| if newrev >= 0 and newrev != rev: | if newrev >= 0 and newrev != rev: | ||||
| oldnode = tonode(rev) | oldnode = tonode(rev) | ||||
| newnode = collapsedas or tonode(newrev) | newnode = collapsedas or tonode(newrev) | ||||
| moves[oldnode] = newnode | moves[oldnode] = newnode | ||||
| if not keepf: | if not keepf: | ||||
| if rev in skipped: | if rev in skipped: | ||||
| succs = () | succs = () | ||||
| else: | else: | ||||
| succs = (newnode,) | succs = (newnode,) | ||||
| replacements[oldnode] = succs | replacements[oldnode] = succs | ||||
| scmutil.cleanupnodes(repo, replacements, 'rebase', moves) | scmutil.cleanupnodes(repo, replacements, 'rebase', moves, backup=backup) | ||||
| if fm: | if fm: | ||||
| hf = fm.hexfunc | hf = fm.hexfunc | ||||
| fl = fm.formatlist | fl = fm.formatlist | ||||
| fd = fm.formatdict | fd = fm.formatdict | ||||
| nodechanges = fd({hf(oldn): fl([hf(n) for n in newn], name='node') | nodechanges = fd({hf(oldn): fl([hf(n) for n in newn], name='node') | ||||
| for oldn, newn in replacements.iteritems()}, | for oldn, newn in replacements.iteritems()}, | ||||
| key="oldnode", value="newnodes") | key="oldnode", value="newnodes") | ||||
| fm.data(nodechanges=nodechanges) | fm.data(nodechanges=nodechanges) | ||||
| def addnodes(self, nodes): | def addnodes(self, nodes): | ||||
| self.nodelist.extend(nodes) | self.nodelist.extend(nodes) | ||||
| def __call__(self, tr): | def __call__(self, tr): | ||||
| roots = safestriproots(self.ui, self.repo, self.nodelist) | roots = safestriproots(self.ui, self.repo, self.nodelist) | ||||
| if roots: | if roots: | ||||
| strip(self.ui, self.repo, roots, self.backup, self.topic) | strip(self.ui, self.repo, roots, self.backup, self.topic) | ||||
| def delayedstrip(ui, repo, nodelist, topic=None): | def delayedstrip(ui, repo, nodelist, topic=None, backup=True): | ||||
| """like strip, but works inside transaction and won't strip irreverent revs | """like strip, but works inside transaction and won't strip irreverent revs | ||||
| nodelist must explicitly contain all descendants. Otherwise a warning will | nodelist must explicitly contain all descendants. Otherwise a warning will | ||||
| be printed that some nodes are not stripped. | be printed that some nodes are not stripped. | ||||
| Always do a backup. The last non-None "topic" will be used as the backup | Will do a backup if `backup` is True. The last non-None "topic" will be | ||||
| topic name. The default backup topic name is "backup". | used as the backup topic name. The default backup topic name is "backup". | ||||
| """ | """ | ||||
| tr = repo.currenttransaction() | tr = repo.currenttransaction() | ||||
| if not tr: | if not tr: | ||||
| nodes = safestriproots(ui, repo, nodelist) | nodes = safestriproots(ui, repo, nodelist) | ||||
| return strip(ui, repo, nodes, True, topic) | return strip(ui, repo, nodes, backup=backup, topic=topic) | ||||
| # transaction postclose callbacks are called in alphabet order. | # transaction postclose callbacks are called in alphabet order. | ||||
| # use '\xff' as prefix so we are likely to be called last. | # use '\xff' as prefix so we are likely to be called last. | ||||
| callback = tr.getpostclose('\xffstrip') | callback = tr.getpostclose('\xffstrip') | ||||
| if callback is None: | if callback is None: | ||||
| callback = stripcallback(ui, repo, True, topic) | callback = stripcallback(ui, repo, backup=backup, topic=topic) | ||||
| tr.addpostclose('\xffstrip', callback) | tr.addpostclose('\xffstrip', callback) | ||||
| if topic: | if topic: | ||||
| callback.topic = topic | callback.topic = topic | ||||
| callback.addnodes(nodelist) | callback.addnodes(nodelist) | ||||
| def stripmanifest(repo, striprev, tr, files): | def stripmanifest(repo, striprev, tr, files): | ||||
| revlog = repo.manifestlog._revlog | revlog = repo.manifestlog._revlog | ||||
| revlog.strip(striprev, tr) | revlog.strip(striprev, tr) | ||||
| def __init__(self, repo, revcontainer): | def __init__(self, repo, revcontainer): | ||||
| self._torev = repo.changelog.rev | self._torev = repo.changelog.rev | ||||
| self._revcontains = revcontainer.__contains__ | self._revcontains = revcontainer.__contains__ | ||||
| def __contains__(self, node): | def __contains__(self, node): | ||||
| return self._revcontains(self._torev(node)) | return self._revcontains(self._torev(node)) | ||||
| def cleanupnodes(repo, replacements, operation, moves=None, metadata=None, | def cleanupnodes(repo, replacements, operation, moves=None, metadata=None, | ||||
| fixphase=False, targetphase=None): | fixphase=False, targetphase=None, backup=True): | ||||
| """do common cleanups when old nodes are replaced by new nodes | """do common cleanups when old nodes are replaced by new nodes | ||||
| That includes writing obsmarkers or stripping nodes, and moving bookmarks. | That includes writing obsmarkers or stripping nodes, and moving bookmarks. | ||||
| (we might also want to move working directory parent in the future) | (we might also want to move working directory parent in the future) | ||||
| By default, bookmark moves are calculated automatically from 'replacements', | By default, bookmark moves are calculated automatically from 'replacements', | ||||
| but 'moves' can be used to override that. Also, 'moves' may include | but 'moves' can be used to override that. Also, 'moves' may include | ||||
| additional bookmark moves that should not have associated obsmarkers. | additional bookmark moves that should not have associated obsmarkers. | ||||
| if s or not isobs(n)] | if s or not isobs(n)] | ||||
| if rels: | if rels: | ||||
| obsolete.createmarkers(repo, rels, operation=operation, | obsolete.createmarkers(repo, rels, operation=operation, | ||||
| metadata=metadata) | metadata=metadata) | ||||
| else: | else: | ||||
| from . import repair # avoid import cycle | from . import repair # avoid import cycle | ||||
| tostrip = list(replacements) | tostrip = list(replacements) | ||||
| if tostrip: | if tostrip: | ||||
| repair.delayedstrip(repo.ui, repo, tostrip, operation) | repair.delayedstrip(repo.ui, repo, tostrip, operation, | ||||
| backup=backup) | |||||
| def addremove(repo, matcher, prefix, opts=None): | def addremove(repo, matcher, prefix, opts=None): | ||||
| if opts is None: | if opts is None: | ||||
| opts = {} | opts = {} | ||||
| m = matcher | m = matcher | ||||
| dry_run = opts.get('dry_run') | dry_run = opts.get('dry_run') | ||||
| try: | try: | ||||
| similarity = float(opts.get('similarity') or 0) | similarity = float(opts.get('similarity') or 0) | ||||
| $ cat << EOF >> $HGRCPATH | |||||
| > [extensions] | |||||
| > rebase= | |||||
| > EOF | |||||
| ========================================== | |||||
| Test history-editing-backup config option | | |||||
| ========================================== | |||||
| Test with Pre-obsmarker rebase: | |||||
| 1) When config option is not set: | |||||
| $ hg init repo1 | |||||
| $ cd repo1 | |||||
| $ echo a>a | |||||
| $ hg ci -qAma | |||||
| $ echo b>b | |||||
| $ hg ci -qAmb | |||||
| $ echo c>c | |||||
| $ hg ci -qAmc | |||||
| $ hg up 0 -q | |||||
| $ echo d>d | |||||
| $ hg ci -qAmd | |||||
| $ echo e>e | |||||
| $ hg ci -qAme | |||||
| $ hg log -GT "{rev}: {firstline(desc)}\n" | |||||
| @ 4: e | |||||
| | | |||||
| o 3: d | |||||
| | | |||||
| | o 2: c | |||||
| | | | |||||
| | o 1: b | |||||
| |/ | |||||
| o 0: a | |||||
| $ hg rebase -s 1 -d . | |||||
| rebasing 1:d2ae7f538514 "b" | |||||
| rebasing 2:177f92b77385 "c" | |||||
| saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/d2ae7f538514-c7ed7a78-rebase.hg | |||||
| $ hg log -GT "{rev}: {firstline(desc)}\n" | |||||
| o 4: c | |||||
| | | |||||
| o 3: b | |||||
| | | |||||
| @ 2: e | |||||
| | | |||||
| o 1: d | |||||
| | | |||||
| o 0: a | |||||
| 2) When config option is set: | |||||
| $ cat << EOF >> $HGRCPATH | |||||
| > [ui] | |||||
| > history-editing-backup = False | |||||
| > EOF | |||||
| $ echo f>f | |||||
| $ hg ci -Aqmf | |||||
| $ echo g>g | |||||
| $ hg ci -Aqmg | |||||
| $ hg log -GT "{rev}: {firstline(desc)}\n" | |||||
| @ 6: g | |||||
| | | |||||
| o 5: f | |||||
| | | |||||
| | o 4: c | |||||
| | | | |||||
| | o 3: b | |||||
| |/ | |||||
| o 2: e | |||||
| | | |||||
| o 1: d | |||||
| | | |||||
| o 0: a | |||||
| $ hg rebase -s 3 -d . | |||||
| rebasing 3:05bff2a95b12 "b" | |||||
| rebasing 4:1762bde4404d "c" | |||||
| $ hg log -GT "{rev}: {firstline(desc)}\n" | |||||
| o 6: c | |||||
| | | |||||
| o 5: b | |||||
| | | |||||
| @ 4: g | |||||
| | | |||||
| o 3: f | |||||
| | | |||||
| o 2: e | |||||
| | | |||||
| o 1: d | |||||
| | | |||||
| o 0: a | |||||
| Test when rebased revisions are stripped during abort: | |||||
| ====================================================== | |||||
| $ echo conflict > c | |||||
| $ hg ci -Am "conflict with c" | |||||
| adding c | |||||
| created new head | |||||
| $ hg log -GT "{rev}: {firstline(desc)}\n" | |||||
| @ 7: conflict with c | |||||
| | | |||||
| | o 6: c | |||||
| | | | |||||
| | o 5: b | |||||
| |/ | |||||
| o 4: g | |||||
| | | |||||
| o 3: f | |||||
| | | |||||
| o 2: e | |||||
| | | |||||
| o 1: d | |||||
| | | |||||
| o 0: a | |||||
| When history-editing-backup = True: | |||||
| $ cat << EOF >> $HGRCPATH | |||||
| > [ui] | |||||
| > history-editing-backup = True | |||||
| > EOF | |||||
| $ hg rebase -s 5 -d . | |||||
| rebasing 5:1f8148a544ee "b" | |||||
| rebasing 6:f8bc7d28e573 "c" | |||||
| merging c | |||||
| warning: conflicts while merging c! (edit, then use 'hg resolve --mark') | |||||
| unresolved conflicts (see hg resolve, then hg rebase --continue) | |||||
| [1] | |||||
| $ hg rebase --abort | |||||
| saved backup bundle to $TESTTMP/repo1/.hg/strip-backup/818c1a43c916-2b644d96-backup.hg | |||||
| rebase aborted | |||||
| When history-editing-backup = False: | |||||
| $ cat << EOF >> $HGRCPATH | |||||
| > [ui] | |||||
| > history-editing-backup = False | |||||
| > EOF | |||||
| $ hg rebase -s 5 -d . | |||||
| rebasing 5:1f8148a544ee "b" | |||||
| rebasing 6:f8bc7d28e573 "c" | |||||
| merging c | |||||
| warning: conflicts while merging c! (edit, then use 'hg resolve --mark') | |||||
| unresolved conflicts (see hg resolve, then hg rebase --continue) | |||||
| [1] | |||||
| $ hg rebase --abort | |||||
| rebase aborted | |||||
| $ cd .. | |||||