Add a stack method for determining whether a branch is initialised
[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 git.get_head_file() == 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 if is_current_branch(doomed_name) and doomed_name != 'master':
89 git.switch_branch('master')
90
91 doomed.delete(force)
92
93 if doomed_name != 'master':
94 git.delete_branch(doomed_name)
95
96 print 'Branch "%s" has been deleted.' % doomed_name
97
98 def rename_branch(from_name, to_name):
99 if from_name == 'master':
100 raise CmdException, 'Renaming the master branch is not allowed'
101
102 to_patchdir = os.path.join(git.base_dir, 'patches', to_name)
103 if os.path.isdir(to_patchdir):
104 raise CmdException, '"%s" already exists' % to_patchdir
105 to_base = os.path.join(git.base_dir, 'refs', 'bases', to_name)
106 if os.path.isfile(to_base):
107 raise CmdException, '"%s" already exists' % to_base
108
109 git.rename_branch(from_name, to_name)
110
111 from_patchdir = os.path.join(git.base_dir, 'patches', from_name)
112 if os.path.isdir(from_patchdir):
113 os.rename(from_patchdir, to_patchdir)
114 from_base = os.path.join(git.base_dir, 'refs', 'bases', from_name)
115 if os.path.isfile(from_base):
116 os.rename(from_base, to_base)
117
118 print 'Renamed branch "%s" as "%s".' % (from_name, to_name)
119
120 def func(parser, options, args):
121
122 if options.create:
123
124 if len(args) == 0 or len(args) > 2:
125 parser.error('incorrect number of arguments')
126 tree_id = None
127 if len(args) == 2:
128 tree_id = args[1]
129
130 git.create_branch(args[0], tree_id)
131 stack.Series(args[0]).init()
132
133 print 'Branch "%s" created.' % args[0]
134 return
135
136 elif options.delete:
137
138 if len(args) != 1:
139 parser.error('incorrect number of arguments')
140 delete_branch(args[0], options.force)
141 return
142
143 elif options.list:
144
145 if len(args) != 0:
146 parser.error('incorrect number of arguments')
147
148 branches = os.listdir(os.path.join(git.base_dir, 'refs', 'heads'))
149 branches.sort()
150
151 print 'Available branches:'
152 for i in branches:
153 print_branch(i)
154 return
155
156 elif options.protect:
157
158 if len(args) == 0:
159 branch_name = git.get_head_file()
160 elif len(args) == 1:
161 branch_name = args[0]
162 else:
163 parser.error('incorrect number of arguments')
164 branch = stack.Series(branch_name)
165
166 if not branch.is_initialised():
167 raise CmdException, 'Branch "%s" is not controlled by StGit' % branch_name
168
169 print 'Protecting branch "%s"...' % branch_name,
170 sys.stdout.flush()
171 branch.protect()
172 print 'done'
173
174 return
175
176 elif options.rename:
177
178 if len(args) != 2:
179 parser.error('incorrect number of arguments')
180 rename_branch(args[0], args[1])
181 return
182
183 elif options.unprotect:
184
185 if len(args) == 0:
186 branch_name = git.get_head_file()
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' % 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 args[0] == git.get_head_file():
206 raise CmdException, 'Branch "%s" is already the current branch' % args[0]
207
208 print 'Switching to branch "%s"...' % args[0],
209 sys.stdout.flush()
210
211 git.switch_branch(args[0])
212
213 print 'done'
214 return
215
216 # default action: print the current branch
217 if len(args) != 0:
218 parser.error('incorrect number of arguments')
219
220 print git.get_head_file()