Restore the original applied patches during 'commit'
[stgit] / stgit / commands / commit.py
CommitLineData
6a093bbb
CM
1__copyright__ = """
2Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com>
3
4This program is free software; you can redistribute it and/or modify
5it under the terms of the GNU General Public License version 2 as
6published by the Free Software Foundation.
7
8This program is distributed in the hope that it will be useful,
9but WITHOUT ANY WARRANTY; without even the implied warranty of
10MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11GNU General Public License for more details.
12
13You should have received a copy of the GNU General Public License
14along with this program; if not, write to the Free Software
15Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16"""
17
575bbdae 18from stgit.argparse import opt
3b0552a7
KH
19from stgit.commands import common
20from stgit.lib import transaction
5e888f30 21from stgit.out import *
6c8a90e1 22from stgit import argparse
6a093bbb 23
575bbdae 24help = 'Permanently store the applied patches into the stack base'
33ff9cdd 25kind = 'stack'
575bbdae 26usage = ['',
54239abf 27 '[--] <patchnames>',
575bbdae
KH
28 '-n NUM',
29 '--all']
30description = """
980bde6a
KH
31Merge one or more patches into the base of the current stack and
32remove them from the series while advancing the base. This is the
33opposite of 'stg uncommit'. Use this command if you no longer want to
34manage a patch with StGIT.
6a093bbb 35
980bde6a
KH
36By default, the bottommost patch is committed. If patch names are
37given, the stack is rearranged so that those patches are at the
38bottom, and then they are committed.
6a093bbb 39
980bde6a
KH
40The -n/--number option specifies the number of applied patches to
41commit (counting from the bottom of the stack). If -a/--all is given,
42all applied patches are committed."""
6a093bbb 43
6c8a90e1
KH
44args = [argparse.patch_range(argparse.applied_patches,
45 argparse.unapplied_patches)]
575bbdae
KH
46options = [
47 opt('-n', '--number', type = 'int',
48 short = 'Commit the specified number of patches'),
49 opt('-a', '--all', action = 'store_true',
50 short = 'Commit all applied patches')]
51
980bde6a 52directory = common.DirectoryHasRepositoryLib()
6a093bbb
CM
53
54def func(parser, options, args):
980bde6a 55 """Commit a number of patches."""
3b0552a7 56 stack = directory.repository.current_stack
d454cc06 57 args = common.parse_patches(args, list(stack.patchorder.all_visible))
980bde6a
KH
58 if len([x for x in [args, options.number != None, options.all] if x]) > 1:
59 parser.error('too many options')
60 if args:
d454cc06 61 patches = [pn for pn in stack.patchorder.all_visible if pn in args]
980bde6a
KH
62 bad = set(args) - set(patches)
63 if bad:
d454cc06 64 raise common.CmdException('Nonexistent or hidden patch names: %s'
980bde6a
KH
65 % ', '.join(sorted(bad)))
66 elif options.number != None:
67 if options.number <= len(stack.patchorder.applied):
68 patches = stack.patchorder.applied[:options.number]
69 else:
70 raise common.CmdException('There are not that many applied patches')
71 elif options.all:
72 patches = stack.patchorder.applied
73 else:
74 patches = stack.patchorder.applied[:1]
3b0552a7 75 if not patches:
980bde6a
KH
76 raise common.CmdException('No patches to commit')
77
a0848ecf 78 iw = stack.repository.default_iw
781e549a
KH
79 def allow_conflicts(trans):
80 # As long as the topmost patch stays where it is, it's OK to
81 # run "stg commit" with conflicts in the index.
82 return len(trans.applied) >= 1
83 trans = transaction.StackTransaction(stack, 'commit',
84 allow_conflicts = allow_conflicts)
980bde6a
KH
85 try:
86 common_prefix = 0
87 for i in xrange(min(len(stack.patchorder.applied), len(patches))):
88 if stack.patchorder.applied[i] == patches[i]:
89 common_prefix += 1
d8a700cf
CM
90 else:
91 break
980bde6a 92 if common_prefix < len(patches):
d8a700cf
CM
93 to_push = [pn for pn in stack.patchorder.applied[common_prefix:]
94 if pn not in patches[common_prefix:]]
95 # this pops all the applied patches from common_prefix
96 trans.pop_patches(lambda pn: pn in to_push)
980bde6a
KH
97 for pn in patches[common_prefix:]:
98 trans.push_patch(pn, iw)
99 else:
100 to_push = []
101 new_base = trans.patches[patches[-1]]
102 for pn in patches:
103 trans.patches[pn] = None
104 trans.applied = [pn for pn in trans.applied if pn not in patches]
105 trans.base = new_base
106 out.info('Committed %d patch%s' % (len(patches),
107 ['es', ''][len(patches) == 1]))
108 for pn in to_push:
109 trans.push_patch(pn, iw)
110 except transaction.TransactionHalted:
111 pass
112 return trans.run(iw)