Use get/set_name for a stack's name.
[stgit] / stgit / commands / branch.py
CommitLineData
7b1ba1a6
CL
1"""Branch command
2"""
3
4__copyright__ = """
5Copyright (C) 2005, Chuck Lever <cel@netapp.com>
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License version 2 as
9published by the Free Software Foundation.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19"""
20
cc3db2b1 21import sys, os, time
7b1ba1a6
CL
22from optparse import OptionParser, make_option
23
24from stgit.commands.common import *
25from stgit.utils import *
170f576b 26from stgit import stack, git, basedir
7b1ba1a6
CL
27
28
4ec67741 29help = 'manage patch stacks'
7b1ba1a6
CL
30usage = """%prog [options] branch-name [commit-id]
31
cc3db2b1 32Create, clone, switch between, rename, or delete development branches
7b1ba1a6
CL
33within a git repository. By default, a single branch called 'master'
34is always created in a new repository. This subcommand allows you to
cc3db2b1 35manage several patch series in the same repository via GIT branches.
7b1ba1a6
CL
36
37When displaying the branches, the names can be prefixed with
a8032a85
CL
38's' (StGIT managed) or 'p' (protected).
39
40If not given any options, switch to the named branch."""
7b1ba1a6
CL
41
42options = [make_option('-c', '--create',
43 help = 'create a new development branch',
44 action = 'store_true'),
cc3db2b1
CL
45 make_option('--clone',
46 help = 'clone the contents of the current branch',
47 action = 'store_true'),
7b1ba1a6
CL
48 make_option('--delete',
49 help = 'delete an existing development branch',
50 action = 'store_true'),
302600dc
CM
51 make_option('-d', '--description',
52 help = 'set the branch description'),
7b1ba1a6
CL
53 make_option('--force',
54 help = 'force a delete when the series is not empty',
55 action = 'store_true'),
56 make_option('-l', '--list',
57 help = 'list branches contained in this repository',
58 action = 'store_true'),
0b4b9499 59 make_option('-p', '--protect',
f644f510 60 help = 'prevent StGIT from modifying this branch',
0b4b9499 61 action = 'store_true'),
7b1ba1a6
CL
62 make_option('-r', '--rename',
63 help = 'rename an existing development branch',
0b4b9499
CL
64 action = 'store_true'),
65 make_option('-u', '--unprotect',
f644f510 66 help = 'allow StGIT to modify this branch',
7b1ba1a6
CL
67 action = 'store_true')]
68
69
fe4f6d58 70def __is_current_branch(branch_name):
d37ff079 71 return crt_series.get_name() == branch_name
7b1ba1a6 72
862ba51a 73def __print_branch(branch_name, length):
7b1ba1a6
CL
74 initialized = ' '
75 current = ' '
0b4b9499 76 protected = ' '
ebfd0156
CL
77
78 branch = stack.Series(branch_name)
79
2d00440c 80 if branch.is_initialised():
7b1ba1a6 81 initialized = 's'
fe4f6d58 82 if __is_current_branch(branch_name):
7b1ba1a6 83 current = '>'
ebfd0156 84 if branch.get_protected():
0b4b9499 85 protected = 'p'
27ac2b7e
KH
86 out.stdout(current + ' ' + initialized + protected + '\t'
87 + branch_name.ljust(length) + ' | ' + branch.get_description())
7b1ba1a6 88
fe4f6d58 89def __delete_branch(doomed_name, force = False):
ebfd0156
CL
90 doomed = stack.Series(doomed_name)
91
92 if doomed.get_protected():
0b4b9499
CL
93 raise CmdException, 'This branch is protected. Delete is not permitted'
94
27ac2b7e 95 out.start('Deleting branch "%s"' % doomed_name)
fe4f6d58
CM
96
97 if __is_current_branch(doomed_name):
98 check_local_changes()
99 check_conflicts()
100 check_head_top_equal()
101
102 if doomed_name != 'master':
103 git.switch_branch('master')
7b1ba1a6 104
ebfd0156 105 doomed.delete(force)
7b1ba1a6
CL
106
107 if doomed_name != 'master':
108 git.delete_branch(doomed_name)
109
27ac2b7e 110 out.done()
7b1ba1a6 111
7b1ba1a6
CL
112def func(parser, options, args):
113
114 if options.create:
115
116 if len(args) == 0 or len(args) > 2:
117 parser.error('incorrect number of arguments')
fe4f6d58
CM
118
119 check_local_changes()
120 check_conflicts()
121 check_head_top_equal()
122
7b1ba1a6 123 tree_id = None
4f5a8c72
YD
124 if len(args) >= 2:
125 try:
126 if git.rev_parse(args[1]) == git.rev_parse('refs/heads/' + args[1]):
a9d090f4 127 # we are for sure referring to a branch
4f5a8c72 128 parentbranch = 'refs/heads/' + args[1]
27ac2b7e 129 out.info('Recording "%s" as parent branch' % parentbranch)
4f5a8c72
YD
130 elif git.rev_parse(args[1]) and re.search('/', args[1]):
131 # FIXME: should the test be more strict ?
132 parentbranch = args[1]
133 else:
134 # Note: this includes refs to StGIT patches
27ac2b7e
KH
135 out.info('Don\'t know how to determine parent branch'
136 ' from "%s"' % args[1])
4f5a8c72
YD
137 parentbranch = None
138 except git.GitException:
27ac2b7e
KH
139 # should use a more specific exception to catch only
140 # non-git refs ?
141 out.info('Don\'t know how to determine parent branch'
142 ' from "%s"' % args[1])
4f5a8c72
YD
143 parentbranch = None
144
2fef9462 145 tree_id = git_id(args[1])
4f5a8c72
YD
146 else:
147 # branch stack off current branch
148 parentbranch = git.get_head_file()
149
150 if parentbranch:
151 parentremote = git.identify_remote(parentbranch)
152 if parentremote:
27ac2b7e
KH
153 out.info('Using remote "%s" to pull parent from'
154 % parentremote)
4f5a8c72 155 else:
27ac2b7e 156 out.info('Recording as a local branch')
4f5a8c72 157 else:
4646e7a3 158 # no known parent branch, can't guess the remote
4f5a8c72
YD
159 parentremote = None
160
161 stack.Series(args[0]).init(create_at = tree_id,
162 parent_remote = parentremote,
163 parent_branch = parentbranch)
7b1ba1a6 164
27ac2b7e 165 out.info('Branch "%s" created' % args[0])
7b1ba1a6
CL
166 return
167
cc3db2b1
CL
168 elif options.clone:
169
170 if len(args) == 0:
d37ff079 171 clone = crt_series.get_name() + \
cc3db2b1
CL
172 time.strftime('-%C%y%m%d-%H%M%S')
173 elif len(args) == 1:
174 clone = args[0]
175 else:
176 parser.error('incorrect number of arguments')
177
178 check_local_changes()
179 check_conflicts()
180 check_head_top_equal()
181
27ac2b7e 182 out.start('Cloning current branch to "%s"' % clone)
cc3db2b1 183 crt_series.clone(clone)
27ac2b7e 184 out.done()
cc3db2b1
CL
185
186 return
187
7b1ba1a6
CL
188 elif options.delete:
189
190 if len(args) != 1:
191 parser.error('incorrect number of arguments')
fe4f6d58 192 __delete_branch(args[0], options.force)
7b1ba1a6
CL
193 return
194
195 elif options.list:
196
197 if len(args) != 0:
198 parser.error('incorrect number of arguments')
199