chiark / gitweb /
ccf1f6baefafb0585a0ebfe0f1f8822b249f0dd6
[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, length):
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 current + ' ' + initialized + protected + '\t' + \
80           branch_name.ljust(length) + '  | ' + 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.get_base_dir(), 'refs', 'heads'))
140         branches.sort()
141         max_len = max([len(i) for i in branches])
142
143         print 'Available branches:'
144         for i in branches:
145             __print_branch(i, max_len)
146         return
147
148     elif options.protect:
149
150         if len(args) == 0:
151             branch_name = crt_series.get_branch()
152         elif len(args) == 1:
153             branch_name = args[0]
154         else:
155             parser.error('incorrect number of arguments')
156         branch = stack.Series(branch_name)
157
158         if not branch.is_initialised():
159             raise CmdException, 'Branch "%s" is not controlled by StGIT' \
160                   % branch_name
161
162         print 'Protecting branch "%s"...' % branch_name,
163         sys.stdout.flush()
164         branch.protect()
165         print 'done'
166
167         return
168
169     elif options.rename:
170
171         if len(args) != 2:
172             parser.error('incorrect number of arguments')
173
174         if __is_current_branch(args[0]):
175             raise CmdException, 'Renaming the current branch is not supported'
176
177         stack.Series(args[0]).rename(args[1])
178
179         print 'Renamed branch "%s" as "%s".' % (args[0], args[1])
180
181         return
182
183     elif options.unprotect:
184
185         if len(args) == 0:
186             branch_name = crt_series.get_branch()
187         elif len(args) == 1:
188             branch_name = args[0]
189         else:
190             parser.error('incorrect number of arguments')
191         branch = stack.Series(branch_name)
192
193         if not branch.is_initialised():
194             raise CmdException, 'Branch "%s" is not controlled by StGIT' \
195                   % branch_name
196
197         print 'Unprotecting branch "%s"...' % branch_name,
198         sys.stdout.flush()
199         branch.unprotect()
200         print 'done'
201
202         return
203
204     elif len(args) == 1:
205
206         if __is_current_branch(args[0]):
207             raise CmdException, 'Branch "%s" is already the current branch' \
208                   % args[0]
209
210         check_local_changes()
211         check_conflicts()
212         check_head_top_equal()
213
214         print 'Switching to branch "%s"...' % args[0],
215         sys.stdout.flush()
216
217         git.switch_branch(args[0])
218
219         print 'done'
220         return
221
222     # default action: print the current branch
223     if len(args) != 0:
224         parser.error('incorrect number of arguments')
225
226     print crt_series.get_branch()