More changelog updates
[stgit.git] / stgit / commands / commit.py
blob5ed995e0809bb5b1fb4b9d5dd0a90fd4c3ceafab
1 from stgit.argparse import opt, patch_range
2 from stgit.commands.common import CmdException, DirectoryHasRepository, parse_patches
3 from stgit.lib import transaction
4 from stgit.out import out
6 __copyright__ = """
7 Copyright (C) 2005, Catalin Marinas <catalin.marinas@gmail.com>
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License version 2 as
11 published by the Free Software Foundation.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, see http://www.gnu.org/licenses/.
20 """
22 help = 'Permanently store the applied patches into the stack base'
23 kind = 'stack'
24 usage = ['', '[--] <patchnames>', '-n NUM', '--all']
25 description = """
26 Merge one or more patches into the base of the current stack and
27 remove them from the series while advancing the base. This is the
28 opposite of 'stg uncommit'. Use this command if you no longer want to
29 manage a patch with StGit.
31 By default, the bottommost patch is committed. If patch names are
32 given, the stack is rearranged so that those patches are at the
33 bottom, and then they are committed.
35 The -n/--number option specifies the number of applied patches to
36 commit (counting from the bottom of the stack). If -a/--all is given,
37 all applied patches are committed."""
39 args = [patch_range('applied_patches', 'unapplied_patches')]
40 options = [
41 opt(
42 '-n',
43 '--number',
44 type='int',
45 short='Commit the specified number of patches',
47 opt('-a', '--all', action='store_true', short='Commit all applied patches'),
50 directory = DirectoryHasRepository()
53 def func(parser, options, args):
54 """Commit a number of patches."""
55 stack = directory.repository.current_stack
56 args = parse_patches(args, list(stack.patchorder.all_visible))
57 exclusive = [args, options.number is not None, options.all]
58 if sum(map(bool, exclusive)) > 1:
59 parser.error('too many options')
60 if args:
61 patches = [pn for pn in stack.patchorder.all_visible if pn in args]
62 bad = set(args) - set(patches)
63 if bad:
64 raise CmdException(
65 'Nonexistent or hidden patch names: %s' % (', '.join(sorted(bad)),)
67 elif options.number is not None:
68 if options.number <= len(stack.patchorder.applied):
69 patches = stack.patchorder.applied[: options.number]
70 else:
71 raise CmdException('There are not that many applied patches')
72 elif options.all:
73 patches = stack.patchorder.applied
74 else:
75 patches = stack.patchorder.applied[:1]
76 if not patches:
77 raise CmdException('No patches to commit')
79 iw = stack.repository.default_iw
81 def allow_conflicts(trans):
82 # As long as the topmost patch stays where it is, it's OK to
83 # run "stg commit" with conflicts in the index.
84 return len(trans.applied) >= 1
86 trans = transaction.StackTransaction(
87 stack, 'commit', allow_conflicts=allow_conflicts
89 try:
90 common_prefix = 0
91 for i in range(min(len(stack.patchorder.applied), len(patches))):
92 if stack.patchorder.applied[i] == patches[i]:
93 common_prefix += 1
94 else:
95 break
96 if common_prefix < len(patches):
97 to_push = [
99 for pn in stack.patchorder.applied[common_prefix:]
100 if pn not in patches[common_prefix:]
102 # this pops all the applied patches from common_prefix
103 trans.pop_patches(lambda pn: pn in to_push)
104 for pn in patches[common_prefix:]:
105 trans.push_patch(pn, iw)
106 else:
107 to_push = []
108 new_base = trans.patches[patches[-1]]
109 for pn in patches:
110 trans.patches[pn] = None
111 trans.applied = [pn for pn in trans.applied if pn not in patches]
112 trans.base = new_base
113 out.info('Committed %d patch%s' % (len(patches), ['es', ''][len(patches) == 1]))
114 for pn in to_push:
115 trans.push_patch(pn, iw)
116 except transaction.TransactionHalted:
117 pass
118 return trans.run(iw)