chiark / gitweb /
Make listing branches more efficient
[stgit] / stgit / commands / branch.py
CommitLineData
7b1ba1a6
CL
1"""Branch command
2"""
3
4__copyright__ = """
5Copyright (C) 2005, Chuck Lever <cel@netapp.com>
6
7This program is free software; you can redistribute it and/or modify
8it under the terms of the GNU General Public License version 2 as
9published by the Free Software Foundation.
10
11This program is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with this program; if not, write to the Free Software
18Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19"""
20
21import sys, os
22from optparse import OptionParser, make_option
23
24from stgit.commands.common import *
25from stgit.utils import *
26from stgit import stack, git
27
28
29help = 'manage development branches'
30usage = """%prog [options] branch-name [commit-id]
31
32Create, list, switch between, rename, or delete development branches
33within a git repository. By default, a single branch called 'master'
34is always created in a new repository. This subcommand allows you to
35manage several patch series in the same repository.
36
37When displaying the branches, the names can be prefixed with
38's' (StGIT managed) or 'p' (protected)."""
39
40options = [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'),
0b4b9499
CL
52 make_option('-p', '--protect',
53 help = 'prevent "stg pull" from modifying this branch',
54 action = 'store_true'),
7b1ba1a6
CL
55 make_option('-r', '--rename',
56 help = 'rename an existing development branch',
0b4b9499
CL
57 action = 'store_true'),
58 make_option('-u', '--unprotect',
59 help = 'allow "stg pull" to modify this branch',
7b1ba1a6
CL
60 action = 'store_true')]
61
62
63def is_current_branch(branch_name):
64 return git.get_head_file() == branch_name
65
66def print_branch(branch_name):
67 initialized = ' '
68 current = ' '
0b4b9499 69 protected = ' '
ebfd0156
CL
70
71 branch = stack.Series(branch_name)
72
7b1ba1a6
CL
73 if os.path.isdir(os.path.join(git.base_dir, 'patches', branch_name)):
74 initialized = 's'
75 if is_current_branch(branch_name):
76 current = '>'
ebfd0156 77 if branch.get_protected():
0b4b9499 78 protected = 'p'
c1fe1f99 79 print '%s %s%s\t%s\t%s' % (current, initialized, protected, branch_name, \
ebfd0156 80 branch.get_description())
7b1ba1a6
CL
81
82def delete_branch(doomed_name, force = False):
ebfd0156
CL
83 doomed = stack.Series(doomed_name)
84
85 if doomed.get_protected():
0b4b9499
CL
86 raise CmdException, 'This branch is protected. Delete is not permitted'
87
7b1ba1a6
CL
88 if is_current_branch(doomed_name) and doomed_name != 'master':
89 git.switch_branch('master')
90
ebfd0156 91 doomed.delete(force)
7b1ba1a6
CL
92
93 if doomed_name != 'master':
94 git.delete_branch(doomed_name)
95
96 print 'Branch "%s" has been deleted.' % doomed_name
97
98def 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
120def 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
0b4b9499
CL
156 elif options.protect:
157
158 if len(args) == 0:
159 branch = git.get_head_file()
160 elif len(args) == 1:
161 branch = args[0]
162 else:
163 parser.error('incorrect number of arguments')
164
165 base = os.path.join(git.base_dir, 'refs', 'bases', branch)
166 if not os.path.isfile(base):
167 raise CmdException, 'Branch "%s" is not controlled by StGit' % branch
168
fa08ec08
CM
169 print 'Protecting branch "%s"...' % branch,
170 sys.stdout.flush()
0b4b9499 171 stack.Series(branch).protect()
fa08ec08
CM
172 print 'done'
173
0b4b9499
CL
174 return
175
7b1ba1a6
CL
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
0b4b9499
CL
183 elif options.unprotect:
184
185 if len(args) == 0:
186 branch = git.get_head_file()
187 elif len(args) == 1:
188 branch = args[0]
189 else:
190 parser.error('incorrect number of arguments')
191
192 base = os.path.join(git.base_dir, 'refs', 'bases', branch)
193 if not os.path.isfile(base):
194 raise CmdException, 'Branch "%s" is not controlled by StGit' % branch
195
fa08ec08
CM
196 print 'Unprotecting branch "%s"...' % branch,
197 sys.stdout.flush()
0b4b9499 198 stack.Series(branch).unprotect()
fa08ec08
CM
199 print 'done'
200
0b4b9499
CL
201 return
202
7b1ba1a6
CL
203 elif len(args) == 1:
204
9756a202
CL
205 if args[0] == git.get_head_file():
206 raise CmdException, 'Branch "%s" is already the current branch' % args[0]
207
7b1ba1a6
CL
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()