Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"""
-import sys, os
-from optparse import OptionParser, make_option
-
-from stgit.commands.common import *
-from stgit.utils import *
-from stgit import stack, git
-
-
-help = 'push a patch on top of the series'
-usage = """%prog [options] [<name>]
-
-Push a patch (defaulting to the first unapplied one) or range of
-patches to the stack. The 'push' operation allows patch reordering by
-commuting them with the three-way merge algorithm. If the result of
-the 'push' operation is not acceptable or if there are too many
-conflicts, the '--undo' option can be used to revert the patch and the
-tree to the state before the operation. Conflicts raised during the
-push operation have to be fixed and the 'resolved' command run.
+from stgit.commands import common
+from stgit.lib import transaction
+from stgit import argparse
+from stgit.argparse import opt
+
+help = 'Push one or more patches onto the stack'
+kind = 'stack'
+usage = ['[options] [<patch1>] [<patch2>] [<patch3>..<patch4>]']
+description = """
+Push one or more patches (defaulting to the first unapplied one) onto
+the stack. The 'push' operation allows patch reordering by commuting
+them with the three-way merge algorithm. If there are conflicts while
+pushing a patch, those conflicts are written to the work tree, and the
+command halts. Conflicts raised during the push operation have to be
+fixed and the 'git add --update' command run (alternatively, you may
+undo the conflicting push with 'stg undo').
The command also notifies when the patch becomes empty (fully merged
upstream) or is modified (three-way merged) by the 'push' operation."""
-options = [make_option('-a', '--all',
- help = 'push all the unapplied patches',
- action = 'store_true'),
- make_option('-n', '--number', type = 'int',
- help = 'push the specified number of patches'),
- make_option('-t', '--to', metavar = 'PATCH1[:PATCH2]',
- help = 'push all patches to PATCH1 or between '
- 'PATCH1 and PATCH2'),
- make_option('--reverse',
- help = 'push the patches in reverse order',
- action = 'store_true'),
- make_option('--undo',
- help = 'undo the last push operation',
- action = 'store_true')]
-
-
-def is_patch_appliable(p):
- """See if patch exists, or is already applied.
- """
- if p in applied:
- raise CmdException, 'Patch "%s" is already applied.' % p
- if p not in unapplied:
- raise CmdException, 'Patch "%s" does not exist.' % p
+args = [argparse.patch_range(argparse.unapplied_patches)]
+options = [
+ opt('-a', '--all', action = 'store_true',
+ short = 'Push all the unapplied patches'),
+ opt('-n', '--number', type = 'int',
+ short = 'Push the specified number of patches'),
+ opt('--reverse', action = 'store_true',
+ short = 'Push the patches in reverse order'),
+ opt('--set-tree', action = 'store_true',
+ short = 'Push the patch with the original tree', long = """
+ Push the patches, but don't perform a merge. Instead, the
+ resulting tree will be identical to the tree that the patch
+ previously created.
+
+ This can be useful when splitting a patch by first popping the
+ patch and creating a new patch with some of the
+ changes. Pushing the original patch with '--set-tree' will
+ avoid conflicts and only the remaining changes will be in the
+ patch.""")
+ ] + argparse.keep_option() + argparse.merged_option()
+
+directory = common.DirectoryHasRepositoryLib()
def func(parser, options, args):
- """Pushes the given patch or all onto the series
- """
- global applied, unapplied
-
- # If --undo is passed, do the work and exit
- if options.undo:
- patch = crt_series.get_current()
- if not patch:
- raise CmdException, 'No patch to undo'
-
- print 'Undoing the "%s" push...' % patch,
- sys.stdout.flush()
- resolved_all()
- if crt_series.undo_push():
- print 'done'
- else:
- print 'done (patch unchanged)'
- print_crt_patch()
-
- return
-
- check_local_changes()
- check_conflicts()
- check_head_top_equal()
-
- applied = crt_series.get_applied()
- unapplied = crt_series.get_unapplied()
- if not unapplied:
- raise CmdException, 'No more patches to push'
-
- if options.to:
- boundaries = options.to.split(':')
- if len(boundaries) == 1:
- is_patch_appliable(boundaries[0])
- patches = unapplied[:unapplied.index(boundaries[0])+1]
- elif len(boundaries) == 2:
- is_patch_appliable(boundaries[0])
- is_patch_appliable(boundaries[1])
- lb = unapplied.index(boundaries[0])
- hb = unapplied.index(boundaries[1])
- if lb > hb:
- raise CmdException, 'Patch "%s" after "%s"' \
- % (boundaries[0], boundaries[1])
- patches = unapplied[lb:hb+1]
- else:
- raise CmdException, 'incorrect parameters to "--to"'
+ """Pushes the given patches or the first unapplied onto the stack."""
+ stack = directory.repository.current_stack
+ iw = stack.repository.default_iw
+ clean_iw = (not options.keep and iw) or None
+ trans = transaction.StackTransaction(stack, 'pop',
+ check_clean_iw = clean_iw)
+
+ if not trans.unapplied:
+ raise common.CmdException('No patches to push')
+
+ if options.all:
+ patches = list(trans.unapplied)
elif options.number:
- patches = unapplied[:options.number]
- elif options.all:
- patches = unapplied
- elif len(args) == 0:
- patches = [unapplied[0]]
- elif len(args) == 1:
- patches = args
- is_patch_appliable(patches[0])
+ patches = trans.unapplied[:options.number]
+ elif not args:
+ patches = [trans.unapplied[0]]
else:
- parser.error('incorrect number of arguments')
+ patches = common.parse_patches(args, trans.unapplied)
- if patches == []:
- raise CmdException, 'No patches to push'
+ if not patches:
+ raise common.CmdException('No patches to push')
if options.reverse:
patches.reverse()
- forwarded = crt_series.forward_patches(patches)
- if forwarded > 1:
- print 'Fast-forwarded patches "%s" - "%s"' % (patches[0],
- patches[forwarded - 1])
- elif forwarded == 1:
- print 'Fast-forwarded patch "%s"' % patches[0]
-
- for p in patches[forwarded:]:
- is_patch_appliable(p)
-
- print 'Pushing patch "%s"...' % p,
- sys.stdout.flush()
-
- modified = crt_series.push_patch(p)
-
- if crt_series.empty_patch(p):
- print 'done (empty patch)'
- elif modified:
- print 'done (modified)'
- else:
- print 'done'
- print_crt_patch()
+ if options.set_tree:
+ for pn in patches:
+ trans.push_tree(pn)
+ else:
+ try:
+ if options.merged:
+ merged = set(trans.check_merged(patches))
+ else:
+ merged = set()
+ for pn in patches:
+ trans.push_patch(pn, iw, allow_interactive = True,
+ already_merged = pn in merged)
+ except transaction.TransactionHalted:
+ pass
+ return trans.run(iw)