[PATCH 2/2] Add 'stg uncommit' command
[stgit] / stgit / commands / uncommit.py
1 __copyright__ = """
2 Copyright (C) 2006, Karl Hasselström <kha@treskal.com>
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License version 2 as
6 published by the Free Software Foundation.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16 """
17
18 import sys, os
19 from optparse import OptionParser, make_option
20
21 from stgit.commands.common import *
22 from stgit.utils import *
23 from stgit import stack, git
24
25 help = 'turn regular git commits into StGIT patches'
26 usage = """%prog [options] <patchname1> [<patchname2> ... ]
27
28 Takes one or more git commits at the base of the current stack, and
29 turns them into StGIT patches. These new patches are alreay applied,
30 at the bottom of the stack. This is the exact opposite of 'stg
31 commit'.
32
33 You can either give one patch name for each commit you wish to
34 uncommit, or use the --number option and exactly one patch name; StGIT
35 will then create numbered patches with the given patch name as prefix.
36
37 Only commits with exactly one parent can be uncommitted; in other
38 words, you can't uncommmit a merge."""
39
40 options = [make_option('-n', '--number', type = 'int',
41 help = 'uncommit the specified number of commits')]
42
43 def func(parser, options, args):
44 if len(args) == 0:
45 parser.error('you must specify at least one patch name')
46 if options.number:
47 if len(args) != 1:
48 parser.error('when using --number, specify exactly one patch name')
49 patchnames = ['%s%d' % (args[0], i)
50 for i in xrange(options.number - 1, -1, -1)]
51 else:
52 patchnames = args
53
54 if crt_series.get_protected():
55 raise CmdException, 'This branch is protected. Uncommit is not permitted'
56
57 print 'Uncommitting %d patches...' % len(patchnames),
58 sys.stdout.flush()
59
60 for patchname in patchnames:
61 base_file = crt_series.get_base_file()
62 commit_id = read_string(base_file)
63 commit = git.Commit(commit_id)
64 try:
65 parent, = commit.get_parents()
66 except ValueError:
67 raise CmdException, ('Commit %s does not have exactly one parent'
68 % commit_id)
69 author_name, author_email, author_date = name_email_date(
70 commit.get_author())
71 crt_series.new_patch(patchname,
72 can_edit = False, before_existing = True,
73 top = commit_id, bottom = parent,
74 message = commit.get_log(),
75 author_name = author_name,
76 author_email = author_email,
77 author_date = author_date)
78 write_string(base_file, parent)
79
80 print 'done'