Have 'stg branch --create' record parent information.
[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
cc3db2b1 21import sys, os, time
7b1ba1a6
CL
22from optparse import OptionParser, make_option
23
24from stgit.commands.common import *
25from stgit.utils import *
170f576b 26from stgit import stack, git, basedir
7b1ba1a6
CL
27
28
29help = 'manage development branches'
30usage = """%prog [options] branch-name [commit-id]
31
cc3db2b1 32Create, clone, switch between, rename, or delete development branches
7b1ba1a6
CL
33within a git repository. By default, a single branch called 'master'
34is always created in a new repository. This subcommand allows you to
cc3db2b1 35manage several patch series in the same repository via GIT branches.
7b1ba1a6
CL
36
37When displaying the branches, the names can be prefixed with
a8032a85
CL
38's' (StGIT managed) or 'p' (protected).
39
40If not given any options, switch to the named branch."""
7b1ba1a6
CL
41
42options = [make_option('-c', '--create',
43 help = 'create a new development branch',
44 action = 'store_true'),
cc3db2b1
CL
45 make_option('--clone',
46 help = 'clone the contents of the current branch',
47 action = 'store_true'),
bad9dcfc
CL
48 make_option('--convert',
49 help = 'switch between old and new format branches',
50 action = 'store_true'),
7b1ba1a6
CL
51 make_option('--delete',
52 help = 'delete an existing development branch',
53 action = 'store_true'),
54 make_option('--force',
55 help = 'force a delete when the series is not empty',
56 action = 'store_true'),
57 make_option('-l', '--list',
58 help = 'list branches contained in this repository',
59 action = 'store_true'),
0b4b9499
CL
60 make_option('-p', '--protect',
61 help = 'prevent "stg pull" from modifying this branch',
62 action = 'store_true'),
7b1ba1a6
CL
63 make_option('-r', '--rename',
64 help = 'rename an existing development branch',
0b4b9499
CL
65 action = 'store_true'),
66 make_option('-u', '--unprotect',
67 help = 'allow "stg pull" to modify this branch',
7b1ba1a6
CL
68 action = 'store_true')]
69
70
fe4f6d58
CM
71def __is_current_branch(branch_name):
72 return crt_series.get_branch() == branch_name
7b1ba1a6 73
862ba51a 74def __print_branch(branch_name, length):
7b1ba1a6
CL
75 initialized = ' '
76 current = ' '
0b4b9499 77 protected = ' '
ebfd0156
CL
78
79 branch = stack.Series(branch_name)
80
2d00440c 81 if branch.is_initialised():
7b1ba1a6 82 initialized = 's'
fe4f6d58 83 if __is_current_branch(branch_name):
7b1ba1a6 84 current = '>'
ebfd0156 85 if branch.get_protected():
0b4b9499 86 protected = 'p'
862ba51a
CL
87 print current + ' ' + initialized + protected + '\t' + \
88 branch_name.ljust(length) + ' | ' + branch.get_description()
7b1ba1a6 89
fe4f6d58 90def __delete_branch(doomed_name, force = False):
ebfd0156
CL
91 doomed = stack.Series(doomed_name)
92
93 if doomed.get_protected():
0b4b9499
CL
94 raise CmdException, 'This branch is protected. Delete is not permitted'
95
fe4f6d58
CM
96 print 'Deleting branch "%s"...' % doomed_name,
97 sys.stdout.flush()
98
99 if __is_current_branch(doomed_name):
100 check_local_changes()
101 check_conflicts()
102 check_head_top_equal()
103
104 if doomed_name != 'master':
105 git.switch_branch('master')
7b1ba1a6 106
ebfd0156 107 doomed.delete(force)
7b1ba1a6
CL
108
109 if doomed_name != 'master':
110 git.delete_branch(doomed_name)
111
fe4f6d58 112 print 'done'
7b1ba1a6 113
7b1ba1a6
CL
114def func(parser, options, args):
115
116 if options.create:
117
118 if len(args) == 0 or len(args) > 2:
119 parser.error('incorrect number of arguments')
fe4f6d58
CM
120
121 check_local_changes()
122 check_conflicts()
123 check_head_top_equal()
124
7b1ba1a6 125 tree_id = None
4f5a8c72
YD
126 if len(args) >= 2:
127 try:
128 if git.rev_parse(args[1]) == git.rev_parse('refs/heads/' + args[1]):
129 # we are for sure refering to a branch
130 parentbranch = 'refs/heads/' + args[1]
131 print 'Recording "%s" as parent branch.' % parentbranch
132 elif git.rev_parse(args[1]) and re.search('/', args[1]):
133 # FIXME: should the test be more strict ?
134 parentbranch = args[1]
135 else:
136 # Note: this includes refs to StGIT patches
137 print 'Don\'t know how to determine parent branch from "%s".' % args[1]
138 parentbranch = None
139 except git.GitException:
140 # should use a more specific exception to catch only non-git refs ?
141 print 'Don\'t know how to determine parent branch from "%s".' % args[1]
142 parentbranch = None
143
2fef9462 144 tree_id = git_id(args[1])
4f5a8c72
YD
145 else:
146 # branch stack off current branch
147 parentbranch = git.get_head_file()
148
149 if parentbranch:
150 parentremote = git.identify_remote(parentbranch)
151 if parentremote:
152 print 'Using "%s" remote to pull parent from.' % parentremote
153 else:
154 print 'Not identified a remote to pull parent from.'
155 else:
156 parentremote = None
157
158 stack.Series(args[0]).init(create_at = tree_id,
159 parent_remote = parentremote,
160 parent_branch = parentbranch)
7b1ba1a6
CL
161
162 print 'Branch "%s" created.' % args[0]
163 return
164
cc3db2b1
CL
165 elif options.clone:
166
167 if len(args) == 0:
168 clone = crt_series.get_branch() + \
169 time.strftime('-%C%y%m%d-%H%M%S')
170 elif len(args) == 1:
171 clone = args[0]
172 else:
173 parser.error('incorrect number of arguments')
174
175 check_local_changes()
176 check_conflicts()
177 check_head_top_equal()
178
179 print 'Cloning current branch to "%s"...' % clone,
180 sys.stdout.flush()
181 crt_series.clone(clone)
182 print 'done'
183
184 return
185
bad9dcfc
CL
186 elif options.convert:
187
188 if len(args) != 0:
189 parser.error('incorrect number of arguments')
190
191 crt_series.convert()
192 return
193
7b1ba1a6
CL
194 elif options.delete:
195
196 if len(args) != 1:
197 parser.error('incorrect number of arguments')
fe4f6d58 198 __delete_branch(args[0], options.force)
7b1ba1a6
CL
199 return
200
201 elif options.list:
202
203 if len(args) != 0:
204 parser.error('incorrect number of arguments')
205