1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44 package org.eclipse.jgit.api;
45
46 import java.io.IOException;
47 import java.text.MessageFormat;
48
49 import org.eclipse.jgit.api.errors.GitAPIException;
50 import org.eclipse.jgit.api.errors.InvalidRefNameException;
51 import org.eclipse.jgit.api.errors.JGitInternalException;
52 import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
53 import org.eclipse.jgit.api.errors.RefNotFoundException;
54 import org.eclipse.jgit.errors.AmbiguousObjectException;
55 import org.eclipse.jgit.internal.JGitText;
56 import org.eclipse.jgit.lib.ConfigConstants;
57 import org.eclipse.jgit.lib.Constants;
58 import org.eclipse.jgit.lib.ObjectId;
59 import org.eclipse.jgit.lib.Ref;
60 import org.eclipse.jgit.lib.RefUpdate;
61 import org.eclipse.jgit.lib.RefUpdate.Result;
62 import org.eclipse.jgit.lib.Repository;
63 import org.eclipse.jgit.lib.StoredConfig;
64 import org.eclipse.jgit.revwalk.RevCommit;
65 import org.eclipse.jgit.revwalk.RevWalk;
66
67
68
69
70
71
72
73
74 public class CreateBranchCommand extends GitCommand<Ref> {
75 private String name;
76
77 private boolean force = false;
78
79 private SetupUpstreamMode upstreamMode;
80
81 private String startPoint = Constants.HEAD;
82
83 private RevCommit startCommit;
84
85
86
87
88
89
90 public enum SetupUpstreamMode {
91
92
93
94 TRACK,
95
96
97
98 NOTRACK,
99
100
101
102 SET_UPSTREAM;
103 }
104
105
106
107
108 protected CreateBranchCommand(Repository repo) {
109 super(repo);
110 }
111
112
113
114
115
116
117
118
119
120
121
122
123 public Ref call() throws GitAPIException, RefAlreadyExistsException,
124 RefNotFoundException, InvalidRefNameException {
125 checkCallable();
126 processOptions();
127 try (RevWalk revWalk = new RevWalk(repo)) {
128 Ref refToCheck = repo.getRef(name);
129 boolean exists = refToCheck != null
130 && refToCheck.getName().startsWith(Constants.R_HEADS);
131 if (!force && exists)
132 throw new RefAlreadyExistsException(MessageFormat.format(
133 JGitText.get().refAlreadyExists1, name));
134
135 ObjectId startAt = getStartPointObjectId();
136 String startPointFullName = null;
137 if (startPoint != null) {
138 Ref baseRef = repo.getRef(startPoint);
139 if (baseRef != null)
140 startPointFullName = baseRef.getName();
141 }
142
143
144
145 String refLogMessage;
146 String baseBranch = "";
147 if (startPointFullName == null) {
148 String baseCommit;
149 if (startCommit != null)
150 baseCommit = startCommit.getShortMessage();
151 else {
152 RevCommit commit = revWalk.parseCommit(repo
153 .resolve(getStartPointOrHead()));
154 baseCommit = commit.getShortMessage();
155 }
156 if (exists)
157 refLogMessage = "branch: Reset start-point to commit "
158 + baseCommit;
159 else
160 refLogMessage = "branch: Created from commit " + baseCommit;
161
162 } else if (startPointFullName.startsWith(Constants.R_HEADS)
163 || startPointFullName.startsWith(Constants.R_REMOTES)) {
164 baseBranch = startPointFullName;
165 if (exists)
166 refLogMessage = "branch: Reset start-point to branch "
167 + startPointFullName;
168 else
169 refLogMessage = "branch: Created from branch " + baseBranch;
170 } else {
171 startAt = revWalk.peel(revWalk.parseAny(startAt));
172 if (exists)
173 refLogMessage = "branch: Reset start-point to tag "
174 + startPointFullName;
175 else
176 refLogMessage = "branch: Created from tag "
177 + startPointFullName;
178 }
179
180 RefUpdate updateRef = repo.updateRef(Constants.R_HEADS + name);
181 updateRef.setNewObjectId(startAt);
182 updateRef.setRefLogMessage(refLogMessage, false);
183 Result updateResult;
184 if (exists && force)
185 updateResult = updateRef.forceUpdate();
186 else
187 updateResult = updateRef.update();
188
189 setCallable(false);
190
191 boolean ok = false;
192 switch (updateResult) {
193 case NEW:
194 ok = !exists;
195 break;
196 case NO_CHANGE:
197 case FAST_FORWARD:
198 case FORCED:
199 ok = exists;
200 break;
201 default:
202 break;
203 }
204
205 if (!ok)
206 throw new JGitInternalException(MessageFormat.format(JGitText
207 .get().createBranchUnexpectedResult, updateResult
208 .name()));
209
210 Ref result = repo.getRef(name);
211 if (result == null)
212 throw new JGitInternalException(
213 JGitText.get().createBranchFailedUnknownReason);
214
215 if (baseBranch.length() == 0) {
216 return result;
217 }
218
219
220
221
222 boolean doConfigure;
223 if (upstreamMode == SetupUpstreamMode.SET_UPSTREAM
224 || upstreamMode == SetupUpstreamMode.TRACK)
225
226 doConfigure = true;
227 else if (upstreamMode == SetupUpstreamMode.NOTRACK)
228
229 doConfigure = false;
230 else {
231
232 String autosetupflag = repo.getConfig().getString(
233 ConfigConstants.CONFIG_BRANCH_SECTION, null,
234 ConfigConstants.CONFIG_KEY_AUTOSETUPMERGE);
235 if ("false".equals(autosetupflag)) {
236 doConfigure = false;
237 } else if ("always".equals(autosetupflag)) {
238 doConfigure = true;
239 } else {
240
241
242 doConfigure = baseBranch.startsWith(Constants.R_REMOTES);
243 }
244 }
245
246 if (doConfigure) {
247 StoredConfig config = repo.getConfig();
248
249 String remoteName = repo.getRemoteName(baseBranch);
250 if (remoteName != null) {
251 String branchName = repo
252 .shortenRemoteBranchName(baseBranch);
253 config
254 .setString(ConfigConstants.CONFIG_BRANCH_SECTION,
255 name, ConfigConstants.CONFIG_KEY_REMOTE,
256 remoteName);
257 config.setString(ConfigConstants.CONFIG_BRANCH_SECTION,
258 name, ConfigConstants.CONFIG_KEY_MERGE,
259 Constants.R_HEADS + branchName);
260 } else {
261
262 config.setString(ConfigConstants.CONFIG_BRANCH_SECTION,
263 name, ConfigConstants.CONFIG_KEY_REMOTE, ".");
264 config.setString(ConfigConstants.CONFIG_BRANCH_SECTION,
265 name, ConfigConstants.CONFIG_KEY_MERGE, baseBranch);
266 }
267 config.save();
268 }
269 return result;
270 } catch (IOException ioe) {
271 throw new JGitInternalException(ioe.getMessage(), ioe);
272 }
273 }
274
275 private ObjectId getStartPointObjectId() throws AmbiguousObjectException,
276 RefNotFoundException, IOException {
277 if (startCommit != null)
278 return startCommit.getId();
279 String startPointOrHead = getStartPointOrHead();
280 ObjectId result = repo.resolve(startPointOrHead);
281 if (result == null)
282 throw new RefNotFoundException(MessageFormat.format(
283 JGitText.get().refNotResolved, startPointOrHead));
284 return result;
285 }
286
287 private String getStartPointOrHead() {
288 return startPoint != null ? startPoint : Constants.HEAD;
289 }
290
291 private void processOptions() throws InvalidRefNameException {
292 if (name == null
293 || !Repository.isValidRefName(Constants.R_HEADS + name))
294 throw new InvalidRefNameException(MessageFormat.format(JGitText
295 .get().branchNameInvalid, name == null ? "<null>" : name));
296 }
297
298
299
300
301
302
303 public CreateBranchCommand setName(String name) {
304 checkCallable();
305 this.name = name;
306 return this;
307 }
308
309
310
311
312
313
314
315
316
317 public CreateBranchCommand setForce(boolean force) {
318 checkCallable();
319 this.force = force;
320 return this;
321 }
322
323
324
325
326
327
328
329 public CreateBranchCommand setStartPoint(String startPoint) {
330 checkCallable();
331 this.startPoint = startPoint;
332 this.startCommit = null;
333 return this;
334 }
335
336
337
338
339
340
341
342 public CreateBranchCommand setStartPoint(RevCommit startPoint) {
343 checkCallable();
344 this.startCommit = startPoint;
345 this.startPoint = null;
346 return this;
347 }
348
349
350
351
352
353
354
355 public CreateBranchCommand setUpstreamMode(SetupUpstreamMode mode) {
356 checkCallable();
357 this.upstreamMode = mode;
358 return this;
359 }
360 }