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