sapling/edenscm/hgext/amend/__init__.py

553 lines
17 KiB
Python
Raw Normal View History

# amend.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
Adds an hg amend command that amends the current parent changeset with the
changes in the working copy. Similar to the existing hg commit --amend
except it doesn't prompt for the commit message unless --edit is provided.
Allows amending changesets that have children and can automatically rebase
the children onto the new version of the changeset.
fbamend: add new implementations of `hg previous` and `hg next` Summary: This diff replaces the `hg previous` and `hg next` commands from the evolve extension with new implementations. The new commands have several features not found in evolve: - Users can now move by multiple commits at a time. Example: `hg next 3` - Users can move all the way to the top or bottom of the current stack with the following new flags: `hg next --top` and `hg prev --bottom` - Users can rebase child commits on demand with `hg next --rebase`. This flag can be combined with the others to specify exactly how many commits to rebase. Example: `hg next --rebase 4` (move 4 commits up the stack, rebasing as needed) `hg next --rebase --top` (rebase all the way to the top of the stack) - When a user lands on a particular commit, if there is a bookmark it will be automatically activated. The user can also move to the previous or next commit with a bookmark with the `--bookmark` flag. - The user can pass the `--newest` flag to resolve ambiguity in situations where history is nonlinear. With the flag the command will always choose the commit with the higher rev number at each step. - The commands now show commit hashes instead of rev numbers when showing the user what commit they landed on. Apologies in advance for the large diff. I've tried splitting it up as best as I could, but the unit tests introduced here significantly increase the size. I figured the unit tests should be part of this diff instead of being added in a separate one. This diff is almost entirely new code, so I hope that helps a little bit. Let me know if there's a better way to split this up. Test Plan: See the new unit tests for an extensive look at the new commands in action. Essentially, all of the features mentioned above should work as expected. Reviewers: quark, #sourcecontrol, durham Reviewed By: durham Subscribers: stash, mjpieters Differential Revision: https://phabricator.intern.facebook.com/D4121778 Tasks: 14119420 Signature: t1:4121778:1478774243:a7131593222bc329f541e77e1d3ebd8222e47e79
2016-11-16 05:46:56 +03:00
To make `hg previous` and `hg next` always pick the newest commit at
each step of walking up or down the stack instead of aborting when
encountering non-linearity (equivalent to the --newest flag), enable
fbamend: add new implementations of `hg previous` and `hg next` Summary: This diff replaces the `hg previous` and `hg next` commands from the evolve extension with new implementations. The new commands have several features not found in evolve: - Users can now move by multiple commits at a time. Example: `hg next 3` - Users can move all the way to the top or bottom of the current stack with the following new flags: `hg next --top` and `hg prev --bottom` - Users can rebase child commits on demand with `hg next --rebase`. This flag can be combined with the others to specify exactly how many commits to rebase. Example: `hg next --rebase 4` (move 4 commits up the stack, rebasing as needed) `hg next --rebase --top` (rebase all the way to the top of the stack) - When a user lands on a particular commit, if there is a bookmark it will be automatically activated. The user can also move to the previous or next commit with a bookmark with the `--bookmark` flag. - The user can pass the `--newest` flag to resolve ambiguity in situations where history is nonlinear. With the flag the command will always choose the commit with the higher rev number at each step. - The commands now show commit hashes instead of rev numbers when showing the user what commit they landed on. Apologies in advance for the large diff. I've tried splitting it up as best as I could, but the unit tests introduced here significantly increase the size. I figured the unit tests should be part of this diff instead of being added in a separate one. This diff is almost entirely new code, so I hope that helps a little bit. Let me know if there's a better way to split this up. Test Plan: See the new unit tests for an extensive look at the new commands in action. Essentially, all of the features mentioned above should work as expected. Reviewers: quark, #sourcecontrol, durham Reviewed By: durham Subscribers: stash, mjpieters Differential Revision: https://phabricator.intern.facebook.com/D4121778 Tasks: 14119420 Signature: t1:4121778:1478774243:a7131593222bc329f541e77e1d3ebd8222e47e79
2016-11-16 05:46:56 +03:00
the following config option::
[amend]
fbamend: add new implementations of `hg previous` and `hg next` Summary: This diff replaces the `hg previous` and `hg next` commands from the evolve extension with new implementations. The new commands have several features not found in evolve: - Users can now move by multiple commits at a time. Example: `hg next 3` - Users can move all the way to the top or bottom of the current stack with the following new flags: `hg next --top` and `hg prev --bottom` - Users can rebase child commits on demand with `hg next --rebase`. This flag can be combined with the others to specify exactly how many commits to rebase. Example: `hg next --rebase 4` (move 4 commits up the stack, rebasing as needed) `hg next --rebase --top` (rebase all the way to the top of the stack) - When a user lands on a particular commit, if there is a bookmark it will be automatically activated. The user can also move to the previous or next commit with a bookmark with the `--bookmark` flag. - The user can pass the `--newest` flag to resolve ambiguity in situations where history is nonlinear. With the flag the command will always choose the commit with the higher rev number at each step. - The commands now show commit hashes instead of rev numbers when showing the user what commit they landed on. Apologies in advance for the large diff. I've tried splitting it up as best as I could, but the unit tests introduced here significantly increase the size. I figured the unit tests should be part of this diff instead of being added in a separate one. This diff is almost entirely new code, so I hope that helps a little bit. Let me know if there's a better way to split this up. Test Plan: See the new unit tests for an extensive look at the new commands in action. Essentially, all of the features mentioned above should work as expected. Reviewers: quark, #sourcecontrol, durham Reviewed By: durham Subscribers: stash, mjpieters Differential Revision: https://phabricator.intern.facebook.com/D4121778 Tasks: 14119420 Signature: t1:4121778:1478774243:a7131593222bc329f541e77e1d3ebd8222e47e79
2016-11-16 05:46:56 +03:00
alwaysnewest = true
To automatically update the commit date, enable the following config option::
[amend]
date = implicitupdate
Commits are restacked automatically on amend, if doing so doesn't create
conflicts. To never automatically restack::
[amend]
autorestack = none
Note that if --date is specified on the command line, it takes precedence.
If a split creates multiple commits that have the same phabricator diff, the
following advice for resolution will be shown::
[split]
phabricatoradvice = edit the commit messages to remove the association
"""
from __future__ import absolute_import
import tempfile
from edenscm.mercurial import (
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
bookmarks,
cmdutil,
commands,
error,
extensions,
hintutil,
lock as lockmod,
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
phases,
registrar,
scmutil,
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 edenscm.mercurial.i18n import _
from edenscm.mercurial.node import hex, short
from . import (
common,
fold,
hiddenoverride,
hide,
metaedit,
movement,
prune,
restack,
revsets,
split,
unamend,
)
from .. import histedit, rebase as rebasemod
revsetpredicate = revsets.revsetpredicate
hint = registrar.hint()
cmdtable = {}
command = registrar.command(cmdtable)
cmdtable.update(fold.cmdtable)
cmdtable.update(hide.cmdtable)
cmdtable.update(metaedit.cmdtable)
cmdtable.update(movement.cmdtable)
cmdtable.update(prune.cmdtable)
cmdtable.update(split.cmdtable)
cmdtable.update(unamend.cmdtable)
configtable = {}
configitem = registrar.configitem(configtable)
configitem("amend", "alwaysnewest", default=False)
configitem("amend", "date", default=None)
configitem("amend", "education", default=None)
configitem("commands", "amend.autorebase", default=True)
testedwith = "ships-with-fb-hgext"
amendopts = [
("", "rebase", None, _("rebases children after the amend")),
("", "fixup", None, _("rebase children from a previous amend")),
("", "to", "", _("amend to a specific commit in the current stack")),
] + cmdutil.templateopts
# Never restack commits on amend.
RESTACK_NEVER = "never"
# Restack commits on amend only if they chage manifest, and don't change the
# commit manifest.
RESTACK_ONLY_TRIVIAL = "only-trivial"
# Restack commits on amend only if doing so won't create merge conflicts.
RESTACK_NO_CONFLICT = "no-conflict"
# Always attempt to restack commits on amend, even if doing so will leave the
# user in a conflicted state.
RESTACK_ALWAYS = "always"
# Possible restack values for `amend.autorestack`.
RESTACK_VALUES = [
RESTACK_NEVER,
RESTACK_ONLY_TRIVIAL,
RESTACK_NO_CONFLICT,
RESTACK_ALWAYS,
]
RESTACK_DEFAULT = RESTACK_ONLY_TRIVIAL
@hint("strip-hide")
def hinthide():
return _("'hg strip' may be deprecated in the future - " "use 'hg hide' instead")
@hint("strip-uncommit")
def hintstrip():
return _(
"'hg strip' may be deprecated in the future - "
"use 'hg uncommit' or 'hg undo -k' to undo commits"
)
@hint("amend-restack")
def hintrestack(node):
return _(
"descendants of %s are left behind - use 'hg restack' to rebase " "them"
) % short(node)
@hint("amend-autorebase")
def hintautorebase():
return _(
"descendants have been auto-rebased because no merge conflict "
"could have happened - use --no-rebase or set "
"commands.amend.autorebase=False to disable auto rebase"
)
@hint("update-prev")
def hintprev():
return _("use 'hg prev' to move to the parent changeset")
@hint("split-phabricator")
def hintsplitphabricator(advice):
msg = _("some split commits have the same Phabricator Diff associated with them")
if advice:
msg += "\n" + advice
return msg
def uisetup(ui):
hiddenoverride.uisetup(ui)
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)
# manual call of the decorator
command(
"^amend",
[
(
"A",
"addremove",
None,
_("mark new/missing files as added/removed before committing"),
),
("e", "edit", None, _("prompt to edit the commit message")),
("i", "interactive", None, _("use interactive mode")),
]
+ amendopts
+ commands.walkopts
+ commands.commitopts
+ commands.commitopts2,
_("hg amend [OPTION]..."),
)(amend)
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)
def evolveloaded(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
evolvemod = extensions.find("evolve")
fbamend: add new implementations of `hg previous` and `hg next` Summary: This diff replaces the `hg previous` and `hg next` commands from the evolve extension with new implementations. The new commands have several features not found in evolve: - Users can now move by multiple commits at a time. Example: `hg next 3` - Users can move all the way to the top or bottom of the current stack with the following new flags: `hg next --top` and `hg prev --bottom` - Users can rebase child commits on demand with `hg next --rebase`. This flag can be combined with the others to specify exactly how many commits to rebase. Example: `hg next --rebase 4` (move 4 commits up the stack, rebasing as needed) `hg next --rebase --top` (rebase all the way to the top of the stack) - When a user lands on a particular commit, if there is a bookmark it will be automatically activated. The user can also move to the previous or next commit with a bookmark with the `--bookmark` flag. - The user can pass the `--newest` flag to resolve ambiguity in situations where history is nonlinear. With the flag the command will always choose the commit with the higher rev number at each step. - The commands now show commit hashes instead of rev numbers when showing the user what commit they landed on. Apologies in advance for the large diff. I've tried splitting it up as best as I could, but the unit tests introduced here significantly increase the size. I figured the unit tests should be part of this diff instead of being added in a separate one. This diff is almost entirely new code, so I hope that helps a little bit. Let me know if there's a better way to split this up. Test Plan: See the new unit tests for an extensive look at the new commands in action. Essentially, all of the features mentioned above should work as expected. Reviewers: quark, #sourcecontrol, durham Reviewed By: durham Subscribers: stash, mjpieters Differential Revision: https://phabricator.intern.facebook.com/D4121778 Tasks: 14119420 Signature: t1:4121778:1478774243:a7131593222bc329f541e77e1d3ebd8222e47e79
2016-11-16 05:46:56 +03:00
# Remove conflicted commands from evolve.
table = evolvemod.cmdtable
for name in ["prev", "next", "split", "fold", "metaedit", "prune"]:
todelete = [k for k in table if name in k]
for k in todelete:
oldentry = table[k]
table["debugevolve%s" % name] = oldentry
del table[k]
extensions.afterloaded("evolve", evolveloaded)
def rebaseloaded(loaded):
if not loaded:
return
entry = extensions.wrapcommand(rebasemod.cmdtable, "rebase", wraprebase)
entry[1].append(
(
"",
"restack",
False,
_(
"rebase all changesets in the current "
"stack onto the latest version of their "
"respective parents"
),
)
)
extensions.afterloaded("rebase", rebaseloaded)
def showtemplate(ui, repo, rev, **opts):
if opts.get("template"):
displayer = cmdutil.show_changeset(ui, repo, opts)
displayer.show(rev)
def commit(orig, ui, repo, *pats, **opts):
if opts.get("amend"):
# commit --amend default behavior is to prompt for edit
opts["noeditmessage"] = True
return amend(ui, repo, *pats, **opts)
else:
badflags = [flag for flag in ["rebase", "fixup"] if opts.get(flag, None)]
if badflags:
raise error.Abort(_("--%s must be called with --amend") % badflags[0])
rc = orig(ui, repo, *pats, **opts)
current = repo["."]
showtemplate(ui, repo, current, **opts)
return rc
def amend(ui, repo, *pats, **opts):
"""save pending changes to the current commit
"""
# 'rebase' is a tristate option: None=auto, True=force, False=disable
rebase = opts.get("rebase")
to = opts.get("to")
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")
raise error.Abort("histedit in progress", hint=hint)
badflags = [flag for flag in ["rebase", "fixup"] if opts.get(flag, None)]
if opts.get("interactive") and badflags:
raise error.Abort(
_("--interactive and --%s are mutually exclusive") % badflags[0]
)
fixup = opts.get("fixup")
badtoflags = [
"rebase",
"fixup",
"addremove",
"edit",
"interactive",
"include",
"exclude",
"message",
"logfile",
"date",
"user",
"no-move-detection",
"stack",
"template",
]
if to and any(opts.get(flag, None) for flag in badtoflags):
raise error.Abort(_("--to cannot be used with any other options"))
if fixup:
fixupamend(ui, repo)
return
if to:
amendtocommit(ui, repo, to)
return
old = repo["."]
if old.phase() == phases.public:
raise error.Abort(_("cannot amend public changesets"))
if len(repo[None].parents()) > 1:
raise error.Abort(_("cannot amend while merging"))
haschildren = len(old.children()) > 0
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"] = ""
if not opts.get("noeditmessage") and not opts.get("message"):
opts["message"] = old.description()
commitdate = opts.get("date")
if not commitdate:
if ui.config("amend", "date") == "implicitupdate":
commitdate = "now"
else:
commitdate = old.date()
oldbookmarks = old.bookmarks()
tr = None
wlock = None
lock = None
try:
wlock = repo.wlock()
lock = repo.lock()
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, old, {}, pats, opts)
if node == old.node():
ui.status(_("nothing changed\n"))
return 1
conf = ui.config("amend", "autorestack", RESTACK_DEFAULT)
noconflict = None
# RESTACK_NO_CONFLICT requires IMM.
if conf == RESTACK_NO_CONFLICT and not ui.config(
"rebase", "experimental.inmemory", False
):
conf = RESTACK_DEFAULT
# If they explicitly disabled the old behavior, disable the new behavior
# too, for now.
# internal config: commands.amend.autorebase
if ui.configbool("commands", "amend.autorebase") is False:
# In the future we'll add a nag message here.
conf = RESTACK_NEVER
if conf not in RESTACK_VALUES:
ui.warn(
_('invalid amend.autorestack config of "%s"; falling back to %s\n')
% (conf, RESTACK_DEFAULT)
)
conf = RESTACK_DEFAULT
if haschildren and rebase is None and not _histediting(repo):
if conf == RESTACK_ALWAYS:
rebase = True
elif conf == RESTACK_NO_CONFLICT:
if repo[None].dirty():
# For now, only restack if the WC is clean (t31742174).
ui.status(_("not restacking because working copy is dirty\n"))
rebase = False
else:
# internal config: amend.autorestackmsg
msg = ui.config(
"amend",
"autorestackmsg",
_("restacking children automatically (unless they conflict)"),
)
if msg:
ui.status("%s\n" % msg)
rebase = True
noconflict = True
elif conf == RESTACK_ONLY_TRIVIAL:
newcommit = repo[node]
# If the rebase did not change the manifest and the
# working copy is clean, force the children to be
# restacked.
rebase = (
old.manifestnode() == newcommit.manifestnode()
and not repo[None].dirty()
)
if rebase:
hintutil.trigger("amend-autorebase")
else:
rebase = False
if haschildren and not rebase and not _histediting(repo):
hintutil.trigger("amend-restack", old.node())
changes = []
# move old bookmarks to new node
for bm in oldbookmarks:
changes.append((bm, node))
tr = repo.transaction("fixupamend")
repo._bookmarks.applychanges(repo, tr, changes)
tr.close()
if rebase and haschildren:
noconflictmsg = _(
"restacking would create conflicts (%s in %s), so you must run it manually\n(run `hg restack` manually to restack this commit's children)"
)
fixupamend(ui, repo, noconflict=noconflict, noconflictmsg=noconflictmsg)
showtemplate(ui, repo, repo[node], **opts)
finally:
lockmod.release(wlock, lock, tr)
def fixupamend(ui, repo, noconflict=None, noconflictmsg=None):
"""rebases any children found on the preamend changset and strips the
preamend changset
"""
wlock = None
lock = None
tr = None
try:
wlock = repo.wlock()
lock = repo.lock()
current = repo["."]
# Use obsolescence information to fix up the amend.
common.restackonce(
ui, repo, current.rev(), noconflict=noconflict, noconflictmsg=noconflictmsg
)
finally:
lockmod.release(wlock, lock, tr)
def amendtocommit(ui, repo, commitspec):
"""amend to a specific commit
"""
with repo.wlock(), repo.lock():
originalcommits = list(repo.set("::. - public()"))
try:
revs = scmutil.revrange(repo, [commitspec])
except error.RepoLookupError:
raise error.Abort(_("revision '%s' cannot be found") % commitspec)
if len(revs) > 1:
raise error.Abort(_("'%s' refers to multiple changesets") % commitspec)
targetcommit = repo[revs.first()]
if targetcommit not in originalcommits:
raise error.Abort(
_("revision '%s' is not a parent of the working copy") % commitspec
)
tempcommit = repo.commit(text="tempCommit")
if not tempcommit:
raise error.Abort(_("no pending changes to amend"))
tempcommithex = hex(tempcommit)
fp = tempfile.NamedTemporaryFile()
try:
found = False
for curcommit in originalcommits:
fp.write("pick " + str(curcommit) + "\n")
if curcommit == targetcommit:
fp.write("roll " + tempcommithex[:12] + "\n")
found = True
if not found:
raise error.Abort(_("revision '%s' cannot be found") % commitspec)
fp.flush()
try:
histedit.histedit(ui, repo, commands=fp.name)
except error.InterventionRequired:
ui.warn(
_(
"amend --to encountered an issue - "
"use hg histedit to continue or abort"
)
)
raise
finally:
fp.close()
def wraprebase(orig, ui, repo, *pats, **opts):
"""Wrapper around `hg rebase` adding the `--restack` option, which rebases
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.
"""
if opts["restack"]:
# We can't abort if --dest is passed because some extensions
# (namely remotenames) will automatically add this flag.
# So just silently drop it instead.
opts.pop("dest", None)
if opts["rev"]:
raise error.Abort(_("cannot use both --rev 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"))
# The --hidden option is handled at a higher level, so instead of
# checking for it directly we have to check whether the repo
# is unfiltered.
if repo == repo.unfiltered():
raise error.Abort(_("cannot use both --hidden and --restack"))
return restack.restack(ui, repo, opts)
return orig(ui, repo, *pats, **opts)
def _histediting(repo):
return repo.localvfs.exists("histedit-state")