1 # -*- coding: utf-8 -*-
4 Copyright (C) 2007, Karl Hasselström <kha@treskal.com>
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License version 2 as
8 published by the Free Software Foundation.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 from optparse import make_option
21 from stgit.out import *
22 from stgit import utils
23 from stgit.commands import common
24 from stgit.lib import git, transaction
26 help = 'coalesce two or more patches into one'
27 usage = """%prog [options] <patches>
29 Coalesce two or more patches, creating one big patch that contains all
30 their changes. The patches must all be applied, and must be
33 directory = common.DirectoryHasRepositoryLib()
34 options = [make_option('-n', '--name', help = 'name of coalesced patch'),
35 make_option('-m', '--message',
36 help = 'commit message of coalesced patch')]
38 def _coalesce(stack, name, msg, patches):
39 applied = stack.patchorder.applied
41 # Make sure the patches are consecutive.
42 applied_ix = dict((applied[i], i) for i in xrange(len(applied)))
43 ixes = list(sorted(applied_ix[p] for p in patches))
44 i0, i1 = ixes[0], ixes[-1]
45 if i1 - i0 + 1 != len(patches):
46 raise common.CmdException('The patches must be consecutive')
48 # Make a commit for the coalesced patch.
50 return pn not in patches and stack.patches.exists(pn)
51 if name and bad_name(name):
52 raise common.CmdException('Patch name "%s" already taken')
53 ps = [stack.patches.get(pn) for pn in applied[i0:i1+1]]
55 msg = '\n\n'.join('%s\n\n%s' % (p.name.ljust(70, '-'),
56 p.commit.data.message)
58 msg = utils.edit_string(msg, '.stgit-coalesce.txt').strip()
60 name = utils.make_patch_name(msg, bad_name)
61 cd = git.Commitdata(tree = ps[-1].commit.data.tree,
62 parents = ps[0].commit.data.parents, message = msg)
65 trans = transaction.StackTransaction(stack, 'stg coalesce')
66 for pn in applied[i0:i1+1]:
67 trans.patches[pn] = None
68 parent = trans.patches[name] = stack.repository.commit(cd)
69 trans.applied = applied[:i0]
70 trans.applied.append(name)
71 for pn in applied[i1+1:]:
72 p = stack.patches.get(pn)
73 parent = trans.patches[pn] = stack.repository.commit(
74 p.commit.data.set_parent(parent))
75 trans.applied.append(pn)
78 def func(parser, options, args):
79 stack = directory.repository.current_stack
80 applied = set(stack.patchorder.applied)
81 patches = set(common.parse_patches(args, list(stack.patchorder.applied)))
83 raise common.CmdException('Need at least two patches')
84 _coalesce(stack, options.name, options.message, patches)