| 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 | Take one or more git commits at the base of the current stack and turn |
| 29 | them into StGIT patches. The new patches are created as applied patches |
| 30 | at the bottom of the stack. This is the exact opposite of 'stg commit'. |
| 31 | |
| 32 | By default, the number of the patches to uncommit is determined by the |
| 33 | number of patch names provided on the command line. First name is used |
| 34 | for the first patch to uncommit, i.e. for the newest patch. |
| 35 | |
| 36 | The --number option specifies the number of patches to uncommit. In |
| 37 | this case, only one patch name may be specified. It is used as prefix to |
| 38 | which the patch number is appended. |
| 39 | |
| 40 | Only commits with exactly one parent can be uncommitted; in other |
| 41 | words, you can't uncommit a merge.""" |
| 42 | |
| 43 | options = [make_option('-n', '--number', type = 'int', |
| 44 | help = 'uncommit the specified number of commits')] |
| 45 | |
| 46 | def func(parser, options, args): |
| 47 | if len(args) == 0: |
| 48 | parser.error('you must specify at least one patch name') |
| 49 | if options.number: |
| 50 | if len(args) != 1: |
| 51 | parser.error('when using --number, specify exactly one patch name') |
| 52 | patchnames = ['%s%d' % (args[0], i) |
| 53 | for i in xrange(options.number - 1, -1, -1)] |
| 54 | else: |
| 55 | patchnames = args |
| 56 | |
| 57 | if crt_series.get_protected(): |
| 58 | raise CmdException, 'This branch is protected. Uncommit is not permitted' |
| 59 | |
| 60 | print 'Uncommitting %d patches...' % len(patchnames), |
| 61 | sys.stdout.flush() |
| 62 | |
| 63 | for patchname in patchnames: |
| 64 | base_file = crt_series.get_base_file() |
| 65 | commit_id = read_string(base_file) |
| 66 | commit = git.Commit(commit_id) |
| 67 | try: |
| 68 | parent, = commit.get_parents() |
| 69 | except ValueError: |
| 70 | raise CmdException, ('Commit %s does not have exactly one parent' |
| 71 | % commit_id) |
| 72 | author_name, author_email, author_date = name_email_date( |
| 73 | commit.get_author()) |
| 74 | crt_series.new_patch(patchname, |
| 75 | can_edit = False, before_existing = True, |
| 76 | top = commit_id, bottom = parent, |
| 77 | message = commit.get_log(), |
| 78 | author_name = author_name, |
| 79 | author_email = author_email, |
| 80 | author_date = author_date) |
| 81 | write_string(base_file, parent) |
| 82 | |
| 83 | print 'done' |