chiark / gitweb /
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()