2014-06-02 23:54:54 +04:00
|
|
|
# fbamend.py - improved amend functionality
|
|
|
|
#
|
|
|
|
# Copyright 2013 Facebook, Inc.
|
|
|
|
#
|
|
|
|
# This software may be used and distributed according to the terms of the
|
|
|
|
# GNU General Public License version 2 or any later version.
|
|
|
|
|
|
|
|
"""extends the existing commit amend functionality
|
|
|
|
|
2016-09-21 17:45:25 +03:00
|
|
|
Adds an hg amend command that amends the current parent changeset with the
|
2014-06-02 23:54:54 +04:00
|
|
|
changes in the working copy. Similiar to the existing hg commit --amend
|
|
|
|
except it doesn't prompt for the commit message unless --edit is provided.
|
|
|
|
|
2016-09-21 17:45:25 +03:00
|
|
|
Allows amending changesets that have children and can automatically rebase
|
|
|
|
the children onto the new version of the changeset.
|
2014-06-02 23:54:54 +04:00
|
|
|
|
2014-06-12 09:34:21 +04:00
|
|
|
This extension is incompatible with changeset evolution. The command will
|
|
|
|
automatically disable itself if changeset evolution is enabled.
|
2016-10-25 21:10:47 +03:00
|
|
|
|
|
|
|
To disable the creation of preamend bookmarks and use obsolescence
|
|
|
|
markers instead to fix up amends, enable the following config option::
|
|
|
|
|
|
|
|
[fbamend]
|
|
|
|
userestack=true
|
|
|
|
|
2014-06-02 23:54:54 +04:00
|
|
|
"""
|
|
|
|
|
Make hg next --rebase intelligently obsolete/inhibit changesets
Summary:
This change updates the behavior hg next --rebase. Specifically:
- Only one changeset can be rebased at a time. If there are multiple candidate changesets, the command aborts.
- Each time a changeset is rebased, its precursor is marked as obsolete, inhibition markers are stripped from it and its ancestors, and its preamend bookmark is deleted, if one exists.
- The result of this is that if no non-obsolete changesets depend on the existence of the pre-rebased changeset, that changeset and its ancestors will be stripped, resulting in a cleaner user experience.
- This change also adds back the --evolve flag, but makes it show in error instead of working. It turns out that removing the flag outright breaks the evolve extension.
Test Plan:
See updated unit tests for the exact commands to run to test this, as well as an overview of all of the new situations where behavior was changed.
A basic test plan would be:
1. Initialize a new repository, and create a stack of 4 commits.
2. Amend the second commit in the stack.
3. Do `hg next --rebase`. It should work as before.
4. Do `hg next --rebase` again. This time, the entire old stack should "disappear" from hg sl.
Additionally, attempting to run `hg next --rebase` when there are multiple possible child changesets should fail.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3941922
Tasks: 13570554
Signature: t1:3941922:1475205056:58a8d1726cfcccbf14a38727be0220a09532ec97
2016-09-30 20:40:58 +03:00
|
|
|
from mercurial import (
|
|
|
|
bookmarks,
|
|
|
|
cmdutil,
|
|
|
|
commands,
|
2016-10-04 20:29:55 +03:00
|
|
|
error,
|
|
|
|
extensions,
|
|
|
|
merge,
|
Make hg next --rebase intelligently obsolete/inhibit changesets
Summary:
This change updates the behavior hg next --rebase. Specifically:
- Only one changeset can be rebased at a time. If there are multiple candidate changesets, the command aborts.
- Each time a changeset is rebased, its precursor is marked as obsolete, inhibition markers are stripped from it and its ancestors, and its preamend bookmark is deleted, if one exists.
- The result of this is that if no non-obsolete changesets depend on the existence of the pre-rebased changeset, that changeset and its ancestors will be stripped, resulting in a cleaner user experience.
- This change also adds back the --evolve flag, but makes it show in error instead of working. It turns out that removing the flag outright breaks the evolve extension.
Test Plan:
See updated unit tests for the exact commands to run to test this, as well as an overview of all of the new situations where behavior was changed.
A basic test plan would be:
1. Initialize a new repository, and create a stack of 4 commits.
2. Amend the second commit in the stack.
3. Do `hg next --rebase`. It should work as before.
4. Do `hg next --rebase` again. This time, the entire old stack should "disappear" from hg sl.
Additionally, attempting to run `hg next --rebase` when there are multiple possible child changesets should fail.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3941922
Tasks: 13570554
Signature: t1:3941922:1475205056:58a8d1726cfcccbf14a38727be0220a09532ec97
2016-09-30 20:40:58 +03:00
|
|
|
obsolete,
|
|
|
|
phases,
|
|
|
|
repair,
|
|
|
|
)
|
2016-10-14 21:05:53 +03:00
|
|
|
from mercurial.node import hex, nullrev
|
2015-08-04 19:10:50 +03:00
|
|
|
from mercurial import lock as lockmod
|
2014-06-02 23:54:54 +04:00
|
|
|
from mercurial.i18n import _
|
2016-10-14 21:05:53 +03:00
|
|
|
from collections import defaultdict, deque
|
2016-04-21 19:17:07 +03:00
|
|
|
from contextlib import nested
|
2014-06-02 23:54:54 +04:00
|
|
|
|
|
|
|
cmdtable = {}
|
|
|
|
command = cmdutil.command(cmdtable)
|
|
|
|
testedwith = 'internal'
|
|
|
|
|
2015-09-25 05:46:12 +03:00
|
|
|
rebasemod = None
|
Make hg next --rebase intelligently obsolete/inhibit changesets
Summary:
This change updates the behavior hg next --rebase. Specifically:
- Only one changeset can be rebased at a time. If there are multiple candidate changesets, the command aborts.
- Each time a changeset is rebased, its precursor is marked as obsolete, inhibition markers are stripped from it and its ancestors, and its preamend bookmark is deleted, if one exists.
- The result of this is that if no non-obsolete changesets depend on the existence of the pre-rebased changeset, that changeset and its ancestors will be stripped, resulting in a cleaner user experience.
- This change also adds back the --evolve flag, but makes it show in error instead of working. It turns out that removing the flag outright breaks the evolve extension.
Test Plan:
See updated unit tests for the exact commands to run to test this, as well as an overview of all of the new situations where behavior was changed.
A basic test plan would be:
1. Initialize a new repository, and create a stack of 4 commits.
2. Amend the second commit in the stack.
3. Do `hg next --rebase`. It should work as before.
4. Do `hg next --rebase` again. This time, the entire old stack should "disappear" from hg sl.
Additionally, attempting to run `hg next --rebase` when there are multiple possible child changesets should fail.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3941922
Tasks: 13570554
Signature: t1:3941922:1475205056:58a8d1726cfcccbf14a38727be0220a09532ec97
2016-09-30 20:40:58 +03:00
|
|
|
inhibitmod = None
|
2015-09-25 05:46:12 +03:00
|
|
|
|
2015-02-12 22:02:34 +03:00
|
|
|
amendopts = [
|
2016-09-21 17:45:25 +03:00
|
|
|
('', 'rebase', None, _('rebases children after the amend')),
|
|
|
|
('', 'fixup', None, _('rebase children from a previous amend')),
|
2014-06-02 23:54:54 +04:00
|
|
|
]
|
|
|
|
|
|
|
|
def uisetup(ui):
|
2015-09-25 05:46:12 +03:00
|
|
|
global rebasemod
|
|
|
|
try:
|
|
|
|
rebasemod = extensions.find('rebase')
|
|
|
|
except KeyError:
|
2016-01-11 21:19:22 +03:00
|
|
|
ui.warn(_("no rebase extension detected - disabling fbamend"))
|
2015-09-25 05:46:12 +03:00
|
|
|
return
|
|
|
|
|
2014-06-02 23:54:54 +04:00
|
|
|
entry = extensions.wrapcommand(commands.table, 'commit', commit)
|
|
|
|
for opt in amendopts:
|
|
|
|
opt = (opt[0], opt[1], opt[2], "(with --amend) " + opt[3])
|
|
|
|
entry[1].append(opt)
|
2016-09-23 20:39:36 +03:00
|
|
|
|
2014-06-12 09:34:21 +04:00
|
|
|
# manual call of the decorator
|
|
|
|
command('^amend', [
|
2015-04-15 19:29:09 +03:00
|
|
|
('A', 'addremove', None,
|
|
|
|
_('mark new/missing files as added/removed before committing')),
|
2014-06-12 09:34:21 +04:00
|
|
|
('e', 'edit', None, _('prompt to edit the commit message')),
|
2015-10-24 03:00:56 +03:00
|
|
|
('i', 'interactive', None, _('use interactive mode')),
|
2014-06-12 09:34:21 +04:00
|
|
|
] + amendopts + commands.walkopts + commands.commitopts,
|
|
|
|
_('hg amend [OPTION]...'))(amend)
|
|
|
|
|
2016-04-21 19:17:07 +03:00
|
|
|
command('^unamend', [])(unamend)
|
|
|
|
|
2016-02-04 14:03:31 +03:00
|
|
|
def has_automv(loaded):
|
|
|
|
if not loaded:
|
|
|
|
return
|
|
|
|
automv = extensions.find('automv')
|
|
|
|
entry = extensions.wrapcommand(cmdtable, 'amend', automv.mvcheck)
|
|
|
|
entry[1].append(
|
|
|
|
('', 'no-move-detection', None,
|
|
|
|
_('disable automatic file move detection')))
|
|
|
|
extensions.afterloaded('automv', has_automv)
|
|
|
|
|
2016-09-23 20:39:36 +03:00
|
|
|
# If the evolve extension is enabled, wrap the `next` command to
|
|
|
|
# add the --rebase flag.
|
|
|
|
def wrapnext(loaded):
|
|
|
|
if not loaded:
|
|
|
|
return
|
Make hg next --rebase intelligently obsolete/inhibit changesets
Summary:
This change updates the behavior hg next --rebase. Specifically:
- Only one changeset can be rebased at a time. If there are multiple candidate changesets, the command aborts.
- Each time a changeset is rebased, its precursor is marked as obsolete, inhibition markers are stripped from it and its ancestors, and its preamend bookmark is deleted, if one exists.
- The result of this is that if no non-obsolete changesets depend on the existence of the pre-rebased changeset, that changeset and its ancestors will be stripped, resulting in a cleaner user experience.
- This change also adds back the --evolve flag, but makes it show in error instead of working. It turns out that removing the flag outright breaks the evolve extension.
Test Plan:
See updated unit tests for the exact commands to run to test this, as well as an overview of all of the new situations where behavior was changed.
A basic test plan would be:
1. Initialize a new repository, and create a stack of 4 commits.
2. Amend the second commit in the stack.
3. Do `hg next --rebase`. It should work as before.
4. Do `hg next --rebase` again. This time, the entire old stack should "disappear" from hg sl.
Additionally, attempting to run `hg next --rebase` when there are multiple possible child changesets should fail.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3941922
Tasks: 13570554
Signature: t1:3941922:1475205056:58a8d1726cfcccbf14a38727be0220a09532ec97
2016-09-30 20:40:58 +03:00
|
|
|
|
|
|
|
global inhibitmod
|
|
|
|
try:
|
|
|
|
inhibitmod = extensions.find('inhibit')
|
|
|
|
except KeyError:
|
|
|
|
pass
|
|
|
|
|
2016-09-23 20:39:36 +03:00
|
|
|
evolvemod = extensions.find('evolve')
|
|
|
|
entry = extensions.wrapcommand(evolvemod.cmdtable, 'next', nextrebase)
|
|
|
|
entry[1].append((
|
|
|
|
'', 'rebase', False, _('rebase the changeset if necessary')
|
|
|
|
))
|
|
|
|
extensions.afterloaded('evolve', wrapnext)
|
2016-02-04 14:03:31 +03:00
|
|
|
|
Add hg rebase --restack
Summary:
This change adds a `--restack` option to `hg rebase`. When invoked, the command will rebase all descendants of precursors of the current changeset onto the current changeset. This is similar to the behavior of `hg evolve --all`, except it only handles unstable changesets, and not other issues that can arise from shared mutable history such as divergence or bumping.
I've been playing around with some of the more advanced features (such as allowing the command to be run from anywhere in the old stack or new stack, as well as allowing the user to specify the number of changesets to rebase), but I wanted to upload the most simple iteration of this command for feedback.
Test Plan:
See unit tests for complete commands.
1. Create a stack of commits.
2. Somewhere in the middle of the stack, amend a commit, potentially several times.
3. Run `hg rebase --restack`.
4. The top half of the stack should be rebased onto the amended commit, and the preamend bookmark should be gone.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: rmcelroy, quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3972103
Tasks: 13651947
Signature: t1:3972103:1476230834:8f77eac4e8d8681dd9f8125747c1ff75c8da1ad8
2016-10-12 03:41:07 +03:00
|
|
|
def wraprebase(loaded):
|
|
|
|
if not loaded:
|
|
|
|
return
|
|
|
|
entry = extensions.wrapcommand(rebasemod.cmdtable, 'rebase',
|
2016-10-25 21:10:47 +03:00
|
|
|
rebaserestack)
|
Add hg rebase --restack
Summary:
This change adds a `--restack` option to `hg rebase`. When invoked, the command will rebase all descendants of precursors of the current changeset onto the current changeset. This is similar to the behavior of `hg evolve --all`, except it only handles unstable changesets, and not other issues that can arise from shared mutable history such as divergence or bumping.
I've been playing around with some of the more advanced features (such as allowing the command to be run from anywhere in the old stack or new stack, as well as allowing the user to specify the number of changesets to rebase), but I wanted to upload the most simple iteration of this command for feedback.
Test Plan:
See unit tests for complete commands.
1. Create a stack of commits.
2. Somewhere in the middle of the stack, amend a commit, potentially several times.
3. Run `hg rebase --restack`.
4. The top half of the stack should be rebased onto the amended commit, and the preamend bookmark should be gone.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: rmcelroy, quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3972103
Tasks: 13651947
Signature: t1:3972103:1476230834:8f77eac4e8d8681dd9f8125747c1ff75c8da1ad8
2016-10-12 03:41:07 +03:00
|
|
|
entry[1].append((
|
|
|
|
'', 'restack', False, _('rebase all changesets in the current '
|
|
|
|
'stack onto the latest version of their '
|
|
|
|
'respective parents')
|
|
|
|
))
|
|
|
|
extensions.afterloaded('rebase', wraprebase)
|
|
|
|
|
2014-06-02 23:54:54 +04:00
|
|
|
def commit(orig, ui, repo, *pats, **opts):
|
|
|
|
if opts.get("amend"):
|
|
|
|
# commit --amend default behavior is to prompt for edit
|
2015-04-07 23:31:44 +03:00
|
|
|
opts['noeditmessage'] = True
|
2014-06-02 23:54:54 +04:00
|
|
|
return amend(ui, repo, *pats, **opts)
|
|
|
|
else:
|
2015-10-27 02:19:40 +03:00
|
|
|
badflags = [flag for flag in
|
|
|
|
['rebase', 'fixup'] if opts.get(flag, None)]
|
|
|
|
if badflags:
|
2016-01-08 05:30:24 +03:00
|
|
|
raise error.Abort(_('--%s must be called with --amend') %
|
2015-10-27 02:19:40 +03:00
|
|
|
badflags[0])
|
|
|
|
|
2014-06-02 23:54:54 +04:00
|
|
|
return orig(ui, repo, *pats, **opts)
|
|
|
|
|
2016-04-21 19:17:07 +03:00
|
|
|
def unamend(ui, repo, **opts):
|
2016-09-21 17:45:25 +03:00
|
|
|
"""undo the amend operation on a current changeset
|
2016-04-21 19:17:07 +03:00
|
|
|
|
2016-09-21 17:45:25 +03:00
|
|
|
This command will roll back to the previous version of a changeset,
|
2016-04-21 19:17:07 +03:00
|
|
|
leaving working directory in state in which it was before running
|
2016-04-25 22:01:35 +03:00
|
|
|
`hg amend` (e.g. files modified as part of an amend will be
|
2016-04-21 19:17:07 +03:00
|
|
|
marked as modified `hg status`)"""
|
|
|
|
try:
|
|
|
|
inhibitmod = extensions.find('inhibit')
|
2016-04-22 00:37:14 +03:00
|
|
|
except KeyError:
|
2016-04-21 19:17:07 +03:00
|
|
|
hint = _("please add inhibit to the list of enabled extensions")
|
|
|
|
e = _("unamend requires inhibit extension to be enabled")
|
|
|
|
raise error.Abort(e, hint=hint)
|
|
|
|
|
|
|
|
unfi = repo.unfiltered()
|
|
|
|
|
|
|
|
# identify the commit from which to unamend
|
2016-04-26 14:58:59 +03:00
|
|
|
curctx = repo['.']
|
2016-04-21 19:17:07 +03:00
|
|
|
|
|
|
|
# identify the commit to which to unamend
|
|
|
|
markers = list(obsolete.precursormarkers(curctx))
|
|
|
|
if len(markers) != 1:
|
2016-09-21 17:45:25 +03:00
|
|
|
e = _("changeset must have one precursor, found %i precursors")
|
2016-04-21 19:17:07 +03:00
|
|
|
raise error.Abort(e % len(markers))
|
|
|
|
|
|
|
|
precnode = markers[0].precnode()
|
|
|
|
precctx = unfi[precnode]
|
|
|
|
|
|
|
|
if curctx.children():
|
|
|
|
raise error.Abort(_("cannot unamend in the middle of a stack"))
|
|
|
|
|
|
|
|
with nested(repo.wlock(), repo.lock()):
|
|
|
|
repobookmarks = repo._bookmarks
|
|
|
|
ctxbookmarks = curctx.bookmarks()
|
2016-04-26 14:58:59 +03:00
|
|
|
# we want to inhibit markers that mark precnode obsolete
|
2016-04-21 19:17:07 +03:00
|
|
|
inhibitmod._inhibitmarkers(unfi, [precnode])
|
|
|
|
changedfiles = []
|
|
|
|
wctx = repo[None]
|
|
|
|
wm = wctx.manifest()
|
|
|
|
cm = precctx.manifest()
|
|
|
|
dirstate = repo.dirstate
|
|
|
|
diff = cm.diff(wm)
|
|
|
|
changedfiles.extend(diff.iterkeys())
|
|
|
|
|
|
|
|
tr = repo.transaction('unamend')
|
|
|
|
dirstate.beginparentchange()
|
|
|
|
dirstate.rebuild(precnode, cm, 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)
|
|
|
|
dirstate.endparentchange()
|
|
|
|
for book in ctxbookmarks:
|
|
|
|
repobookmarks[book] = precnode
|
|
|
|
repobookmarks.recordchange(tr)
|
|
|
|
tr.close()
|
|
|
|
# we want to mark the changeset from which we were unamending
|
|
|
|
# as obsolete
|
|
|
|
obsolete.createmarkers(repo, [(curctx, ())])
|
|
|
|
|
2014-06-02 23:54:54 +04:00
|
|
|
def amend(ui, repo, *pats, **opts):
|
2016-09-21 17:45:25 +03:00
|
|
|
'''amend the current changeset with more changes
|
2014-06-02 23:54:54 +04:00
|
|
|
'''
|
2015-04-07 23:52:59 +03:00
|
|
|
if obsolete.isenabled(repo, 'allnewcommands'):
|
|
|
|
msg = ('fbamend and evolve extension are incompatible, '
|
|
|
|
'fbamend deactivated.\n'
|
|
|
|
'You can either disable it globally:\n'
|
|
|
|
'- type `hg config --edit`\n'
|
|
|
|
'- drop the `fbamend=` line from the `[extensions]` section\n'
|
|
|
|
'or disable it for a specific repo:\n'
|
|
|
|
'- type `hg config --local --edit`\n'
|
|
|
|
'- add a `fbamend=!%s` line in the `[extensions]` section\n')
|
|
|
|
msg %= ui.config('extensions', 'fbamend')
|
|
|
|
ui.write_err(msg)
|
2014-06-02 23:54:54 +04:00
|
|
|
rebase = opts.get('rebase')
|
|
|
|
|
2015-02-12 22:02:34 +03:00
|
|
|
if rebase and _histediting(repo):
|
|
|
|
# if a histedit is in flight, it's dangerous to remove old commits
|
|
|
|
hint = _('during histedit, use amend without --rebase')
|
2016-01-08 05:30:24 +03:00
|
|
|
raise error.Abort('histedit in progress', hint=hint)
|
2015-02-12 22:02:34 +03:00
|
|
|
|
2015-10-24 03:00:56 +03:00
|
|
|
badflags = [flag for flag in
|
|
|
|
['rebase', 'fixup'] if opts.get(flag, None)]
|
|
|
|
if opts.get('interactive') and badflags:
|
2016-01-08 05:30:24 +03:00
|
|
|
raise error.Abort(_('--interactive and --%s are mutually exclusive') %
|
2015-10-24 03:00:56 +03:00
|
|
|
badflags[0])
|
|
|
|
|
2015-02-12 22:02:34 +03:00
|
|
|
fixup = opts.get('fixup')
|
2014-06-02 23:54:54 +04:00
|
|
|
if fixup:
|
|
|
|
fixupamend(ui, repo)
|
|
|
|
return
|
|
|
|
|
|
|
|
old = repo['.']
|
|
|
|
if old.phase() == phases.public:
|
2016-01-08 05:30:24 +03:00
|
|
|
raise error.Abort(_('cannot amend public changesets'))
|
2014-06-02 23:54:54 +04:00
|
|
|
if len(repo[None].parents()) > 1:
|
2016-01-08 05:30:24 +03:00
|
|
|
raise error.Abort(_('cannot amend while merging'))
|
2014-06-02 23:54:54 +04:00
|
|
|
|
|
|
|
haschildren = len(old.children()) > 0
|
|
|
|
|
2015-10-28 00:37:20 +03:00
|
|
|
opts['message'] = cmdutil.logmessage(ui, opts)
|
|
|
|
# Avoid further processing of any logfile. If such a file existed, its
|
|
|
|
# contents have been copied into opts['message'] by logmessage
|
|
|
|
opts['logfile'] = ''
|
|
|
|
|
2015-04-07 23:31:44 +03:00
|
|
|
if not opts.get('noeditmessage') and not opts.get('message'):
|
2014-06-02 23:54:54 +04:00
|
|
|
opts['message'] = old.description()
|
|
|
|
|
|
|
|
tempnode = []
|
2015-10-23 01:50:59 +03:00
|
|
|
commitdate = old.date() if not opts.get('date') else opts.get('date')
|
2014-06-02 23:54:54 +04:00
|
|
|
def commitfunc(ui, repo, message, match, opts):
|
|
|
|
e = cmdutil.commiteditor
|
|
|
|
noderesult = repo.commit(message,
|
|
|
|
old.user(),
|
2015-10-23 01:50:59 +03:00
|
|
|
commitdate,
|
2014-06-02 23:54:54 +04:00
|
|
|
match,
|
|
|
|
editor=e,
|
|
|
|
extra={})
|
|
|
|
|
|
|
|
# the temporary commit is the very first commit
|
|
|
|
if not tempnode:
|
|
|
|
tempnode.append(noderesult)
|
|
|
|
|
|
|
|
return noderesult
|
|
|
|
|
2015-05-10 06:22:31 +03:00
|
|
|
active = bmactive(repo)
|
2014-06-02 23:54:54 +04:00
|
|
|
oldbookmarks = old.bookmarks()
|
|
|
|
|
|
|
|
if haschildren:
|
|
|
|
def fakestrip(orig, ui, repo, *args, **kwargs):
|
|
|
|
if tempnode:
|
|
|
|
if tempnode[0]:
|
|
|
|
# don't strip everything, just the temp node
|
|
|
|
# this is very hacky
|
|
|
|
orig(ui, repo, tempnode[0], backup='none')
|
|
|
|
tempnode.pop()
|
|
|
|
else:
|
|
|
|
orig(ui, repo, *args, **kwargs)
|
|
|
|
extensions.wrapfunction(repair, 'strip', fakestrip)
|
|
|
|
|
2015-12-14 22:30:33 +03:00
|
|
|
tr = None
|
2015-08-04 19:10:50 +03:00
|
|
|
wlock = None
|
|
|
|
lock = None
|
|
|
|
try:
|
|
|
|
wlock = repo.wlock()
|
|
|
|
lock = repo.lock()
|
2015-10-24 03:00:56 +03:00
|
|
|
|
|
|
|
if opts.get('interactive'):
|
|
|
|
# Strip the interactive flag to avoid infinite recursive loop
|
|
|
|
opts.pop('interactive')
|
|
|
|
cmdutil.dorecord(ui, repo, amend, None, False,
|
|
|
|
cmdutil.recordfilter, *pats, **opts)
|
|
|
|
return
|
|
|
|
|
|
|
|
else:
|
|
|
|
node = cmdutil.amend(ui, repo, commitfunc, old, {}, pats, opts)
|
2015-08-04 19:10:50 +03:00
|
|
|
|
|
|
|
if node == old.node():
|
|
|
|
ui.status(_("nothing changed\n"))
|
2015-09-10 00:43:16 +03:00
|
|
|
return 0
|
2015-08-04 19:10:50 +03:00
|
|
|
|
|
|
|
if haschildren and not rebase:
|
2016-09-21 17:45:25 +03:00
|
|
|
msg = _("warning: the changeset's children were left behind\n")
|
2015-08-04 19:10:50 +03:00
|
|
|
if _histediting(repo):
|
|
|
|
ui.warn(msg)
|
|
|
|
ui.status(_('(this is okay since a histedit is in progress)\n'))
|
|
|
|
else:
|
|
|
|
_usereducation(ui)
|
|
|
|
ui.warn(msg)
|
2016-06-29 22:56:45 +03:00
|
|
|
ui.status(_("(use 'hg amend --fixup' to rebase them)\n"))
|
2015-08-04 19:10:50 +03:00
|
|
|
|
|
|
|
newbookmarks = repo._bookmarks
|
|
|
|
|
|
|
|
# move old bookmarks to new node
|
|
|
|
for bm in oldbookmarks:
|
|
|
|
newbookmarks[bm] = node
|
|
|
|
|
2016-10-25 21:10:47 +03:00
|
|
|
userestack = ui.configbool('fbamend', 'userestack')
|
|
|
|
if not _histediting(repo) and not userestack:
|
2015-08-04 19:10:50 +03:00
|
|
|
preamendname = _preamendname(repo, node)
|
|
|
|
if haschildren:
|
|
|
|
newbookmarks[preamendname] = old.node()
|
|
|
|
elif not active:
|
|
|
|
# update bookmark if it isn't based on the active bookmark name
|
|
|
|
oldname = _preamendname(repo, old.node())
|
|
|
|
if oldname in repo._bookmarks:
|
|
|
|
newbookmarks[preamendname] = repo._bookmarks[oldname]
|
|
|
|
del newbookmarks[oldname]
|
|
|
|
|
2015-12-14 22:30:33 +03:00
|
|
|
tr = repo.transaction('fixupamend')
|
|
|
|
newbookmarks.recordchange(tr)
|
|
|
|
tr.close()
|
2015-08-04 19:10:50 +03:00
|
|
|
|
|
|
|
if rebase and haschildren:
|
|
|
|
fixupamend(ui, repo)
|
|
|
|
finally:
|
2015-12-14 22:30:33 +03:00
|
|
|
lockmod.release(wlock, lock, tr)
|
2014-06-02 23:54:54 +04:00
|
|
|
|
|
|
|
def fixupamend(ui, repo):
|
2016-09-21 17:45:25 +03:00
|
|
|
"""rebases any children found on the preamend changset and strips the
|
|
|
|
preamend changset
|
2014-06-02 23:54:54 +04:00
|
|
|
"""
|
2015-08-04 19:10:50 +03:00
|
|
|
wlock = None
|
|
|
|
lock = None
|
2015-12-14 22:30:33 +03:00
|
|
|
tr = None
|
2015-08-04 19:10:50 +03:00
|
|
|
try:
|
|
|
|
wlock = repo.wlock()
|
|
|
|
lock = repo.lock()
|
|
|
|
current = repo['.']
|
2014-06-02 23:54:54 +04:00
|
|
|
|
2016-10-25 21:10:47 +03:00
|
|
|
# Use obsolescence information to fix up the amend instead of relying
|
|
|
|
# on the preamend bookmark if the user enables this feature.
|
|
|
|
if ui.configbool('fbamend', 'userestack'):
|
|
|
|
with repo.transaction('fixupamend') as tr:
|
|
|
|
try:
|
|
|
|
_restackonce(ui, repo, current.rev())
|
|
|
|
except error.InterventionRequired:
|
|
|
|
tr.close()
|
|
|
|
raise
|
|
|
|
return
|
|
|
|
|
|
|
|
preamendname = _preamendname(repo, current.node())
|
2015-08-04 19:10:50 +03:00
|
|
|
if not preamendname in repo._bookmarks:
|
2016-01-11 21:19:22 +03:00
|
|
|
raise error.Abort(_('no bookmark %s') % preamendname,
|
2015-08-04 19:10:50 +03:00
|
|
|
hint=_('check if your bookmark is active'))
|
2014-06-02 23:54:54 +04:00
|
|
|
|
2015-08-04 19:10:50 +03:00
|
|
|
old = repo[preamendname]
|
2016-06-17 15:25:32 +03:00
|
|
|
if old == current:
|
2016-09-21 17:45:25 +03:00
|
|
|
hint = _('please examine smartlog and rebase your changsets '
|
|
|
|
'manually')
|
2016-06-17 15:25:32 +03:00
|
|
|
err = _('cannot automatically determine what to rebase '
|
2016-09-21 17:45:25 +03:00
|
|
|
'because bookmark "%s" points to the current changset') % \
|
2016-06-17 15:25:32 +03:00
|
|
|
preamendname
|
|
|
|
raise error.Abort(err, hint=hint)
|
2015-08-04 19:10:50 +03:00
|
|
|
oldbookmarks = old.bookmarks()
|
2014-06-02 23:54:54 +04:00
|
|
|
|
2016-06-17 15:25:32 +03:00
|
|
|
ui.status(_("rebasing the children of %s\n") % (preamendname))
|
|
|
|
|
2015-08-04 19:10:50 +03:00
|
|
|
active = bmactive(repo)
|
|
|
|
opts = {
|
|
|
|
'rev' : [str(c.rev()) for c in old.descendants()],
|
2016-03-10 04:53:11 +03:00
|
|
|
'dest' : current.rev()
|
2015-08-04 19:10:50 +03:00
|
|
|
}
|
2014-06-02 23:54:54 +04:00
|
|
|
|
2015-08-04 19:10:50 +03:00
|
|
|
if opts['rev'] and opts['rev'][0]:
|
2015-09-25 05:46:12 +03:00
|
|
|
rebasemod.rebase(ui, repo, **opts)
|
2014-06-02 23:54:54 +04:00
|
|
|
|
2015-08-04 19:10:50 +03:00
|
|
|
for bookmark in oldbookmarks:
|
|
|
|
repo._bookmarks.pop(bookmark)
|
2015-07-08 20:33:04 +03:00
|
|
|
|
2015-12-14 22:30:33 +03:00
|
|
|
tr = repo.transaction('fixupamend')
|
|
|
|
repo._bookmarks.recordchange(tr)
|
2015-07-08 20:33:04 +03:00
|
|
|
|
2015-08-04 19:10:50 +03:00
|
|
|
if obsolete.isenabled(repo, obsolete.createmarkersopt):
|
2016-01-08 05:30:24 +03:00
|
|
|
# clean up the original node if inhibit kept it alive
|
|
|
|
if not old.obsolete():
|
2015-08-04 19:10:50 +03:00
|
|
|
obsolete.createmarkers(repo, [(old,())])
|
2016-01-08 05:30:24 +03:00
|
|
|
tr.close()
|
2015-08-04 19:10:50 +03:00
|
|
|
else:
|
2016-01-08 05:30:24 +03:00
|
|
|
tr.close()
|
|
|
|
repair.strip(ui, repo, old.node(), topic='preamend-backup')
|
2014-06-02 23:54:54 +04:00
|
|
|
|
2015-08-04 19:10:50 +03:00
|
|
|
merge.update(repo, current.node(), False, True, False)
|
|
|
|
if active:
|
|
|
|
bmactivate(repo, active)
|
|
|
|
finally:
|
2015-12-14 22:30:33 +03:00
|
|
|
lockmod.release(wlock, lock, tr)
|
2015-02-12 12:26:20 +03:00
|
|
|
|
2016-09-23 20:39:36 +03:00
|
|
|
def nextrebase(orig, ui, repo, **opts):
|
Make hg next --rebase intelligently obsolete/inhibit changesets
Summary:
This change updates the behavior hg next --rebase. Specifically:
- Only one changeset can be rebased at a time. If there are multiple candidate changesets, the command aborts.
- Each time a changeset is rebased, its precursor is marked as obsolete, inhibition markers are stripped from it and its ancestors, and its preamend bookmark is deleted, if one exists.
- The result of this is that if no non-obsolete changesets depend on the existence of the pre-rebased changeset, that changeset and its ancestors will be stripped, resulting in a cleaner user experience.
- This change also adds back the --evolve flag, but makes it show in error instead of working. It turns out that removing the flag outright breaks the evolve extension.
Test Plan:
See updated unit tests for the exact commands to run to test this, as well as an overview of all of the new situations where behavior was changed.
A basic test plan would be:
1. Initialize a new repository, and create a stack of 4 commits.
2. Amend the second commit in the stack.
3. Do `hg next --rebase`. It should work as before.
4. Do `hg next --rebase` again. This time, the entire old stack should "disappear" from hg sl.
Additionally, attempting to run `hg next --rebase` when there are multiple possible child changesets should fail.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3941922
Tasks: 13570554
Signature: t1:3941922:1475205056:58a8d1726cfcccbf14a38727be0220a09532ec97
2016-09-30 20:40:58 +03:00
|
|
|
# Disable `hg next --evolve`. The --rebase flag takes its place.
|
|
|
|
if opts['evolve']:
|
|
|
|
raise error.Abort(
|
|
|
|
_("the --evolve flag is not supported"),
|
|
|
|
hint=_("use 'hg next --rebase' instead")
|
|
|
|
)
|
|
|
|
|
|
|
|
# Just perform `hg next` if no --rebase option.
|
|
|
|
if not opts['rebase']:
|
|
|
|
return orig(ui, repo, **opts)
|
|
|
|
|
|
|
|
with nested(repo.wlock(), repo.lock()):
|
|
|
|
_nextrebase(orig, ui, repo, **opts)
|
|
|
|
|
|
|
|
def _nextrebase(orig, ui, repo, **opts):
|
2016-09-23 20:39:36 +03:00
|
|
|
"""Wrapper around the evolve extension's next command, adding the
|
|
|
|
--rebase option, which detects whether the current changeset has
|
|
|
|
any children on an obsolete precursor, and if so, rebases those
|
|
|
|
children onto the current version.
|
|
|
|
"""
|
|
|
|
# Abort if there is an unfinished operation or changes to the
|
|
|
|
# working copy, to be consistent with the behavior of `hg next`.
|
|
|
|
cmdutil.checkunfinished(repo)
|
|
|
|
cmdutil.bailifchanged(repo)
|
|
|
|
|
Make hg next --rebase intelligently obsolete/inhibit changesets
Summary:
This change updates the behavior hg next --rebase. Specifically:
- Only one changeset can be rebased at a time. If there are multiple candidate changesets, the command aborts.
- Each time a changeset is rebased, its precursor is marked as obsolete, inhibition markers are stripped from it and its ancestors, and its preamend bookmark is deleted, if one exists.
- The result of this is that if no non-obsolete changesets depend on the existence of the pre-rebased changeset, that changeset and its ancestors will be stripped, resulting in a cleaner user experience.
- This change also adds back the --evolve flag, but makes it show in error instead of working. It turns out that removing the flag outright breaks the evolve extension.
Test Plan:
See updated unit tests for the exact commands to run to test this, as well as an overview of all of the new situations where behavior was changed.
A basic test plan would be:
1. Initialize a new repository, and create a stack of 4 commits.
2. Amend the second commit in the stack.
3. Do `hg next --rebase`. It should work as before.
4. Do `hg next --rebase` again. This time, the entire old stack should "disappear" from hg sl.
Additionally, attempting to run `hg next --rebase` when there are multiple possible child changesets should fail.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3941922
Tasks: 13570554
Signature: t1:3941922:1475205056:58a8d1726cfcccbf14a38727be0220a09532ec97
2016-09-30 20:40:58 +03:00
|
|
|
# Find all children on the current changeset's obsolete precursors.
|
|
|
|
precursors = list(repo.set('allprecursors(.)'))
|
2016-09-23 20:39:36 +03:00
|
|
|
children = []
|
Make hg next --rebase intelligently obsolete/inhibit changesets
Summary:
This change updates the behavior hg next --rebase. Specifically:
- Only one changeset can be rebased at a time. If there are multiple candidate changesets, the command aborts.
- Each time a changeset is rebased, its precursor is marked as obsolete, inhibition markers are stripped from it and its ancestors, and its preamend bookmark is deleted, if one exists.
- The result of this is that if no non-obsolete changesets depend on the existence of the pre-rebased changeset, that changeset and its ancestors will be stripped, resulting in a cleaner user experience.
- This change also adds back the --evolve flag, but makes it show in error instead of working. It turns out that removing the flag outright breaks the evolve extension.
Test Plan:
See updated unit tests for the exact commands to run to test this, as well as an overview of all of the new situations where behavior was changed.
A basic test plan would be:
1. Initialize a new repository, and create a stack of 4 commits.
2. Amend the second commit in the stack.
3. Do `hg next --rebase`. It should work as before.
4. Do `hg next --rebase` again. This time, the entire old stack should "disappear" from hg sl.
Additionally, attempting to run `hg next --rebase` when there are multiple possible child changesets should fail.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3941922
Tasks: 13570554
Signature: t1:3941922:1475205056:58a8d1726cfcccbf14a38727be0220a09532ec97
2016-09-30 20:40:58 +03:00
|
|
|
for p in precursors:
|
|
|
|
children.extend(p.children())
|
|
|
|
|
|
|
|
# If there are no children on precursors, just do `hg next` normally.
|
|
|
|
if not children:
|
|
|
|
ui.warn(_("found no changesets to rebase, "
|
|
|
|
"doing normal 'hg next' instead\n"))
|
|
|
|
return orig(ui, repo, **opts)
|
|
|
|
|
|
|
|
current = repo['.']
|
|
|
|
child = children[0]
|
|
|
|
|
|
|
|
showopts = {'template': '[{shortest(node)}] {desc|firstline}\n'}
|
|
|
|
displayer = cmdutil.show_changeset(ui, repo, showopts)
|
|
|
|
|
|
|
|
# Catch the case where there are children on precursors, but
|
|
|
|
# there are also children on the current changeset.
|
|
|
|
if list(current.children()):
|
|
|
|
ui.warn(_("there are child changesets on one or more previous "
|
|
|
|
"versions of the current changeset, but the current "
|
|
|
|
"version also has children\n"))
|
|
|
|
ui.status(_("skipping rebasing the following child changesets:\n"))
|
|
|
|
for c in children:
|
|
|
|
displayer.show(c)
|
|
|
|
return orig(ui, repo, **opts)
|
|
|
|
|
|
|
|
# If there are several children on one or more precusors, it is
|
|
|
|
# ambiguous which changeset to rebase and update to.
|
|
|
|
if len(children) > 1:
|
|
|
|
ui.warn(_("there are multiple child changesets on previous versions "
|
|
|
|
"of the current changeset, namely:\n"))
|
|
|
|
for c in children:
|
|
|
|
displayer.show(c)
|
|
|
|
raise error.Abort(
|
|
|
|
_("ambiguous next changeset to rebase"),
|
|
|
|
hint=_("please rebase the desired one manually")
|
|
|
|
)
|
2016-09-23 20:39:36 +03:00
|
|
|
|
|
|
|
# If doing a dry run, just print out the corresponding commands.
|
|
|
|
if opts['dry_run']:
|
Make hg next --rebase intelligently obsolete/inhibit changesets
Summary:
This change updates the behavior hg next --rebase. Specifically:
- Only one changeset can be rebased at a time. If there are multiple candidate changesets, the command aborts.
- Each time a changeset is rebased, its precursor is marked as obsolete, inhibition markers are stripped from it and its ancestors, and its preamend bookmark is deleted, if one exists.
- The result of this is that if no non-obsolete changesets depend on the existence of the pre-rebased changeset, that changeset and its ancestors will be stripped, resulting in a cleaner user experience.
- This change also adds back the --evolve flag, but makes it show in error instead of working. It turns out that removing the flag outright breaks the evolve extension.
Test Plan:
See updated unit tests for the exact commands to run to test this, as well as an overview of all of the new situations where behavior was changed.
A basic test plan would be:
1. Initialize a new repository, and create a stack of 4 commits.
2. Amend the second commit in the stack.
3. Do `hg next --rebase`. It should work as before.
4. Do `hg next --rebase` again. This time, the entire old stack should "disappear" from hg sl.
Additionally, attempting to run `hg next --rebase` when there are multiple possible child changesets should fail.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3941922
Tasks: 13570554
Signature: t1:3941922:1475205056:58a8d1726cfcccbf14a38727be0220a09532ec97
2016-09-30 20:40:58 +03:00
|
|
|
ui.write(('hg rebase -r %s -d %s -k\n' % (child.hex(), current.hex())))
|
2016-09-23 20:39:36 +03:00
|
|
|
# Since we don't know what the new hashes will be until we actually
|
|
|
|
# perform the rebase, the dry run output can't explicitly say
|
|
|
|
# `hg update %s`. This is different from the normal output
|
|
|
|
# of `hg next --dry-run`.
|
|
|
|
ui.write(('hg next\n'))
|
Make hg next --rebase intelligently obsolete/inhibit changesets
Summary:
This change updates the behavior hg next --rebase. Specifically:
- Only one changeset can be rebased at a time. If there are multiple candidate changesets, the command aborts.
- Each time a changeset is rebased, its precursor is marked as obsolete, inhibition markers are stripped from it and its ancestors, and its preamend bookmark is deleted, if one exists.
- The result of this is that if no non-obsolete changesets depend on the existence of the pre-rebased changeset, that changeset and its ancestors will be stripped, resulting in a cleaner user experience.
- This change also adds back the --evolve flag, but makes it show in error instead of working. It turns out that removing the flag outright breaks the evolve extension.
Test Plan:
See updated unit tests for the exact commands to run to test this, as well as an overview of all of the new situations where behavior was changed.
A basic test plan would be:
1. Initialize a new repository, and create a stack of 4 commits.
2. Amend the second commit in the stack.
3. Do `hg next --rebase`. It should work as before.
4. Do `hg next --rebase` again. This time, the entire old stack should "disappear" from hg sl.
Additionally, attempting to run `hg next --rebase` when there are multiple possible child changesets should fail.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3941922
Tasks: 13570554
Signature: t1:3941922:1475205056:58a8d1726cfcccbf14a38727be0220a09532ec97
2016-09-30 20:40:58 +03:00
|
|
|
return
|
|
|
|
|
|
|
|
# When the transaction closes, inhibition markers will be added back to
|
Add hg rebase --restack
Summary:
This change adds a `--restack` option to `hg rebase`. When invoked, the command will rebase all descendants of precursors of the current changeset onto the current changeset. This is similar to the behavior of `hg evolve --all`, except it only handles unstable changesets, and not other issues that can arise from shared mutable history such as divergence or bumping.
I've been playing around with some of the more advanced features (such as allowing the command to be run from anywhere in the old stack or new stack, as well as allowing the user to specify the number of changesets to rebase), but I wanted to upload the most simple iteration of this command for feedback.
Test Plan:
See unit tests for complete commands.
1. Create a stack of commits.
2. Somewhere in the middle of the stack, amend a commit, potentially several times.
3. Run `hg rebase --restack`.
4. The top half of the stack should be rebased onto the amended commit, and the preamend bookmark should be gone.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: rmcelroy, quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3972103
Tasks: 13651947
Signature: t1:3972103:1476230834:8f77eac4e8d8681dd9f8125747c1ff75c8da1ad8
2016-10-12 03:41:07 +03:00
|
|
|
# changesets that have non-obsolete descendants, so those won't be
|
Make hg next --rebase intelligently obsolete/inhibit changesets
Summary:
This change updates the behavior hg next --rebase. Specifically:
- Only one changeset can be rebased at a time. If there are multiple candidate changesets, the command aborts.
- Each time a changeset is rebased, its precursor is marked as obsolete, inhibition markers are stripped from it and its ancestors, and its preamend bookmark is deleted, if one exists.
- The result of this is that if no non-obsolete changesets depend on the existence of the pre-rebased changeset, that changeset and its ancestors will be stripped, resulting in a cleaner user experience.
- This change also adds back the --evolve flag, but makes it show in error instead of working. It turns out that removing the flag outright breaks the evolve extension.
Test Plan:
See updated unit tests for the exact commands to run to test this, as well as an overview of all of the new situations where behavior was changed.
A basic test plan would be:
1. Initialize a new repository, and create a stack of 4 commits.
2. Amend the second commit in the stack.
3. Do `hg next --rebase`. It should work as before.
4. Do `hg next --rebase` again. This time, the entire old stack should "disappear" from hg sl.
Additionally, attempting to run `hg next --rebase` when there are multiple possible child changesets should fail.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3941922
Tasks: 13570554
Signature: t1:3941922:1475205056:58a8d1726cfcccbf14a38727be0220a09532ec97
2016-09-30 20:40:58 +03:00
|
|
|
# "stripped". As such, we're relying on the inhibition markers to take
|
|
|
|
# care of the hard work of identifying which changesets not to strip.
|
|
|
|
with repo.transaction('nextrebase') as tr:
|
|
|
|
# Rebase any children of the obsolete changesets.
|
2016-09-23 20:39:36 +03:00
|
|
|
try:
|
Make hg next --rebase intelligently obsolete/inhibit changesets
Summary:
This change updates the behavior hg next --rebase. Specifically:
- Only one changeset can be rebased at a time. If there are multiple candidate changesets, the command aborts.
- Each time a changeset is rebased, its precursor is marked as obsolete, inhibition markers are stripped from it and its ancestors, and its preamend bookmark is deleted, if one exists.
- The result of this is that if no non-obsolete changesets depend on the existence of the pre-rebased changeset, that changeset and its ancestors will be stripped, resulting in a cleaner user experience.
- This change also adds back the --evolve flag, but makes it show in error instead of working. It turns out that removing the flag outright breaks the evolve extension.
Test Plan:
See updated unit tests for the exact commands to run to test this, as well as an overview of all of the new situations where behavior was changed.
A basic test plan would be:
1. Initialize a new repository, and create a stack of 4 commits.
2. Amend the second commit in the stack.
3. Do `hg next --rebase`. It should work as before.
4. Do `hg next --rebase` again. This time, the entire old stack should "disappear" from hg sl.
Additionally, attempting to run `hg next --rebase` when there are multiple possible child changesets should fail.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3941922
Tasks: 13570554
Signature: t1:3941922:1475205056:58a8d1726cfcccbf14a38727be0220a09532ec97
2016-09-30 20:40:58 +03:00
|
|
|
rebasemod.rebase(ui, repo, rev=[child.rev()], dest=current.rev(),
|
|
|
|
keep=True)
|
2016-09-23 20:39:36 +03:00
|
|
|
except error.InterventionRequired:
|
|
|
|
ui.status(_(
|
|
|
|
"please resolve any conflicts, run 'hg rebase --continue', "
|
|
|
|
"and then run 'hg next'\n"
|
|
|
|
))
|
Make hg next --rebase intelligently obsolete/inhibit changesets
Summary:
This change updates the behavior hg next --rebase. Specifically:
- Only one changeset can be rebased at a time. If there are multiple candidate changesets, the command aborts.
- Each time a changeset is rebased, its precursor is marked as obsolete, inhibition markers are stripped from it and its ancestors, and its preamend bookmark is deleted, if one exists.
- The result of this is that if no non-obsolete changesets depend on the existence of the pre-rebased changeset, that changeset and its ancestors will be stripped, resulting in a cleaner user experience.
- This change also adds back the --evolve flag, but makes it show in error instead of working. It turns out that removing the flag outright breaks the evolve extension.
Test Plan:
See updated unit tests for the exact commands to run to test this, as well as an overview of all of the new situations where behavior was changed.
A basic test plan would be:
1. Initialize a new repository, and create a stack of 4 commits.
2. Amend the second commit in the stack.
3. Do `hg next --rebase`. It should work as before.
4. Do `hg next --rebase` again. This time, the entire old stack should "disappear" from hg sl.
Additionally, attempting to run `hg next --rebase` when there are multiple possible child changesets should fail.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3941922
Tasks: 13570554
Signature: t1:3941922:1475205056:58a8d1726cfcccbf14a38727be0220a09532ec97
2016-09-30 20:40:58 +03:00
|
|
|
tr.close()
|
2016-09-23 20:39:36 +03:00
|
|
|
raise
|
|
|
|
|
Make hg next --rebase intelligently obsolete/inhibit changesets
Summary:
This change updates the behavior hg next --rebase. Specifically:
- Only one changeset can be rebased at a time. If there are multiple candidate changesets, the command aborts.
- Each time a changeset is rebased, its precursor is marked as obsolete, inhibition markers are stripped from it and its ancestors, and its preamend bookmark is deleted, if one exists.
- The result of this is that if no non-obsolete changesets depend on the existence of the pre-rebased changeset, that changeset and its ancestors will be stripped, resulting in a cleaner user experience.
- This change also adds back the --evolve flag, but makes it show in error instead of working. It turns out that removing the flag outright breaks the evolve extension.
Test Plan:
See updated unit tests for the exact commands to run to test this, as well as an overview of all of the new situations where behavior was changed.
A basic test plan would be:
1. Initialize a new repository, and create a stack of 4 commits.
2. Amend the second commit in the stack.
3. Do `hg next --rebase`. It should work as before.
4. Do `hg next --rebase` again. This time, the entire old stack should "disappear" from hg sl.
Additionally, attempting to run `hg next --rebase` when there are multiple possible child changesets should fail.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3941922
Tasks: 13570554
Signature: t1:3941922:1475205056:58a8d1726cfcccbf14a38727be0220a09532ec97
2016-09-30 20:40:58 +03:00
|
|
|
# There isn't a good way of getting the newly rebased child changeset
|
|
|
|
# from rebasemod.rebase(), so just assume that it's the current
|
|
|
|
# changeset's only child. (This should always be the case.)
|
|
|
|
rebasedchild = current.children()[0]
|
2016-10-14 21:05:53 +03:00
|
|
|
ancestors = repo.set('%d %% .', child.rev())
|
Make hg next --rebase intelligently obsolete/inhibit changesets
Summary:
This change updates the behavior hg next --rebase. Specifically:
- Only one changeset can be rebased at a time. If there are multiple candidate changesets, the command aborts.
- Each time a changeset is rebased, its precursor is marked as obsolete, inhibition markers are stripped from it and its ancestors, and its preamend bookmark is deleted, if one exists.
- The result of this is that if no non-obsolete changesets depend on the existence of the pre-rebased changeset, that changeset and its ancestors will be stripped, resulting in a cleaner user experience.
- This change also adds back the --evolve flag, but makes it show in error instead of working. It turns out that removing the flag outright breaks the evolve extension.
Test Plan:
See updated unit tests for the exact commands to run to test this, as well as an overview of all of the new situations where behavior was changed.
A basic test plan would be:
1. Initialize a new repository, and create a stack of 4 commits.
2. Amend the second commit in the stack.
3. Do `hg next --rebase`. It should work as before.
4. Do `hg next --rebase` again. This time, the entire old stack should "disappear" from hg sl.
Additionally, attempting to run `hg next --rebase` when there are multiple possible child changesets should fail.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3941922
Tasks: 13570554
Signature: t1:3941922:1475205056:58a8d1726cfcccbf14a38727be0220a09532ec97
2016-09-30 20:40:58 +03:00
|
|
|
|
|
|
|
# Mark the old child changeset as obsolete, and remove the
|
|
|
|
# the inhibition markers from it and its ancestors. This
|
|
|
|
# effectively "strips" all of the obsoleted changesets in the
|
|
|
|
# stack below the child.
|
2016-10-14 21:05:53 +03:00
|
|
|
_deinhibit(repo, ancestors)
|
2016-10-22 03:58:19 +03:00
|
|
|
obsolete.createmarkers(
|
|
|
|
repo,
|
|
|
|
[(child, [rebasedchild])],
|
|
|
|
metadata={'operation': 'rebase'}
|
|
|
|
)
|
Make hg next --rebase intelligently obsolete/inhibit changesets
Summary:
This change updates the behavior hg next --rebase. Specifically:
- Only one changeset can be rebased at a time. If there are multiple candidate changesets, the command aborts.
- Each time a changeset is rebased, its precursor is marked as obsolete, inhibition markers are stripped from it and its ancestors, and its preamend bookmark is deleted, if one exists.
- The result of this is that if no non-obsolete changesets depend on the existence of the pre-rebased changeset, that changeset and its ancestors will be stripped, resulting in a cleaner user experience.
- This change also adds back the --evolve flag, but makes it show in error instead of working. It turns out that removing the flag outright breaks the evolve extension.
Test Plan:
See updated unit tests for the exact commands to run to test this, as well as an overview of all of the new situations where behavior was changed.
A basic test plan would be:
1. Initialize a new repository, and create a stack of 4 commits.
2. Amend the second commit in the stack.
3. Do `hg next --rebase`. It should work as before.
4. Do `hg next --rebase` again. This time, the entire old stack should "disappear" from hg sl.
Additionally, attempting to run `hg next --rebase` when there are multiple possible child changesets should fail.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3941922
Tasks: 13570554
Signature: t1:3941922:1475205056:58a8d1726cfcccbf14a38727be0220a09532ec97
2016-09-30 20:40:58 +03:00
|
|
|
|
|
|
|
# Remove any preamend bookmarks on precursors, as these would
|
|
|
|
# create unnecessary inhibition markers.
|
Add hg rebase --restack
Summary:
This change adds a `--restack` option to `hg rebase`. When invoked, the command will rebase all descendants of precursors of the current changeset onto the current changeset. This is similar to the behavior of `hg evolve --all`, except it only handles unstable changesets, and not other issues that can arise from shared mutable history such as divergence or bumping.
I've been playing around with some of the more advanced features (such as allowing the command to be run from anywhere in the old stack or new stack, as well as allowing the user to specify the number of changesets to rebase), but I wanted to upload the most simple iteration of this command for feedback.
Test Plan:
See unit tests for complete commands.
1. Create a stack of commits.
2. Somewhere in the middle of the stack, amend a commit, potentially several times.
3. Run `hg rebase --restack`.
4. The top half of the stack should be rebased onto the amended commit, and the preamend bookmark should be gone.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: rmcelroy, quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3972103
Tasks: 13651947
Signature: t1:3972103:1476230834:8f77eac4e8d8681dd9f8125747c1ff75c8da1ad8
2016-10-12 03:41:07 +03:00
|
|
|
_clearpreamend(repo, precursors)
|
Make hg next --rebase intelligently obsolete/inhibit changesets
Summary:
This change updates the behavior hg next --rebase. Specifically:
- Only one changeset can be rebased at a time. If there are multiple candidate changesets, the command aborts.
- Each time a changeset is rebased, its precursor is marked as obsolete, inhibition markers are stripped from it and its ancestors, and its preamend bookmark is deleted, if one exists.
- The result of this is that if no non-obsolete changesets depend on the existence of the pre-rebased changeset, that changeset and its ancestors will be stripped, resulting in a cleaner user experience.
- This change also adds back the --evolve flag, but makes it show in error instead of working. It turns out that removing the flag outright breaks the evolve extension.
Test Plan:
See updated unit tests for the exact commands to run to test this, as well as an overview of all of the new situations where behavior was changed.
A basic test plan would be:
1. Initialize a new repository, and create a stack of 4 commits.
2. Amend the second commit in the stack.
3. Do `hg next --rebase`. It should work as before.
4. Do `hg next --rebase` again. This time, the entire old stack should "disappear" from hg sl.
Additionally, attempting to run `hg next --rebase` when there are multiple possible child changesets should fail.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3941922
Tasks: 13570554
Signature: t1:3941922:1475205056:58a8d1726cfcccbf14a38727be0220a09532ec97
2016-09-30 20:40:58 +03:00
|
|
|
|
|
|
|
# Run `hg next` to update to the newly rebased child.
|
2016-09-23 20:39:36 +03:00
|
|
|
return orig(ui, repo, **opts)
|
|
|
|
|
2016-10-25 21:10:47 +03:00
|
|
|
def rebaserestack(orig, ui, repo, **opts):
|
Add hg rebase --restack
Summary:
This change adds a `--restack` option to `hg rebase`. When invoked, the command will rebase all descendants of precursors of the current changeset onto the current changeset. This is similar to the behavior of `hg evolve --all`, except it only handles unstable changesets, and not other issues that can arise from shared mutable history such as divergence or bumping.
I've been playing around with some of the more advanced features (such as allowing the command to be run from anywhere in the old stack or new stack, as well as allowing the user to specify the number of changesets to rebase), but I wanted to upload the most simple iteration of this command for feedback.
Test Plan:
See unit tests for complete commands.
1. Create a stack of commits.
2. Somewhere in the middle of the stack, amend a commit, potentially several times.
3. Run `hg rebase --restack`.
4. The top half of the stack should be rebased onto the amended commit, and the preamend bookmark should be gone.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: rmcelroy, quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3972103
Tasks: 13651947
Signature: t1:3972103:1476230834:8f77eac4e8d8681dd9f8125747c1ff75c8da1ad8
2016-10-12 03:41:07 +03:00
|
|
|
"""Wrapper around `hg rebase` adding the `--restack` option, which rebases
|
2016-10-14 21:05:53 +03:00
|
|
|
all "unstable" descendants of an obsolete changeset onto the latest
|
|
|
|
version of that changeset. This is similar to (and intended as a
|
|
|
|
replacement for) the `hg evolve --all` command.
|
Add hg rebase --restack
Summary:
This change adds a `--restack` option to `hg rebase`. When invoked, the command will rebase all descendants of precursors of the current changeset onto the current changeset. This is similar to the behavior of `hg evolve --all`, except it only handles unstable changesets, and not other issues that can arise from shared mutable history such as divergence or bumping.
I've been playing around with some of the more advanced features (such as allowing the command to be run from anywhere in the old stack or new stack, as well as allowing the user to specify the number of changesets to rebase), but I wanted to upload the most simple iteration of this command for feedback.
Test Plan:
See unit tests for complete commands.
1. Create a stack of commits.
2. Somewhere in the middle of the stack, amend a commit, potentially several times.
3. Run `hg rebase --restack`.
4. The top half of the stack should be rebased onto the amended commit, and the preamend bookmark should be gone.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: rmcelroy, quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3972103
Tasks: 13651947
Signature: t1:3972103:1476230834:8f77eac4e8d8681dd9f8125747c1ff75c8da1ad8
2016-10-12 03:41:07 +03:00
|
|
|
"""
|
|
|
|
if not opts['restack']:
|
|
|
|
return orig(ui, repo, **opts)
|
|
|
|
|
|
|
|
if opts['rev']:
|
|
|
|
raise error.Abort(_("cannot use both --rev and --restack"))
|
|
|
|
|
|
|
|
if opts['dest']:
|
|
|
|
raise error.Abort(_("cannot use both --dest and --restack"))
|
|
|
|
|
|
|
|
if opts['source']:
|
|
|
|
raise error.Abort(_("cannot use both --source and --restack"))
|
|
|
|
|
|
|
|
if opts['base']:
|
|
|
|
raise error.Abort(_("cannot use both --base and --restack"))
|
|
|
|
|
|
|
|
if opts['abort']:
|
|
|
|
raise error.Abort(_("cannot use both --abort and --restack"))
|
|
|
|
|
|
|
|
if opts['continue']:
|
|
|
|
raise error.Abort(_("cannot use both --continue and --restack"))
|
|
|
|
|
2016-10-25 21:10:47 +03:00
|
|
|
restack(ui, repo, opts)
|
|
|
|
|
|
|
|
def restack(ui, repo, rebaseopts=None):
|
|
|
|
"""Repair a situation in which one or more changesets in a stack
|
|
|
|
have been obsoleted (thereby leaving their descendants in the stack
|
|
|
|
unstable) by finding any such changesets and rebasing their descendants
|
|
|
|
onto the latest version of each respective changeset.
|
|
|
|
"""
|
|
|
|
if rebaseopts is None:
|
|
|
|
rebaseopts = {}
|
|
|
|
|
Add hg rebase --restack
Summary:
This change adds a `--restack` option to `hg rebase`. When invoked, the command will rebase all descendants of precursors of the current changeset onto the current changeset. This is similar to the behavior of `hg evolve --all`, except it only handles unstable changesets, and not other issues that can arise from shared mutable history such as divergence or bumping.
I've been playing around with some of the more advanced features (such as allowing the command to be run from anywhere in the old stack or new stack, as well as allowing the user to specify the number of changesets to rebase), but I wanted to upload the most simple iteration of this command for feedback.
Test Plan:
See unit tests for complete commands.
1. Create a stack of commits.
2. Somewhere in the middle of the stack, amend a commit, potentially several times.
3. Run `hg rebase --restack`.
4. The top half of the stack should be rebased onto the amended commit, and the preamend bookmark should be gone.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: rmcelroy, quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3972103
Tasks: 13651947
Signature: t1:3972103:1476230834:8f77eac4e8d8681dd9f8125747c1ff75c8da1ad8
2016-10-12 03:41:07 +03:00
|
|
|
with nested(repo.wlock(), repo.lock()):
|
|
|
|
cmdutil.checkunfinished(repo)
|
|
|
|
cmdutil.bailifchanged(repo)
|
|
|
|
|
2016-10-14 21:05:53 +03:00
|
|
|
# Identify a base changeset from which to begin stabilizing.
|
|
|
|
base = _findrestackbase(repo)
|
|
|
|
targets = _findrestacktargets(repo, base)
|
Add hg rebase --restack
Summary:
This change adds a `--restack` option to `hg rebase`. When invoked, the command will rebase all descendants of precursors of the current changeset onto the current changeset. This is similar to the behavior of `hg evolve --all`, except it only handles unstable changesets, and not other issues that can arise from shared mutable history such as divergence or bumping.
I've been playing around with some of the more advanced features (such as allowing the command to be run from anywhere in the old stack or new stack, as well as allowing the user to specify the number of changesets to rebase), but I wanted to upload the most simple iteration of this command for feedback.
Test Plan:
See unit tests for complete commands.
1. Create a stack of commits.
2. Somewhere in the middle of the stack, amend a commit, potentially several times.
3. Run `hg rebase --restack`.
4. The top half of the stack should be rebased onto the amended commit, and the preamend bookmark should be gone.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: rmcelroy, quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3972103
Tasks: 13651947
Signature: t1:3972103:1476230834:8f77eac4e8d8681dd9f8125747c1ff75c8da1ad8
2016-10-12 03:41:07 +03:00
|
|
|
|
|
|
|
with repo.transaction('restack') as tr:
|
2016-10-14 21:05:53 +03:00
|
|
|
# Attempt to stabilize all changesets that are or will be (after
|
|
|
|
# rebasing) descendants of base.
|
|
|
|
for rev in targets:
|
|
|
|
try:
|
2016-10-25 21:10:47 +03:00
|
|
|
_restackonce(ui, repo, rev, rebaseopts)
|
2016-10-14 21:05:53 +03:00
|
|
|
except error.InterventionRequired:
|
|
|
|
tr.close()
|
|
|
|
raise
|
|
|
|
|
|
|
|
# If we're currently on one of the precursors of the base, update
|
|
|
|
# to the latest successor since the old changeset is no longer
|
|
|
|
# needed. Note that if we're on a descendant of the base or its
|
|
|
|
# precurosrs, the rebase command will ensure that we end up on a
|
|
|
|
# non-obsolete changeset, so it is only necessary to explicitly
|
|
|
|
# update if we're on a precursor of the base.
|
|
|
|
if not repo.revs('. - allprecursors(%d)', base):
|
|
|
|
commands.update(ui, repo, rev=base)
|
|
|
|
|
|
|
|
def _restackonce(ui, repo, rev, rebaseopts=None):
|
|
|
|
"""Rebase all descendants of precursors of rev onto rev, thereby
|
|
|
|
stabilzing any non-obsolete descendants of those precursors.
|
|
|
|
"""
|
|
|
|
# Get visible descendants of precusors of rev.
|
|
|
|
allprecursors = repo.revs('allprecursors(%d)', rev)
|
|
|
|
descendants = repo.revs('descendants(%ld) - %ld', allprecursors,
|
|
|
|
allprecursors)
|
|
|
|
|
|
|
|
# Nothing to do if there are no descendants.
|
|
|
|
if not descendants:
|
|
|
|
return
|
|
|
|
|
|
|
|
# Overwrite source and destination, leave all other options.
|
|
|
|
if rebaseopts is None:
|
|
|
|
rebaseopts = {}
|
|
|
|
rebaseopts['rev'] = descendants
|
|
|
|
rebaseopts['dest'] = rev
|
|
|
|
|
|
|
|
rebasemod.rebase(ui, repo, **rebaseopts)
|
|
|
|
|
|
|
|
# Remove any preamend bookmarks and any inhibition markers
|
|
|
|
# on precursors so that they will be correctly labelled as
|
|
|
|
# obsolete. The rebase command will obsolete the descendants,
|
|
|
|
# so we only need to do this for the precursors.
|
|
|
|
contexts = [repo[r] for r in allprecursors]
|
|
|
|
_clearpreamend(repo, contexts)
|
|
|
|
_deinhibit(repo, contexts)
|
|
|
|
|
|
|
|
def _findrestackbase(repo):
|
|
|
|
"""Search backwards through history to find a changeset in the current
|
|
|
|
stack that may have unstable descendants on its precursors, or
|
|
|
|
may itself need to be stabilized.
|
|
|
|
"""
|
|
|
|
# Move down current stack until we find a changeset with visible
|
|
|
|
# precursors or successors, indicating that we may need to stabilize
|
|
|
|
# some descendants of this changeset or its precursors.
|
2016-10-19 00:20:37 +03:00
|
|
|
stack = repo.revs('::. & draft()')
|
2016-10-14 21:05:53 +03:00
|
|
|
stack.reverse()
|
|
|
|
for rev in stack:
|
|
|
|
# Is this the latest version of this changeset? If not, we need
|
|
|
|
# to rebase any unstable descendants onto the latest version.
|
|
|
|
latest = _latest(repo, rev)
|
|
|
|
if rev != latest:
|
|
|
|
return latest
|
|
|
|
|
|
|
|
# If we're already on the latest version, check if there are any
|
|
|
|
# visible precusors. If so, we need to rebase their descendants.
|
|
|
|
if repo.revs('allprecursors(%d)', rev):
|
|
|
|
return rev
|
|
|
|
|
|
|
|
# If we don't encounter any changesets with precursors or successors
|
|
|
|
# on the way down, assume the user just wants to recusively fix
|
|
|
|
# the stack upwards from the current changeset.
|
|
|
|
return repo['.'].rev()
|
|
|
|
|
|
|
|
def _findrestacktargets(repo, base):
|
|
|
|
"""Starting from the given base revision, do a BFS forwards through
|
|
|
|
history, looking for changesets with unstable descendants on their
|
|
|
|
precursors. Returns a list of any such changesets, in a top-down
|
|
|
|
ordering that will allow all of the descendants of their precursors
|
|
|
|
to be correctly rebased.
|
|
|
|
"""
|
|
|
|
childrenof = _getchildrelationships(repo, base)
|
|
|
|
|
|
|
|
# Perform BFS starting from base.
|
|
|
|
queue = deque([base])
|
|
|
|
targets = []
|
|
|
|
processed = set()
|
|
|
|
while queue:
|
|
|
|
rev = queue.popleft()
|
|
|
|
|
|
|
|
# Merges may result in the same revision being added to the queue
|
|
|
|
# multiple times. Filter those cases out.
|
|
|
|
if rev in processed:
|
|
|
|
continue
|
|
|
|
|
|
|
|
processed.add(rev)
|
|
|
|
queue.extend(childrenof[rev])
|
|
|
|
|
|
|
|
# Look for visible precursors (which are probably visible because
|
|
|
|
# they have unstable descendants) and successors (for which the latest
|
|
|
|
# non-obsolete version should be visible).
|
|
|
|
precursors = repo.revs('allprecursors(%d)', rev)
|
|
|
|
successors = repo.revs('allsuccessors(%d)', rev)
|
|
|
|
|
|
|
|
# If this changeset has precursors but no successor, then
|
|
|
|
# if its precursors have children those children need to be
|
|
|
|
# rebased onto the changeset.
|
|
|
|
if precursors and not successors:
|
|
|
|
children = []
|
|
|
|
for p in precursors:
|
|
|
|
children.extend(childrenof[p])
|
|
|
|
if children:
|
|
|
|
queue.extend(children)
|
|
|
|
targets.append(rev)
|
|
|
|
|
|
|
|
# We need to perform the rebases in reverse-BFS order so that
|
|
|
|
# obsolescence information at lower levels is not modified by rebases
|
|
|
|
# at higher levels.
|
|
|
|
return reversed(targets)
|
|
|
|
|
|
|
|
def _getchildrelationships(repo, base):
|
|
|
|
"""Build a defaultdict of child relationships between all descendants of
|
|
|
|
base. This information will prevent us from having to repeatedly
|
|
|
|
perform children that reconstruct these relationships each time.
|
|
|
|
"""
|
|
|
|
cl = repo.changelog
|
|
|
|
children = defaultdict(list)
|
|
|
|
for rev in repo.revs('%d:: + allprecursors(%d)::', base, base):
|
|
|
|
for parent in cl.parentrevs(rev):
|
|
|
|
if parent != nullrev:
|
|
|
|
children[parent].append(rev)
|
|
|
|
return children
|
|
|
|
|
|
|
|
def _latest(repo, rev):
|
|
|
|
"""Find the "latest version" of the given revision -- either the
|
|
|
|
latest visible successor, or the revision itself if it has no
|
|
|
|
visible successors. Throws an exception if divergence is
|
|
|
|
detected.
|
|
|
|
"""
|
|
|
|
unfiltered = repo.unfiltered()
|
|
|
|
|
|
|
|
def leadstovisible(rev):
|
|
|
|
"""Return true if the given revision is visble, or if one
|
|
|
|
of the revisions in its chain of successors is visible.
|
|
|
|
"""
|
|
|
|
try:
|
|
|
|
return repo.revs('allsuccessors(%d) + %d', rev, rev)
|
|
|
|
except error.FilteredRepoLookupError:
|
|
|
|
return False
|
|
|
|
|
|
|
|
def getsuccessors(rev):
|
|
|
|
"""Return all successors of the given revision that leads
|
|
|
|
to a visible successor.
|
|
|
|
"""
|
|
|
|
return [
|
|
|
|
r for r in unfiltered.revs('successors(%d)', rev)
|
|
|
|
if leadstovisible(r)
|
|
|
|
]
|
|
|
|
|
|
|
|
# Right now this loop runs in O(n^2) due to the allsuccessors
|
|
|
|
# lookup inside getsuccessors(). This check is neccesary to deal
|
|
|
|
# with unamended changesets (which create situations where
|
|
|
|
# the latest successor is acutally obsolete, and we want a
|
|
|
|
# precursor instead. This logic could probably be made more
|
|
|
|
# sophisticated for better performance.
|
|
|
|
successors = getsuccessors(rev)
|
|
|
|
while successors:
|
|
|
|
if len(successors) > 1:
|
|
|
|
raise error.Abort(_("changeset %s has multiple newer versions, "
|
|
|
|
"cannot automatically determine latest verion")
|
|
|
|
% unfiltered[rev].hex())
|
|
|
|
rev = successors[0]
|
|
|
|
successors = getsuccessors(rev)
|
|
|
|
return rev
|
|
|
|
|
|
|
|
def _clearpreamend(repo, contexts):
|
|
|
|
"""Remove any preamend bookmarks on the given change contexts."""
|
|
|
|
for ctx in contexts:
|
|
|
|
for bookmark in repo.nodebookmarks(ctx.node()):
|
|
|
|
if bookmark.endswith('.preamend'):
|
|
|
|
repo._bookmarks.pop(bookmark, None)
|
|
|
|
|
|
|
|
def _deinhibit(repo, contexts):
|
|
|
|
"""Remove any inhibit markers on the given change contexts."""
|
|
|
|
if inhibitmod:
|
|
|
|
inhibitmod._deinhibitmarkers(repo, (ctx.node() for ctx in contexts))
|
Add hg rebase --restack
Summary:
This change adds a `--restack` option to `hg rebase`. When invoked, the command will rebase all descendants of precursors of the current changeset onto the current changeset. This is similar to the behavior of `hg evolve --all`, except it only handles unstable changesets, and not other issues that can arise from shared mutable history such as divergence or bumping.
I've been playing around with some of the more advanced features (such as allowing the command to be run from anywhere in the old stack or new stack, as well as allowing the user to specify the number of changesets to rebase), but I wanted to upload the most simple iteration of this command for feedback.
Test Plan:
See unit tests for complete commands.
1. Create a stack of commits.
2. Somewhere in the middle of the stack, amend a commit, potentially several times.
3. Run `hg rebase --restack`.
4. The top half of the stack should be rebased onto the amended commit, and the preamend bookmark should be gone.
Reviewers: #sourcecontrol, durham
Reviewed By: durham
Subscribers: rmcelroy, quark, mjpieters
Differential Revision: https://phabricator.intern.facebook.com/D3972103
Tasks: 13651947
Signature: t1:3972103:1476230834:8f77eac4e8d8681dd9f8125747c1ff75c8da1ad8
2016-10-12 03:41:07 +03:00
|
|
|
|
2015-02-12 13:16:28 +03:00
|
|
|
def _preamendname(repo, node):
|
|
|
|
suffix = '.preamend'
|
2015-05-10 06:22:31 +03:00
|
|
|
name = bmactive(repo)
|
2015-02-12 13:16:28 +03:00
|
|
|
if not name:
|
2015-02-13 07:43:29 +03:00
|
|
|
name = hex(node)[:12]
|
2015-02-12 13:16:28 +03:00
|
|
|
return name + suffix
|
|
|
|
|
2015-02-12 22:02:34 +03:00
|
|
|
def _histediting(repo):
|
|
|
|
return repo.vfs.exists('histedit-state')
|
|
|
|
|
2015-02-12 12:26:20 +03:00
|
|
|
def _usereducation(ui):
|
|
|
|
"""
|
|
|
|
You can print out a message to the user here
|
|
|
|
"""
|
2015-04-17 20:17:23 +03:00
|
|
|
education = ui.config('fbamend', 'education')
|
|
|
|
if education:
|
|
|
|
ui.warn(education + "\n")
|
2015-05-10 06:22:31 +03:00
|
|
|
|
|
|
|
### bookmarks api compatibility layer ###
|
|
|
|
def bmactivate(repo, mark):
|
|
|
|
try:
|
|
|
|
return bookmarks.activate(repo, mark)
|
|
|
|
except AttributeError:
|
|
|
|
return bookmarks.setcurrent(repo, mark)
|
|
|
|
|
|
|
|
def bmactive(repo):
|
|
|
|
try:
|
|
|
|
return repo._activebookmark
|
|
|
|
except AttributeError:
|
|
|
|
return repo._bookmarkcurrent
|