Add --binary flag to commands that generate diffs
[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
4ec67741 29help = 'manage patch stacks'
7b1ba1a6
CL
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'),
7b1ba1a6
CL
48 make_option('--delete',
49 help = 'delete an existing development branch',
50 action = 'store_true'),
302600dc
CM
51 make_option('-d', '--description',
52 help = 'set the branch description'),
7b1ba1a6
CL
53 make_option('--force',
54 help = 'force a delete when the series is not empty',
55 action = 'store_true'),
56 make_option('-l', '--list',
57 help = 'list branches contained in this repository',
58 action = 'store_true'),
0b4b9499 59 make_option('-p', '--protect',
f644f510 60 help = 'prevent StGIT from modifying this branch',
0b4b9499 61 action = 'store_true'),
7b1ba1a6
CL
62 make_option('-r', '--rename',
63 help = 'rename an existing development branch',
0b4b9499
CL
64 action = 'store_true'),
65 make_option('-u', '--unprotect',
f644f510 66 help = 'allow StGIT to modify this branch',
7b1ba1a6
CL
67 action = 'store_true')]
68
69
fe4f6d58
CM
70def __is_current_branch(branch_name):
71 return crt_series.get_branch() == branch_name
7b1ba1a6 72
862ba51a 73def __print_branch(branch_name, length):
7b1ba1a6
CL
74 initialized = ' '
75 current = ' '
0b4b9499 76 protected = ' '
ebfd0156
CL
77
78 branch = stack.Series(branch_name)
79
2d00440c 80 if branch.is_initialised():
7b1ba1a6 81 initialized = 's'
fe4f6d58 82 if __is_current_branch(branch_name):
7b1ba1a6 83 current = '>'
ebfd0156 84 if branch.get_protected():
0b4b9499 85 protected = 'p'
862ba51a
CL
86 print current + ' ' + initialized + protected + '\t' + \
87 branch_name.ljust(length) + ' | ' + branch.get_description()
7b1ba1a6 88
fe4f6d58 89def __delete_branch(doomed_name, force = False):
ebfd0156
CL
90 doomed = stack.Series(doomed_name)
91
92 if doomed.get_protected():
0b4b9499
CL
93 raise CmdException, 'This branch is protected. Delete is not permitted'
94
fe4f6d58
CM
95 print 'Deleting branch "%s"...' % doomed_name,
96 sys.stdout.flush()
97
98 if __is_current_branch(doomed_name):
99 check_local_changes()
100 check_conflicts()
101 check_head_top_equal()
102
103 if doomed_name != 'master':
104 git.switch_branch('master')
7b1ba1a6 105
ebfd0156 106 doomed.delete(force)
7b1ba1a6
CL
107
108 if doomed_name != 'master':
109 git.delete_branch(doomed_name)
110
fe4f6d58 111 print 'done'
7b1ba1a6 112
7b1ba1a6
CL
113def func(parser, options, args):
114
115 if options.create:
116
117 if len(args) == 0 or len(args) > 2:
118 parser.error('incorrect number of arguments')
fe4f6d58
CM
119
120 check_local_changes()
121 check_conflicts()
122 check_head_top_equal()
123
7b1ba1a6 124 tree_id = None
4f5a8c72
YD
125 if len(args) >= 2:
126 try:
127 if git.rev_parse(args[1]) == git.rev_parse('refs/heads/' + args[1]):
a9d090f4 128 # we are for sure referring to a branch
4f5a8c72
YD
129 parentbranch = 'refs/heads/' + args[1]
130 print 'Recording "%s" as parent branch.' % parentbranch
131 elif git.rev_parse(args[1]) and re.search('/', args[1]):
132 # FIXME: should the test be more strict ?
133 parentbranch = args[1]
134 else:
135 # Note: this includes refs to StGIT patches
136 print 'Don\'t know how to determine parent branch from "%s".' % args[1]
137 parentbranch = None
138 except git.GitException:
139 # should use a more specific exception to catch only non-git refs ?
140 print 'Don\'t know how to determine parent branch from "%s".' % args[1]
141 parentbranch = None
142
2fef9462 143 tree_id = git_id(args[1])
4f5a8c72
YD
144 else:
145 # branch stack off current branch
146 parentbranch = git.get_head_file()
147
148 if parentbranch:
149 parentremote = git.identify_remote(parentbranch)
150 if parentremote:
151 print 'Using "%s" remote to pull parent from.' % parentremote
152 else:
4646e7a3 153 print 'Recording as a local branch.'
4f5a8c72 154 else:
4646e7a3 155 # no known parent branch, can't guess the remote
4f5a8c72
YD
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
7b1ba1a6
CL
186 elif options.delete:
187
188 if len(args) != 1:
189 parser.error('incorrect number of arguments')
fe4f6d58 190 __delete_branch(args[0], options.force)
7b1ba1a6
CL
191 return
192
193 elif options.list:
194
195 if len(args) != 0:
196 parser.error('incorrect number of arguments')
197