chiark / gitweb /
56a5fe608634d8af075658f4ffebabbc2698dbaf
[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     if os.path.isdir(os.path.join(git.base_dir, 'patches', branch_name)):
71         initialized = 's'
72     if is_current_branch(branch_name):
73         current = '>'
74     if stack.Series(branch_name).get_protected():
75         protected = 'p'
76     print '%s %s%s\t%s\t%s' % (current, initialized, protected, branch_name, \
77                                stack.Series(branch_name).get_description())
78
79 def delete_branch(doomed_name, force = False):
80     if stack.Series(doomed_name).get_protected():
81         raise CmdException, 'This branch is protected. Delete is not permitted'
82
83     if is_current_branch(doomed_name) and doomed_name != 'master':
84         git.switch_branch('master')
85
86     stack.Series(doomed_name).delete(force)
87
88     if doomed_name != 'master':
89         git.delete_branch(doomed_name)
90
91     print 'Branch "%s" has been deleted.' % doomed_name
92
93 def rename_branch(from_name, to_name):
94     if from_name == 'master':
95         raise CmdException, 'Renaming the master branch is not allowed'
96
97     to_patchdir = os.path.join(git.base_dir, 'patches', to_name)
98     if os.path.isdir(to_patchdir):
99         raise CmdException, '"%s" already exists' % to_patchdir
100     to_base = os.path.join(git.base_dir, 'refs', 'bases', to_name)
101     if os.path.isfile(to_base):
102         raise CmdException, '"%s" already exists' % to_base
103
104     git.rename_branch(from_name, to_name)
105
106     from_patchdir = os.path.join(git.base_dir, 'patches', from_name)
107     if os.path.isdir(from_patchdir):
108         os.rename(from_patchdir, to_patchdir)
109     from_base = os.path.join(git.base_dir, 'refs', 'bases', from_name)
110     if os.path.isfile(from_base):
111         os.rename(from_base, to_base)
112
113     print 'Renamed branch "%s" as "%s".' % (from_name, to_name)
114
115 def func(parser, options, args):
116
117     if options.create:
118
119         if len(args) == 0 or len(args) > 2:
120             parser.error('incorrect number of arguments')
121         tree_id = None
122         if len(args) == 2:
123             tree_id = args[1]
124
125         git.create_branch(args[0], tree_id)
126         stack.Series(args[0]).init()
127
128         print 'Branch "%s" created.' % args[0]
129         return
130
131     elif options.delete:
132
133         if len(args) != 1:
134             parser.error('incorrect number of arguments')
135         delete_branch(args[0], options.force)
136         return
137
138     elif options.list:
139
140         if len(args) != 0:
141             parser.error('incorrect number of arguments')
142
143         branches = os.listdir(os.path.join(git.base_dir, 'refs', 'heads'))
144         branches.sort()
145
146         print 'Available branches:'
147         for i in branches:
148             print_branch(i)
149         return
150
151     elif options.protect:
152
153         if len(args) == 0:
154             branch = git.get_head_file()
155         elif len(args) == 1:
156             branch = args[0]
157         else:
158             parser.error('incorrect number of arguments')
159
160         base = os.path.join(git.base_dir, 'refs', 'bases', branch)
161         if not os.path.isfile(base):
162             raise CmdException, 'Branch "%s" is not controlled by StGit' % branch
163
164         print 'Protecting branch "%s"...' % branch
165         stack.Series(branch).protect()
166         return
167
168     elif options.rename:
169
170         if len(args) != 2:
171             parser.error('incorrect number of arguments')
172         rename_branch(args[0], args[1])
173         return
174
175     elif options.unprotect:
176
177         if len(args) == 0:
178             branch = git.get_head_file()
179         elif len(args) == 1:
180             branch = args[0]
181         else:
182             parser.error('incorrect number of arguments')
183
184         base = os.path.join(git.base_dir, 'refs', 'bases', branch)
185         if not os.path.isfile(base):
186             raise CmdException, 'Branch "%s" is not controlled by StGit' % branch
187
188         print 'Unprotecting branch "%s"...' % branch
189         stack.Series(branch).unprotect()
190         return
191
192     elif len(args) == 1:
193
194         print 'Switching to branch "%s"...' % args[0],
195         sys.stdout.flush()
196
197         git.switch_branch(args[0])
198
199         print 'done'
200         return
201
202     # default action: print the current branch
203     if len(args) != 0:
204         parser.error('incorrect number of arguments')
205
206     print git.get_head_file()