1
2
3
4
5
6
7
8
9
10 package org.eclipse.jgit.api;
11
12 import static org.junit.Assert.assertEquals;
13 import static org.junit.Assert.assertFalse;
14 import static org.junit.Assert.assertNull;
15 import static org.junit.Assert.fail;
16
17 import java.util.List;
18
19 import org.eclipse.jgit.api.CreateBranchCommand.SetupUpstreamMode;
20 import org.eclipse.jgit.api.ListBranchCommand.ListMode;
21 import org.eclipse.jgit.api.errors.CannotDeleteCurrentBranchException;
22 import org.eclipse.jgit.api.errors.DetachedHeadException;
23 import org.eclipse.jgit.api.errors.GitAPIException;
24 import org.eclipse.jgit.api.errors.InvalidRefNameException;
25 import org.eclipse.jgit.api.errors.JGitInternalException;
26 import org.eclipse.jgit.api.errors.NotMergedException;
27 import org.eclipse.jgit.api.errors.RefAlreadyExistsException;
28 import org.eclipse.jgit.api.errors.RefNotFoundException;
29 import org.eclipse.jgit.junit.RepositoryTestCase;
30 import org.eclipse.jgit.lib.Constants;
31 import org.eclipse.jgit.lib.ObjectId;
32 import org.eclipse.jgit.lib.Ref;
33 import org.eclipse.jgit.lib.RefUpdate;
34 import org.eclipse.jgit.lib.Repository;
35 import org.eclipse.jgit.lib.StoredConfig;
36 import org.eclipse.jgit.revwalk.RevCommit;
37 import org.eclipse.jgit.transport.FetchResult;
38 import org.eclipse.jgit.transport.RefSpec;
39 import org.eclipse.jgit.transport.RemoteConfig;
40 import org.eclipse.jgit.transport.URIish;
41 import org.junit.Before;
42 import org.junit.Test;
43
44 public class BranchCommandTest extends RepositoryTestCase {
45 private Git git;
46
47 RevCommit initialCommit;
48
49 RevCommit secondCommit;
50
51 @Override
52 @Before
53 public void setUp() throws Exception {
54 super.setUp();
55 git = new Git(db);
56
57 git.commit().setMessage("initial commit").call();
58
59 writeTrashFile("Test.txt", "Hello world");
60 git.add().addFilepattern("Test.txt").call();
61 initialCommit = git.commit().setMessage("Initial commit").call();
62 writeTrashFile("Test.txt", "Some change");
63 git.add().addFilepattern("Test.txt").call();
64 secondCommit = git.commit().setMessage("Second commit").call();
65
66 RefUpdate rup = db.updateRef("refs/heads/master");
67 rup.setNewObjectId(initialCommit.getId());
68 rup.setForceUpdate(true);
69 rup.update();
70 }
71
72 private Git setUpRepoWithRemote() throws Exception {
73 Repository remoteRepository = createWorkRepository();
74 addRepoToClose(remoteRepository);
75 try (Git remoteGit = new Git(remoteRepository)) {
76
77 writeTrashFile("Test.txt", "Hello world");
78 remoteGit.add().addFilepattern("Test.txt").call();
79 initialCommit = remoteGit.commit().setMessage("Initial commit").call();
80 writeTrashFile("Test.txt", "Some change");
81 remoteGit.add().addFilepattern("Test.txt").call();
82 secondCommit = remoteGit.commit().setMessage("Second commit").call();
83
84 RefUpdate rup = remoteRepository.updateRef("refs/heads/master");
85 rup.setNewObjectId(initialCommit.getId());
86 rup.forceUpdate();
87
88 Repository localRepository = createWorkRepository();
89 addRepoToClose(localRepository);
90 Git localGit = new Git(localRepository);
91 StoredConfig config = localRepository.getConfig();
92 RemoteConfig rc = new RemoteConfig(config, "origin");
93 rc.addURI(new URIish(remoteRepository.getDirectory().getAbsolutePath()));
94 rc.addFetchRefSpec(new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
95 rc.update(config);
96 config.save();
97 FetchResult res = localGit.fetch().setRemote("origin").call();
98 assertFalse(res.getTrackingRefUpdates().isEmpty());
99 rup = localRepository.updateRef("refs/heads/master");
100 rup.setNewObjectId(initialCommit.getId());
101 rup.forceUpdate();
102 rup = localRepository.updateRef(Constants.HEAD);
103 rup.link("refs/heads/master");
104 rup.setNewObjectId(initialCommit.getId());
105 rup.update();
106 return localGit;
107 }
108 }
109
110 @Test
111 public void testCreateAndList() throws Exception {
112 int localBefore;
113 int remoteBefore;
114 int allBefore;
115
116
117 try {
118 git.branchCreate().setName("In va lid").call();
119 fail("Create branch with invalid ref name should fail");
120 } catch (InvalidRefNameException e) {
121
122 }
123
124 try {
125 git.branchCreate().setName("master").call();
126 fail("Create branch with existing ref name should fail");
127 } catch (RefAlreadyExistsException e) {
128
129 }
130
131 localBefore = git.branchList().call().size();
132 remoteBefore = git.branchList().setListMode(ListMode.REMOTE).call()
133 .size();
134 allBefore = git.branchList().setListMode(ListMode.ALL).call().size();
135
136 assertEquals(localBefore + remoteBefore, allBefore);
137 Ref newBranch = createBranch(git, "NewForTestList", false, "master",
138 null);
139 assertEquals("refs/heads/NewForTestList", newBranch.getName());
140
141 assertEquals(1, git.branchList().call().size() - localBefore);
142 assertEquals(0, git.branchList().setListMode(ListMode.REMOTE).call()
143 .size()
144 - remoteBefore);
145 assertEquals(1, git.branchList().setListMode(ListMode.ALL).call()
146 .size()
147 - allBefore);
148
149 newBranch = createBranch(git,
150 "refs/remotes/origin/NewRemoteForTestList", false, "master",
151 null);
152 assertEquals("refs/heads/refs/remotes/origin/NewRemoteForTestList",
153 newBranch.getName());
154 assertEquals(2, git.branchList().call().size() - localBefore);
155 assertEquals(0, git.branchList().setListMode(ListMode.REMOTE).call()
156 .size()
157 - remoteBefore);
158 assertEquals(2, git.branchList().setListMode(ListMode.ALL).call()
159 .size()
160 - allBefore);
161 }
162
163 @Test(expected = InvalidRefNameException.class)
164 public void testInvalidBranchHEAD() throws Exception {
165 git.branchCreate().setName("HEAD").call();
166 fail("Create branch with invalid ref name should fail");
167 }
168
169 @Test(expected = InvalidRefNameException.class)
170 public void testInvalidBranchDash() throws Exception {
171 git.branchCreate().setName("-x").call();
172 fail("Create branch with invalid ref name should fail");
173 }
174
175 @Test
176 public void testListAllBranchesShouldNotDie() throws Exception {
177 setUpRepoWithRemote().branchList().setListMode(ListMode.ALL).call();
178 }
179
180 @Test
181 public void testListBranchesWithContains() throws Exception {
182 git.branchCreate().setName("foo").setStartPoint(secondCommit).call();
183
184 List<Ref> refs = git.branchList().call();
185 assertEquals(2, refs.size());
186
187 List<Ref> refsContainingSecond = git.branchList()
188 .setContains(secondCommit.name()).call();
189 assertEquals(1, refsContainingSecond.size());
190
191 assertEquals("refs/heads/foo", refsContainingSecond.get(0).getName());
192 }
193
194 @Test
195 public void testCreateFromCommit() throws Exception {
196 Ref branch = git.branchCreate().setName("FromInitial").setStartPoint(
197 initialCommit).call();
198 assertEquals(initialCommit.getId(), branch.getObjectId());
199 branch = git.branchCreate().setName("FromInitial2").setStartPoint(
200 initialCommit.getId().name()).call();
201 assertEquals(initialCommit.getId(), branch.getObjectId());
202 try {
203 git.branchCreate().setName("FromInitial").setStartPoint(
204 secondCommit).call();
205 } catch (RefAlreadyExistsException e) {
206
207 }
208 branch = git.branchCreate().setName("FromInitial").setStartPoint(
209 secondCommit).setForce(true).call();
210 assertEquals(secondCommit.getId(), branch.getObjectId());
211 }
212
213 @Test
214 public void testCreateForce() throws Exception {
215
216 Ref newBranch = createBranch(git, "NewForce", false, secondCommit
217 .getId().name(), null);
218 assertEquals(newBranch.getTarget().getObjectId(), secondCommit.getId());
219 try {
220 newBranch = createBranch(git, "NewForce", false, initialCommit
221 .getId().name(), null);
222 fail("Should have failed");
223 } catch (RefAlreadyExistsException e) {
224
225 }
226 newBranch = createBranch(git, "NewForce", true, initialCommit.getId()
227 .name(), null);
228 assertEquals(newBranch.getTarget().getObjectId(), initialCommit.getId());
229 git.branchDelete().setBranchNames("NewForce").call();
230
231
232 git.branchCreate().setName("NewForce").setStartPoint("master").call();
233 assertEquals(newBranch.getTarget().getObjectId(), initialCommit.getId());
234 try {
235 git.branchCreate().setName("NewForce").setStartPoint("master")
236 .call();
237 fail("Should have failed");
238 } catch (RefAlreadyExistsException e) {
239
240 }
241 git.branchCreate().setName("NewForce").setStartPoint("master")
242 .setForce(true).call();
243 assertEquals(newBranch.getTarget().getObjectId(), initialCommit.getId());
244 }
245
246 @Test
247 public void testCreateFromLightweightTag() throws Exception {
248 RefUpdate rup = db.updateRef("refs/tags/V10");
249 rup.setNewObjectId(initialCommit);
250 rup.setExpectedOldObjectId(ObjectId.zeroId());
251 rup.update();
252
253 Ref branch = git.branchCreate().setName("FromLightweightTag")
254 .setStartPoint("refs/tags/V10").call();
255 assertEquals(initialCommit.getId(), branch.getObjectId());
256
257 }
258
259 @Test
260 public void testCreateFromAnnotatetdTag() throws Exception {
261 Ref tagRef = git.tag().setName("V10").setObjectId(secondCommit).call();
262 Ref branch = git.branchCreate().setName("FromAnnotatedTag")
263 .setStartPoint("refs/tags/V10").call();
264 assertFalse(tagRef.getObjectId().equals(branch.getObjectId()));
265 assertEquals(secondCommit.getId(), branch.getObjectId());
266 }
267
268 @Test
269 public void testDelete() throws Exception {
270 createBranch(git, "ForDelete", false, "master", null);
271 git.branchDelete().setBranchNames("ForDelete").call();
272
273 createBranch(git, "ForDelete", false, secondCommit.getId().name(), null);
274 try {
275 git.branchDelete().setBranchNames("ForDelete").call();
276 fail("Deletion of a non-merged branch without force should have failed");
277 } catch (NotMergedException e) {
278
279 }
280 List<String> deleted = git.branchDelete().setBranchNames("ForDelete")
281 .setForce(true).call();
282 assertEquals(1, deleted.size());
283 assertEquals(Constants.R_HEADS + "ForDelete", deleted.get(0));
284 createBranch(git, "ForDelete", false, "master", null);
285 try {
286 createBranch(git, "ForDelete", false, "master", null);
287 fail("Repeated creation of same branch without force should fail");
288 } catch (RefAlreadyExistsException e) {
289
290 }
291
292 Ref newBranch = createBranch(git, "ForDelete", true, initialCommit
293 .name(), null);
294 assertEquals(newBranch.getTarget().getObjectId(), initialCommit.getId());
295 newBranch = createBranch(git, "ForDelete", true, secondCommit.name(),
296 null);
297 assertEquals(newBranch.getTarget().getObjectId(), secondCommit.getId());
298 git.branchDelete().setBranchNames("ForDelete").setForce(true);
299 try {
300 git.branchDelete().setBranchNames("master").call();
301 fail("Deletion of checked out branch without force should have failed");
302 } catch (CannotDeleteCurrentBranchException e) {
303
304 }
305 try {
306 git.branchDelete().setBranchNames("master").setForce(true).call();
307 fail("Deletion of checked out branch with force should have failed");
308 } catch (CannotDeleteCurrentBranchException e) {
309
310 }
311 }
312
313 @Test
314 public void testPullConfigRemoteBranch() throws Exception {
315 Git localGit = setUpRepoWithRemote();
316 Ref remote = localGit.branchList().setListMode(ListMode.REMOTE).call()
317 .get(0);
318 assertEquals("refs/remotes/origin/master", remote.getName());
319
320 createBranch(localGit, "newFromRemote", false, remote.getName(), null);
321 assertEquals("origin", localGit.getRepository().getConfig().getString(
322 "branch", "newFromRemote", "remote"));
323 localGit.branchDelete().setBranchNames("newFromRemote").call();
324
325 assertNull(localGit.getRepository().getConfig().getString("branch",
326 "newFromRemote", "remote"));
327
328 createBranch(localGit, "newFromRemote", false, remote.getName(), null);
329 assertEquals("origin", localGit.getRepository().getConfig().getString(
330 "branch", "newFromRemote", "remote"));
331 localGit.branchDelete().setBranchNames("refs/heads/newFromRemote")
332 .call();
333
334 assertNull(localGit.getRepository().getConfig().getString("branch",
335 "newFromRemote", "remote"));
336
337
338 createBranch(localGit, "newFromRemote", false, remote.getName(),
339 SetupUpstreamMode.NOTRACK);
340 assertNull(localGit.getRepository().getConfig().getString("branch",
341 "newFromRemote", "remote"));
342 localGit.branchDelete().setBranchNames("newFromRemote").call();
343 }
344
345 @Test
346 public void testPullConfigLocalBranch() throws Exception {
347 Git localGit = setUpRepoWithRemote();
348
349 createBranch(localGit, "newFromMaster", false, "master", null);
350 assertNull(localGit.getRepository().getConfig().getString("branch",
351 "newFromMaster", "remote"));
352 localGit.branchDelete().setBranchNames("newFromMaster").call();
353
354 createBranch(localGit, "newFromMaster", false, "master",
355 SetupUpstreamMode.TRACK);
356 assertEquals(".", localGit.getRepository().getConfig().getString(
357 "branch", "newFromMaster", "remote"));
358 localGit.branchDelete().setBranchNames("refs/heads/newFromMaster")
359 .call();
360
361 assertNull(localGit.getRepository().getConfig().getString("branch",
362 "newFromRemote", "remote"));
363 }
364
365 @Test
366 public void testPullConfigRenameLocalBranch() throws Exception {
367 Git localGit = setUpRepoWithRemote();
368
369 createBranch(localGit, "newFromMaster", false, "master", null);
370 assertNull(localGit.getRepository().getConfig().getString("branch",
371 "newFromMaster", "remote"));
372 localGit.branchDelete().setBranchNames("newFromMaster").call();
373
374 createBranch(localGit, "newFromMaster", false, "master",
375 SetupUpstreamMode.TRACK);
376 assertEquals(".", localGit.getRepository().getConfig().getString(
377 "branch", "newFromMaster", "remote"));
378 localGit.branchRename().setOldName("newFromMaster").setNewName(
379 "renamed").call();
380 assertNull(".", localGit.getRepository().getConfig().getString(
381 "branch", "newFromMaster", "remote"));
382 assertEquals(".", localGit.getRepository().getConfig().getString(
383 "branch", "renamed", "remote"));
384 localGit.branchDelete().setBranchNames("renamed").call();
385
386 assertNull(localGit.getRepository().getConfig().getString("branch",
387 "newFromRemote", "remote"));
388 }
389
390 @Test
391 public void testRenameLocalBranch() throws Exception {
392
393 try {
394 git.branchRename().call();
395 } catch (InvalidRefNameException e) {
396
397 }
398
399 try {
400 git.branchRename().setNewName("In va lid").call();
401 } catch (InvalidRefNameException e) {
402
403 }
404
405 try {
406 git.branchRename().setOldName("notexistingbranch").setNewName(
407 "newname").call();
408 } catch (RefNotFoundException e) {
409
410 }
411
412 createBranch(git, "existing", false, "master", null);
413
414 Ref branch = createBranch(git, "fromMasterForRename", false, "master",
415 null);
416 assertEquals(Constants.R_HEADS + "fromMasterForRename", branch
417 .getName());
418 Ref renamed = git.branchRename().setOldName("fromMasterForRename")
419 .setNewName("newName").call();
420 assertEquals(Constants.R_HEADS + "newName", renamed.getName());
421 try {
422 git.branchRename().setOldName(renamed.getName()).setNewName(
423 "existing").call();
424 fail("Should have failed");
425 } catch (RefAlreadyExistsException e) {
426
427 }
428 try {
429 git.branchRename().setNewName("In va lid").call();
430 fail("Rename with invalid ref name should fail");
431 } catch (InvalidRefNameException e) {
432
433 }
434
435 RefUpdate rup = git.getRepository().updateRef(Constants.HEAD, true);
436 rup.setNewObjectId(initialCommit);
437 rup.forceUpdate();
438 try {
439 git.branchRename().setNewName("detached").call();
440 } catch (DetachedHeadException e) {
441
442 }
443 }
444
445 @Test
446 public void testRenameRemoteTrackingBranch() throws Exception {
447 Git localGit = setUpRepoWithRemote();
448 Ref remoteBranch = localGit.branchList().setListMode(ListMode.REMOTE)
449 .call().get(0);
450 Ref renamed = localGit.branchRename()
451 .setOldName(remoteBranch.getName()).setNewName("newRemote")
452 .call();
453 assertEquals(Constants.R_REMOTES + "newRemote", renamed.getName());
454 }
455
456 @Test
457 public void testCreationImplicitStart() throws Exception {
458 git.branchCreate().setName("topic").call();
459 assertEquals(db.resolve("HEAD"), db.resolve("topic"));
460 }
461
462 @Test
463 public void testCreationNullStartPoint() throws Exception {
464 String startPoint = null;
465 git.branchCreate().setName("topic").setStartPoint(startPoint).call();
466 assertEquals(db.resolve("HEAD"), db.resolve("topic"));
467 }
468
469 public Ref createBranch(Git actGit, String name, boolean force,
470 String startPoint, SetupUpstreamMode mode)
471 throws JGitInternalException, GitAPIException {
472 CreateBranchCommand cmd = actGit.branchCreate();
473 cmd.setName(name);
474 cmd.setForce(force);
475 cmd.setStartPoint(startPoint);
476 cmd.setUpstreamMode(mode);
477 return cmd.call();
478 }
479 }