Different fixes for the branch command
[stgit] / stgit / commands / branch.py
1 """Branch command
2 """
3
4 __copyright__ = """
5 Copyright (C) 2005, Chuck Lever <cel@netapp.com>
6
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.
10
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.
15
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
19 """
20
21 import sys, os
22 from optparse import OptionParser, make_option
23
24 from stgit.commands.common import *
25 from stgit.utils import *
26 from stgit import stack, git
27
28
29 help = 'manage development branches'
30 usage = """%prog [options] branch-name [commit-id]
31
32 Create, list, 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.
36
37 When displaying the branches, the names can be prefixed with
38 's' (StGIT managed) or 'p' (protected)."""
39
40 options = [make_option('-c', '--create',
41 help = 'create a new development branch',
42 action = 'store_true'),
43 make_option('--delete',
44 help = 'delete an existing development branch',
45 action = 'store_true'),
46 make_option('--force',
47 help = 'force a delete when the series is not empty',
48 action = 'store_true'),
49 make_option('-l', '--list',
50 help = 'list branches contained in this repository',
51 action = 'store_true'),
52 make_option('-p', '--protect',
53 help = 'prevent "stg pull" from modifying this branch',
54 action = 'store_true'),
55 make_option('-r', '--rename',
56 help = 'rename an existing development branch',
57 action = 'store_true'),
58 make_option('-u', '--unprotect',
59 help = 'allow "stg pull" to modify this branch',
60 action = 'store_true')]
61
62
63 def __is_current_branch(branch_name):
64 return crt_series.get_branch() == branch_name
65
66 def __print_branch(branch_name):
67 initialized = ' '
68 current = ' '
69 protected = ' '
70
71 branch = stack.Series(branch_name)
72
73 if branch.is_initialised():
74 initialized = 's'
75 if __is_current_branch(branch_name):
76 current = '>'
77 if branch.get_protected():
78 protected = 'p'
79 print '%s %s%s\t%s\t%s' % (current, initialized, protected, branch_name, \
80 branch.get_description())
81
82 def __delete_branch(doomed_name, force = False):
83 doomed = stack.Series(doomed_name)
84
85 if doomed.get_protected():
86 raise CmdException, 'This branch is protected. Delete is not permitted'
87
88 print 'Deleting branch "%s"...' % doomed_name,
89 sys.stdout.flush()
90
91 if __is_current_branch(doomed_name):
92 check_local_changes()
93 check_conflicts()
94 check_head_top_equal()
95
96 if doomed_name != 'master':
97 git.switch_branch('master')
98
99 doomed.delete(force)
100
101 if doomed_name != 'master':
102 git.delete_branch(doomed_name)
103
104 print 'done'
105
106 def func(parser, options, args):
107
108 if options.create:
109
110 if len(args) == 0 or len(args) > 2:
111 parser.error('incorrect number of arguments')
112
113 check_local_changes()
114 check_conflicts()
115 check_head_top_equal()
116
117 tree_id = None
118 if len(args) == 2:
119 tree_id = args[1]
120
121 git.create_branch(args[0], tree_id)
122 stack.Series(args[0]).init()
123
124 print 'Branch "%s" created.' % args[0]
125 return
126
127 elif options.delete:
128
129 if len(args) != 1:
130 parser.error('incorrect number of arguments')
131 __delete_branch(args[0], options.force)
132 return
133
134 elif options.list:
135
136 if len(args) != 0:
137 parser.error('incorrect number of arguments')
138
139 branches = os.listdir(os.path.join(git.base_dir, 'refs', 'heads'))
140 branches.sort()
141
142 print 'Available branches:'
143 for i in branches:
144 __print_branch(i)
145 return
146
147 elif options.protect:
148
149 if len(args) == 0:
150 branch_name = git.get_head_file()
151 elif len(args) == 1:
152 branch_name = args[0]
153 else:
154 parser.error('incorrect number of arguments')
155 branch = stack.Series(branch_name)
156
157 if not branch.is_initialised():
158 raise CmdException, 'Branch "%s" is not controlled by StGIT' \
159 % branch_name
160
161 print 'Protecting branch "%s"...' % branch_name,
162 sys.stdout.flush()
163 branch.protect()
164 print 'done'
165
166 return
167
168 elif options.rename:
169
170 if len(args) != 2:
171 parser.error('incorrect number of arguments')
172
173 if __is_current_branch(args[0]):
174 raise CmdException, 'Renaming the current branch is not supported'
175
176 stack.Series(args[0]).rename(args[1])
177
178 print 'Renamed branch "%s" as "%s".' % (args[0], args[1])
179
180 return
181
182 elif options.unprotect:
183
184 if len(args) == 0:
185 branch_name = git.get_head_file()
186 elif len(args) == 1:
187 branch_name = args[0]
188 else:
189 parser.error('incorrect number of arguments')
190 branch = stack.Series(branch_name)
191
192 if not branch.is_initialised():
193 raise CmdException, 'Branch "%s" is not controlled by StGIT' \
194 % branch_name
195
196 print 'Unprotecting branch "%s"...' % branch_name,
197 sys.stdout.flush()
198 branch.unprotect()
199 print 'done'
200
201 return
202
203 elif len(args) == 1:
204
205 if __is_current_branch(args[0]):
206 raise CmdException, 'Branch "%s" is already the current branch' \
207 % args[0]
208
209 check_local_changes()
210 check_conflicts()
211 check_head_top_equal()
212
213 print 'Switching to branch "%s"...' % args[0],
214 sys.stdout.flush()
215
216 git.switch_branch(args[0])
217
218 print 'done'
219 return
220
221 # default action: print the current branch
222 if len(args) != 0:
223 parser.error('incorrect number of arguments')
224
225 print git.get_head_file()