5 Copyright (C) 2005, Chuck Lever <cel@netapp.com>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License version 2 as
9 published by the Free Software Foundation.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 from optparse import OptionParser, make_option
24 from stgit.commands.common import *
25 from stgit.utils import *
26 from stgit import stack, git, basedir
29 help = 'manage patch stacks'
30 usage = """%prog [options] branch-name [commit-id]
32 Create, clone, switch between, rename, or delete development branches
33 within a git repository. By default, a single branch called 'master'
34 is always created in a new repository. This subcommand allows you to
35 manage several patch series in the same repository via GIT branches.
37 When displaying the branches, the names can be prefixed with
38 's' (StGIT managed) or 'p' (protected).
40 If not given any options, switch to the named branch."""
42 options = [make_option('-c', '--create',
43 help = 'create a new development branch',
44 action = 'store_true'),
45 make_option('--clone',
46 help = 'clone the contents of the current branch',
47 action = 'store_true'),
48 make_option('--convert',
49 help = 'switch between old and new format branches',
50 action = 'store_true'),
51 make_option('--delete',
52 help = 'delete an existing development branch',
53 action = 'store_true'),
54 make_option('--force',
55 help = 'force a delete when the series is not empty',
56 action = 'store_true'),
57 make_option('-l', '--list',
58 help = 'list branches contained in this repository',
59 action = 'store_true'),
60 make_option('-p', '--protect',
61 help = 'prevent StGIT from modifying this branch',
62 action = 'store_true'),
63 make_option('-r', '--rename',
64 help = 'rename an existing development branch',
65 action = 'store_true'),
66 make_option('-u', '--unprotect',
67 help = 'allow StGIT to modify this branch',
68 action = 'store_true')]
71 def __is_current_branch(branch_name):
72 return crt_series.get_branch() == branch_name
74 def __print_branch(branch_name, length):
79 branch = stack.Series(branch_name)
81 if branch.is_initialised():
83 if __is_current_branch(branch_name):
85 if branch.get_protected():
87 print current + ' ' + initialized + protected + '\t' + \
88 branch_name.ljust(length) + ' | ' + branch.get_description()
90 def __delete_branch(doomed_name, force = False):
91 doomed = stack.Series(doomed_name)
93 if doomed.get_protected():
94 raise CmdException, 'This branch is protected. Delete is not permitted'
96 print 'Deleting branch "%s"...' % doomed_name,
99 if __is_current_branch(doomed_name):
100 check_local_changes()
102 check_head_top_equal()
104 if doomed_name != 'master':
105 git.switch_branch('master')
109 if doomed_name != 'master':
110 git.delete_branch(doomed_name)
114 def func(parser, options, args):
118 if len(args) == 0 or len(args) > 2:
119 parser.error('incorrect number of arguments')
121 check_local_changes()
123 check_head_top_equal()
128 if git.rev_parse(args[1]) == git.rev_parse('refs/heads/' + args[1]):
129 # we are for sure referring to a branch
130 parentbranch = 'refs/heads/' + args[1]
131 print 'Recording "%s" as parent branch.' % parentbranch
132 elif git.rev_parse(args[1]) and re.search('/', args[1]):
133 # FIXME: should the test be more strict ?
134 parentbranch = args[1]
136 # Note: this includes refs to StGIT patches
137 print 'Don\'t know how to determine parent branch from "%s".' % args[1]
139 except git.GitException:
140 # should use a more specific exception to catch only non-git refs ?
141 print 'Don\'t know how to determine parent branch from "%s".' % args[1]
144 tree_id = git_id(args[1])
146 # branch stack off current branch
147 parentbranch = git.get_head_file()
150 parentremote = git.identify_remote(parentbranch)
152 print 'Using "%s" remote to pull parent from.' % parentremote
154 print 'Recording as a local branch.'
156 # no known parent branch, can't guess the remote
159 stack.Series(args[0]).init(create_at = tree_id,
160 parent_remote = parentremote,
161 parent_branch = parentbranch)
163 print 'Branch "%s" created.' % args[0]
169 clone = crt_series.get_branch() + \
170 time.strftime('-%C%y%m%d-%H%M%S')
174 parser.error('incorrect number of arguments')
176 check_local_changes()
178 check_head_top_equal()
180 print 'Cloning current branch to "%s"...' % clone,
182 crt_series.clone(clone)
187 elif options.convert:
190 parser.error('incorrect number of arguments')
198 parser.error('incorrect number of arguments')
199 __delete_branch(args[0], options.force)
205 parser.error('incorrect number of arguments')
208 basepath = os.path.join(basedir.get(), 'refs', 'heads')
209 for path, files, dirs in walk_tree(basepath):
210 branches += [os.path.join(path, f) for f in files]
214 print 'Available branches:'
215 max_len = max([len(i) for i in branches])
217 __print_branch(i, max_len)
222 elif options.protect:
225 branch_name = crt_series.get_branch()
227 branch_name = args[0]
229 parser.error('incorrect number of arguments')
230 branch = stack.Series(branch_name)
232 if not branch.is_initialised():
233 raise CmdException, 'Branch "%s" is not controlled by StGIT' \
236 print 'Protecting branch "%s"...' % branch_name,
246 parser.error('incorrect number of arguments')
248 if __is_current_branch(args[0]):
249 raise CmdException, 'Renaming the current branch is not supported'
251 stack.Series(args[0]).rename(args[1])
253 print 'Renamed branch "%s" as "%s".' % (args[0], args[1])
257 elif options.unprotect:
260 branch_name = crt_series.get_branch()
262 branch_name = args[0]
264 parser.error('incorrect number of arguments')
265 branch = stack.Series(branch_name)
267 if not branch.is_initialised():
268 raise CmdException, 'Branch "%s" is not controlled by StGIT' \
271 print 'Unprotecting branch "%s"...' % branch_name,
280 if __is_current_branch(args[0]):
281 raise CmdException, 'Branch "%s" is already the current branch' \
284 check_local_changes()
286 check_head_top_equal()
288 print 'Switching to branch "%s"...' % args[0],
291 git.switch_branch(args[0])
296 # default action: print the current branch
298 parser.error('incorrect number of arguments')
300 print crt_series.get_branch()