Allow patch refreshing for some files only
[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, time
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, 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.
36
37 When displaying the branches, the names can be prefixed with
38 's' (StGIT managed) or 'p' (protected).
39
40 If not given any options, switch to the named branch."""
41
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('--delete',
49 help = 'delete an existing development branch',
50 action = 'store_true'),
51 make_option('--force',
52 help = 'force a delete when the series is not empty',
53 action = 'store_true'),
54 make_option('-l', '--list',
55 help = 'list branches contained in this repository',
56 action = 'store_true'),
57 make_option('-p', '--protect',
58 help = 'prevent "stg pull" from modifying this branch',
59 action = 'store_true'),
60 make_option('-r', '--rename',
61 help = 'rename an existing development branch',
62 action = 'store_true'),
63 make_option('-u', '--unprotect',
64 help = 'allow "stg pull" to modify this branch',
65 action = 'store_true')]
66
67
68 def __is_current_branch(branch_name):
69 return crt_series.get_branch() == branch_name
70
71 def __print_branch(branch_name, length):
72 initialized = ' '
73 current = ' '
74 protected = ' '
75
76 branch = stack.Series(branch_name)
77
78 if branch.is_initialised():
79 initialized = 's'
80 if __is_current_branch(branch_name):
81 current = '>'
82 if branch.get_protected():
83 protected = 'p'
84 print current + ' ' + initialized + protected + '\t' + \
85 branch_name.ljust(length) + ' | ' + branch.get_description()
86
87 def __delete_branch(doomed_name, force = False):
88 doomed = stack.Series(doomed_name)
89
90 if doomed.get_protected():
91 raise CmdException, 'This branch is protected. Delete is not permitted'
92
93 print 'Deleting branch "%s"...' % doomed_name,
94 sys.stdout.flush()
95
96 if __is_current_branch(doomed_name):
97 check_local_changes()
98 check_conflicts()
99 check_head_top_equal()
100
101 if doomed_name != 'master':
102 git.switch_branch('master')
103
104 doomed.delete(force)
105
106 if doomed_name != 'master':
107 git.delete_branch(doomed_name)
108
109 print 'done'
110
111 def func(parser, options, args):
112
113 if options.create:
114
115 if len(args) == 0 or len(args) > 2:
116 parser.error('incorrect number of arguments')
117
118 check_local_changes()
119 check_conflicts()
120 check_head_top_equal()
121
122 tree_id = None
123 if len(args) == 2:
124 tree_id = args[1]
125
126 git.create_branch(args[0], tree_id)
127 stack.Series(args[0]).init()
128
129 print 'Branch "%s" created.' % args[0]
130 return
131
132 elif options.clone:
133
134 if len(args) == 0:
135 clone = crt_series.get_branch() + \
136 time.strftime('-%C%y%m%d-%H%M%S')
137 elif len(args) == 1:
138 clone = args[0]
139 else:
140 parser.error('incorrect number of arguments')
141
142 check_local_changes()
143 check_conflicts()
144 check_head_top_equal()
145
146 print 'Cloning current branch to "%s"...' % clone,
147 sys.stdout.flush()
148 crt_series.clone(clone)
149 print 'done'
150
151 return
152
153 elif options.delete:
154
155 if len(args) != 1:
156 parser.error('incorrect number of arguments')
157 __delete_branch(args[0], options.force)
158 return
159
160 elif options.list:
161
162 if len(args) != 0:
163 parser.error('incorrect number of arguments')
164
165 branches = os.listdir(os.path.join(git.get_base_dir(), 'refs', 'heads'))
166 branches.sort()
167 max_len = max([len(i) for i in branches])
168
169 print 'Available branches:'
170 for i in branches:
171 __print_branch(i, max_len)
172 return
173
174 elif options.protect:
175
176 if len(args) == 0:
177 branch_name = crt_series.get_branch()
178 elif len(args) == 1:
179 branch_name = args[0]
180 else:
181 parser.error('incorrect number of arguments')
182 branch = stack.Series(branch_name)
183
184 if not branch.is_initialised():
185 raise CmdException, 'Branch "%s" is not controlled by StGIT' \
186 % branch_name
187
188 print 'Protecting branch "%s"...' % branch_name,
189 sys.stdout.flush()
190 branch.protect()
191 print 'done'
192
193 return
194
195 elif options.rename:
196
197 if len(args) != 2:
198 parser.error('incorrect number of arguments')
199
200 if __is_current_branch(args[0]):
201 raise CmdException, 'Renaming the current branch is not supported'
202
203 stack.Series(args[0]).rename(args[1])
204
205 print 'Renamed branch "%s" as "%s".' % (args[0], args[1])
206
207 return
208
209 elif options.unprotect:
210
211 if len(args) == 0:
212 branch_name = crt_series.get_branch()
213 elif len(args) == 1:
214 branch_name = args[0]
215 else:
216 parser.error('incorrect number of arguments')
217 branch = stack.Series(branch_name)
218
219 if not branch.is_initialised():
220 raise CmdException, 'Branch "%s" is not controlled by StGIT' \
221 % branch_name
222
223 print 'Unprotecting branch "%s"...' % branch_name,
224 sys.stdout.flush()
225 branch.unprotect()
226 print 'done'
227
228 return
229
230 elif len(args) == 1:
231
232 if __is_current_branch(args[0]):
233 raise CmdException, 'Branch "%s" is already the current branch' \
234 % args[0]
235
236 check_local_changes()
237 check_conflicts()
238 check_head_top_equal()
239
240 print 'Switching to branch "%s"...' % args[0],
241 sys.stdout.flush()
242
243 git.switch_branch(args[0])
244
245 print 'done'
246 return
247
248 # default action: print the current branch
249 if len(args) != 0:
250 parser.error('incorrect number of arguments')
251
252 print crt_series.get_branch()