View Javadoc
1   /*
2    * Copyright (C) 2011, 2013 Chris Aniszczyk <caniszczyk@gmail.com> and others
3    *
4    * This program and the accompanying materials are made available under the
5    * terms of the Eclipse Distribution License v. 1.0 which is available at
6    * https://www.eclipse.org/org/documents/edl-v10.php.
7    *
8    * SPDX-License-Identifier: BSD-3-Clause
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.assertNotNull;
15  import static org.junit.Assert.assertNull;
16  import static org.junit.Assert.assertTrue;
17  import static org.junit.Assert.fail;
18  
19  import java.io.File;
20  import java.io.IOException;
21  import java.net.URISyntaxException;
22  import java.util.Collections;
23  import java.util.List;
24  import java.util.Map;
25  
26  import org.eclipse.jgit.api.ListBranchCommand.ListMode;
27  import org.eclipse.jgit.api.errors.GitAPIException;
28  import org.eclipse.jgit.api.errors.JGitInternalException;
29  import org.eclipse.jgit.errors.NoWorkTreeException;
30  import org.eclipse.jgit.junit.RepositoryTestCase;
31  import org.eclipse.jgit.junit.TestRepository;
32  import org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode;
33  import org.eclipse.jgit.lib.ConfigConstants;
34  import org.eclipse.jgit.lib.Constants;
35  import org.eclipse.jgit.lib.ObjectId;
36  import org.eclipse.jgit.lib.Ref;
37  import org.eclipse.jgit.lib.RefUpdate;
38  import org.eclipse.jgit.lib.Repository;
39  import org.eclipse.jgit.lib.StoredConfig;
40  import org.eclipse.jgit.revwalk.RevBlob;
41  import org.eclipse.jgit.revwalk.RevCommit;
42  import org.eclipse.jgit.submodule.SubmoduleStatus;
43  import org.eclipse.jgit.submodule.SubmoduleStatusType;
44  import org.eclipse.jgit.submodule.SubmoduleWalk;
45  import org.eclipse.jgit.transport.RefSpec;
46  import org.eclipse.jgit.transport.RemoteConfig;
47  import org.eclipse.jgit.transport.TagOpt;
48  import org.eclipse.jgit.transport.URIish;
49  import org.eclipse.jgit.util.SystemReader;
50  import org.junit.Test;
51  
52  public class CloneCommandTest extends RepositoryTestCase {
53  
54  	private Git git;
55  
56  	private TestRepository<Repository> tr;
57  
58  	@Override
59  	public void setUp() throws Exception {
60  		super.setUp();
61  		tr = new TestRepository<>(db);
62  
63  		git = new Git(db);
64  		// commit something
65  		writeTrashFile("Test.txt", "Hello world");
66  		git.add().addFilepattern("Test.txt").call();
67  		git.commit().setMessage("Initial commit").call();
68  		Ref head = git.tag().setName("tag-initial").setMessage("Tag initial")
69  				.call();
70  
71  		// create a test branch and switch to it
72  		git.checkout().setCreateBranch(true).setName("test").call();
73  		// create a non-standard ref
74  		RefUpdate ru = db.updateRef("refs/meta/foo/bar");
75  		ru.setNewObjectId(head.getObjectId());
76  		ru.update();
77  
78  		// commit something on the test branch
79  		writeTrashFile("Test.txt", "Some change");
80  		git.add().addFilepattern("Test.txt").call();
81  		git.commit().setMessage("Second commit").call();
82  		RevBlob blob = tr.blob("blob-not-in-master-branch");
83  		git.tag().setName("tag-for-blob").setObjectId(blob).call();
84  	}
85  
86  	@Test
87  	public void testCloneRepository() throws IOException,
88  			JGitInternalException, GitAPIException, URISyntaxException {
89  		File directory = createTempDirectory("testCloneRepository");
90  		CloneCommand command = Git.cloneRepository();
91  		command.setDirectory(directory);
92  		command.setURI(fileUri());
93  		Git git2 = command.call();
94  		addRepoToClose(git2.getRepository());
95  		assertNotNull(git2);
96  		ObjectId id = git2.getRepository().resolve("tag-for-blob");
97  		assertNotNull(id);
98  		assertEquals(git2.getRepository().getFullBranch(), "refs/heads/test");
99  		assertEquals(
100 				"origin",
101 				git2.getRepository()
102 						.getConfig()
103 						.getString(ConfigConstants.CONFIG_BRANCH_SECTION,
104 								"test", ConfigConstants.CONFIG_KEY_REMOTE));
105 		assertEquals(
106 				"refs/heads/test",
107 				git2.getRepository()
108 						.getConfig()
109 						.getString(ConfigConstants.CONFIG_BRANCH_SECTION,
110 								"test", ConfigConstants.CONFIG_KEY_MERGE));
111 		assertEquals(2, git2.branchList().setListMode(ListMode.REMOTE).call()
112 				.size());
113 		assertEquals(new RefSpec("+refs/heads/*:refs/remotes/origin/*"),
114 				fetchRefSpec(git2.getRepository()));
115 		assertTagOption(git2.getRepository(), TagOpt.AUTO_FOLLOW);
116 	}
117 
118 	@Test
119 	public void testCloneRepositoryExplicitGitDir() throws IOException,
120 			JGitInternalException, GitAPIException {
121 		File directory = createTempDirectory("testCloneRepository");
122 		CloneCommand command = Git.cloneRepository();
123 		command.setDirectory(directory);
124 		command.setGitDir(new File(directory, Constants.DOT_GIT));
125 		command.setURI(fileUri());
126 		Git git2 = command.call();
127 		addRepoToClose(git2.getRepository());
128 		assertEquals(directory, git2.getRepository().getWorkTree());
129 		assertEquals(new File(directory, Constants.DOT_GIT), git2.getRepository()
130 				.getDirectory());
131 	}
132 
133 	@Test
134 	public void testCloneRepositoryDefaultDirectory()
135 			throws URISyntaxException, JGitInternalException {
136 		CloneCommand command = Git.cloneRepository().setURI(fileUri());
137 
138 		command.verifyDirectories(new URIish(fileUri()));
139 		File directory = command.getDirectory();
140 		assertEquals(git.getRepository().getWorkTree().getName(), directory.getName());
141 	}
142 
143 	@Test
144 	public void testCloneBareRepositoryDefaultDirectory()
145 			throws URISyntaxException, JGitInternalException {
146 		CloneCommand command = Git.cloneRepository().setURI(fileUri()).setBare(true);
147 
148 		command.verifyDirectories(new URIish(fileUri()));
149 		File directory = command.getDirectory();
150 		assertEquals(git.getRepository().getWorkTree().getName() + Constants.DOT_GIT_EXT, directory.getName());
151 	}
152 
153 	@Test
154 	public void testCloneRepositoryExplicitGitDirNonStd() throws IOException,
155 			JGitInternalException, GitAPIException {
156 		File directory = createTempDirectory("testCloneRepository");
157 		File gDir = createTempDirectory("testCloneRepository.git");
158 		CloneCommand command = Git.cloneRepository();
159 		command.setDirectory(directory);
160 		command.setGitDir(gDir);
161 		command.setURI(fileUri());
162 		Git git2 = command.call();
163 		addRepoToClose(git2.getRepository());
164 		assertEquals(directory, git2.getRepository().getWorkTree());
165 		assertEquals(gDir, git2.getRepository()
166 				.getDirectory());
167 		assertTrue(new File(directory, Constants.DOT_GIT).isFile());
168 		assertFalse(new File(gDir, Constants.DOT_GIT).exists());
169 	}
170 
171 	@Test
172 	public void testCloneRepositoryExplicitGitDirBare() throws IOException,
173 			JGitInternalException, GitAPIException {
174 		File gDir = createTempDirectory("testCloneRepository.git");
175 		CloneCommand command = Git.cloneRepository();
176 		command.setBare(true);
177 		command.setGitDir(gDir);
178 		command.setURI(fileUri());
179 		Git git2 = command.call();
180 		addRepoToClose(git2.getRepository());
181 		try {
182 			assertNull(null, git2.getRepository().getWorkTree());
183 			fail("Expected NoWorkTreeException");
184 		} catch (NoWorkTreeException e) {
185 			assertEquals(gDir, git2.getRepository().getDirectory());
186 		}
187 	}
188 
189 	@Test
190 	public void testBareCloneRepository() throws IOException,
191 			JGitInternalException, GitAPIException, URISyntaxException {
192 		File directory = createTempDirectory("testCloneRepository_bare");
193 		CloneCommand command = Git.cloneRepository();
194 		command.setBare(true);
195 		command.setDirectory(directory);
196 		command.setURI(fileUri());
197 		Git git2 = command.call();
198 		addRepoToClose(git2.getRepository());
199 		assertEquals(new RefSpec("+refs/heads/*:refs/heads/*"),
200 				fetchRefSpec(git2.getRepository()));
201 	}
202 
203 	@Test
204 	public void testCloneRepositoryCustomRemote() throws Exception {
205 		File directory = createTempDirectory("testCloneRemoteUpstream");
206 		CloneCommand command = Git.cloneRepository();
207 		command.setDirectory(directory);
208 		command.setRemote("upstream");
209 		command.setURI(fileUri());
210 		Git git2 = command.call();
211 		addRepoToClose(git2.getRepository());
212 		assertEquals("+refs/heads/*:refs/remotes/upstream/*",
213 				git2.getRepository()
214 					.getConfig()
215 					.getStringList("remote", "upstream",
216 							"fetch")[0]);
217 		assertEquals("upstream",
218 				git2.getRepository()
219 					.getConfig()
220 					.getString("branch", "test", "remote"));
221 		assertEquals(db.resolve("test"),
222 				git2.getRepository().resolve("upstream/test"));
223 	}
224 
225 	@Test
226 	public void testBareCloneRepositoryCustomRemote() throws Exception {
227 		File directory = createTempDirectory("testCloneRemoteUpstream_bare");
228 		CloneCommand command = Git.cloneRepository();
229 		command.setBare(true);
230 		command.setDirectory(directory);
231 		command.setRemote("upstream");
232 		command.setURI(fileUri());
233 		Git git2 = command.call();
234 		addRepoToClose(git2.getRepository());
235 		assertEquals("+refs/heads/*:refs/heads/*",
236 				git2.getRepository()
237 					.getConfig()
238 					.getStringList("remote", "upstream",
239 							"fetch")[0]);
240 		assertEquals("upstream",
241 				git2.getRepository()
242 					.getConfig()
243 					.getString("branch", "test", "remote"));
244 		assertNull(git2.getRepository().resolve("upstream/test"));
245 	}
246 
247 	@Test
248 	public void testBareCloneRepositoryNullRemote() throws Exception {
249 		File directory = createTempDirectory("testCloneRemoteNull_bare");
250 		CloneCommand command = Git.cloneRepository();
251 		command.setBare(true);
252 		command.setDirectory(directory);
253 		command.setRemote(null);
254 		command.setURI(fileUri());
255 		Git git2 = command.call();
256 		addRepoToClose(git2.getRepository());
257 		assertEquals("+refs/heads/*:refs/heads/*", git2.getRepository()
258 				.getConfig().getStringList("remote", "origin", "fetch")[0]);
259 		assertEquals("origin", git2.getRepository().getConfig()
260 				.getString("branch", "test", "remote"));
261 	}
262 
263 	public static RefSpec fetchRefSpec(Repository r) throws URISyntaxException {
264 		RemoteConfig remoteConfig =
265 				new RemoteConfig(r.getConfig(), Constants.DEFAULT_REMOTE_NAME);
266 		return remoteConfig.getFetchRefSpecs().get(0);
267 	}
268 
269 	@Test
270 	public void testCloneRepositoryWithBranch() throws IOException,
271 			JGitInternalException, GitAPIException {
272 		File directory = createTempDirectory("testCloneRepositoryWithBranch");
273 		CloneCommand command = Git.cloneRepository();
274 		command.setBranch("refs/heads/master");
275 		command.setDirectory(directory);
276 		command.setURI(fileUri());
277 		Git git2 = command.call();
278 		addRepoToClose(git2.getRepository());
279 
280 		assertNotNull(git2);
281 		assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
282 		assertEquals(
283 				"refs/heads/master, refs/remotes/origin/master, refs/remotes/origin/test",
284 				allRefNames(git2.branchList().setListMode(ListMode.ALL).call()));
285 
286 		// Same thing, but now without checkout
287 		directory = createTempDirectory("testCloneRepositoryWithBranch_bare");
288 		command = Git.cloneRepository();
289 		command.setBranch("refs/heads/master");
290 		command.setDirectory(directory);
291 		command.setURI(fileUri());
292 		command.setNoCheckout(true);
293 		git2 = command.call();
294 		addRepoToClose(git2.getRepository());
295 
296 		assertNotNull(git2);
297 		assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
298 		assertEquals("refs/remotes/origin/master, refs/remotes/origin/test",
299 				allRefNames(git2.branchList().setListMode(ListMode.ALL).call()));
300 
301 		// Same thing, but now test with bare repo
302 		directory = createTempDirectory("testCloneRepositoryWithBranch_bare");
303 		command = Git.cloneRepository();
304 		command.setBranch("refs/heads/master");
305 		command.setDirectory(directory);
306 		command.setURI(fileUri());
307 		command.setBare(true);
308 		git2 = command.call();
309 		addRepoToClose(git2.getRepository());
310 
311 		assertNotNull(git2);
312 		assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
313 		assertEquals("refs/heads/master, refs/heads/test", allRefNames(git2
314 				.branchList().setListMode(ListMode.ALL).call()));
315 	}
316 
317 	@Test
318 	public void testCloneRepositoryWithBranchShortName() throws Exception {
319 		File directory = createTempDirectory("testCloneRepositoryWithBranch");
320 		CloneCommand command = Git.cloneRepository();
321 		command.setBranch("test");
322 		command.setDirectory(directory);
323 		command.setURI(fileUri());
324 		Git git2 = command.call();
325 		addRepoToClose(git2.getRepository());
326 
327 		assertNotNull(git2);
328 		assertEquals("refs/heads/test", git2.getRepository().getFullBranch());
329 	}
330 
331 	@Test
332 	public void testCloneRepositoryWithTagName() throws Exception {
333 		File directory = createTempDirectory("testCloneRepositoryWithBranch");
334 		CloneCommand command = Git.cloneRepository();
335 		command.setBranch("tag-initial");
336 		command.setDirectory(directory);
337 		command.setURI(fileUri());
338 		Git git2 = command.call();
339 		addRepoToClose(git2.getRepository());
340 
341 		assertNotNull(git2);
342 		ObjectId taggedCommit = db.resolve("tag-initial^{commit}");
343 		assertEquals(taggedCommit.name(), git2
344 				.getRepository().getFullBranch());
345 	}
346 
347 	@Test
348 	public void testCloneRepositoryOnlyOneBranch() throws Exception {
349 		File directory = createTempDirectory("testCloneRepositoryWithBranch");
350 		CloneCommand command = Git.cloneRepository();
351 		command.setBranch("refs/heads/master");
352 		command.setBranchesToClone(Collections
353 				.singletonList("refs/heads/master"));
354 		command.setDirectory(directory);
355 		command.setURI(fileUri());
356 		Git git2 = command.call();
357 		addRepoToClose(git2.getRepository());
358 		assertNotNull(git2);
359 		assertNull(git2.getRepository().resolve("tag-for-blob"));
360 		assertNotNull(git2.getRepository().resolve("tag-initial"));
361 		assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
362 		assertEquals("refs/remotes/origin/master", allRefNames(git2
363 				.branchList().setListMode(ListMode.REMOTE).call()));
364 		RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
365 				Constants.DEFAULT_REMOTE_NAME);
366 		List<RefSpec> specs = cfg.getFetchRefSpecs();
367 		assertEquals(1, specs.size());
368 		assertEquals(
369 				new RefSpec("+refs/heads/master:refs/remotes/origin/master"),
370 				specs.get(0));
371 	}
372 
373 	@Test
374 	public void testBareCloneRepositoryOnlyOneBranch() throws Exception {
375 		File directory = createTempDirectory(
376 				"testCloneRepositoryWithBranch_bare");
377 		CloneCommand command = Git.cloneRepository();
378 		command.setBranch("refs/heads/master");
379 		command.setBranchesToClone(Collections
380 				.singletonList("refs/heads/master"));
381 		command.setDirectory(directory);
382 		command.setURI(fileUri());
383 		command.setBare(true);
384 		Git git2 = command.call();
385 		addRepoToClose(git2.getRepository());
386 		assertNotNull(git2);
387 		assertNull(git2.getRepository().resolve("tag-for-blob"));
388 		assertNotNull(git2.getRepository().resolve("tag-initial"));
389 		assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
390 		assertEquals("refs/heads/master", allRefNames(git2.branchList()
391 				.setListMode(ListMode.ALL).call()));
392 		RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
393 				Constants.DEFAULT_REMOTE_NAME);
394 		List<RefSpec> specs = cfg.getFetchRefSpecs();
395 		assertEquals(1, specs.size());
396 		assertEquals(
397 				new RefSpec("+refs/heads/master:refs/heads/master"),
398 				specs.get(0));
399 	}
400 
401 	@Test
402 	public void testBareCloneRepositoryMirror() throws Exception {
403 		File directory = createTempDirectory(
404 				"testCloneRepositoryWithBranch_mirror");
405 		CloneCommand command = Git.cloneRepository();
406 		command.setBranch("refs/heads/master");
407 		command.setMirror(true); // implies bare repository
408 		command.setDirectory(directory);
409 		command.setURI(fileUri());
410 		Git git2 = command.call();
411 		addRepoToClose(git2.getRepository());
412 		assertNotNull(git2);
413 		assertTrue(git2.getRepository().isBare());
414 		assertNotNull(git2.getRepository().resolve("tag-for-blob"));
415 		assertNotNull(git2.getRepository().resolve("tag-initial"));
416 		assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
417 		assertEquals("refs/heads/master, refs/heads/test", allRefNames(
418 				git2.branchList().setListMode(ListMode.ALL).call()));
419 		assertNotNull(git2.getRepository().exactRef("refs/meta/foo/bar"));
420 		RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
421 				Constants.DEFAULT_REMOTE_NAME);
422 		List<RefSpec> specs = cfg.getFetchRefSpecs();
423 		assertEquals(1, specs.size());
424 		assertEquals(new RefSpec("+refs/*:refs/*"),
425 				specs.get(0));
426 	}
427 
428 	@Test
429 	public void testCloneRepositoryOnlyOneTag() throws Exception {
430 		File directory = createTempDirectory("testCloneRepositoryWithBranch");
431 		CloneCommand command = Git.cloneRepository();
432 		command.setBranch("tag-initial");
433 		command.setBranchesToClone(
434 				Collections.singletonList("refs/tags/tag-initial"));
435 		command.setDirectory(directory);
436 		command.setURI(fileUri());
437 		Git git2 = command.call();
438 		addRepoToClose(git2.getRepository());
439 		assertNotNull(git2);
440 		assertNull(git2.getRepository().resolve("tag-for-blob"));
441 		assertNull(git2.getRepository().resolve("refs/heads/master"));
442 		assertNotNull(git2.getRepository().resolve("tag-initial"));
443 		ObjectId taggedCommit = db.resolve("tag-initial^{commit}");
444 		assertEquals(taggedCommit.name(), git2.getRepository().getFullBranch());
445 		RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
446 				Constants.DEFAULT_REMOTE_NAME);
447 		List<RefSpec> specs = cfg.getFetchRefSpecs();
448 		assertEquals(1, specs.size());
449 		assertEquals(
450 				new RefSpec("+refs/tags/tag-initial:refs/tags/tag-initial"),
451 				specs.get(0));
452 	}
453 
454 	@Test
455 	public void testCloneRepositoryAllBranchesTakesPreference()
456 			throws Exception {
457 		File directory = createTempDirectory(
458 				"testCloneRepositoryAllBranchesTakesPreference");
459 		CloneCommand command = Git.cloneRepository();
460 		command.setCloneAllBranches(true);
461 		command.setBranchesToClone(
462 				Collections.singletonList("refs/heads/test"));
463 		command.setDirectory(directory);
464 		command.setURI(fileUri());
465 		Git git2 = command.call();
466 		addRepoToClose(git2.getRepository());
467 		assertNotNull(git2);
468 		assertEquals(git2.getRepository().getFullBranch(), "refs/heads/test");
469 		// Expect both remote branches to exist; setCloneAllBranches(true)
470 		// should override any setBranchesToClone().
471 		assertNotNull(
472 				git2.getRepository().resolve("refs/remotes/origin/master"));
473 		assertNotNull(git2.getRepository().resolve("refs/remotes/origin/test"));
474 		RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
475 				Constants.DEFAULT_REMOTE_NAME);
476 		List<RefSpec> specs = cfg.getFetchRefSpecs();
477 		assertEquals(1, specs.size());
478 		assertEquals(new RefSpec("+refs/heads/*:refs/remotes/origin/*"),
479 				specs.get(0));
480 	}
481 
482 	@Test
483 	public void testCloneRepositoryAllBranchesIndependent() throws Exception {
484 		File directory = createTempDirectory(
485 				"testCloneRepositoryAllBranchesIndependent");
486 		CloneCommand command = Git.cloneRepository();
487 		command.setCloneAllBranches(true);
488 		command.setBranchesToClone(
489 				Collections.singletonList("refs/heads/test"));
490 		command.setCloneAllBranches(false);
491 		command.setDirectory(directory);
492 		command.setURI(fileUri());
493 		Git git2 = command.call();
494 		addRepoToClose(git2.getRepository());
495 		assertNotNull(git2);
496 		assertEquals(git2.getRepository().getFullBranch(), "refs/heads/test");
497 		// Expect only the test branch; allBranches was re-set to false
498 		assertNull(git2.getRepository().resolve("refs/remotes/origin/master"));
499 		assertNotNull(git2.getRepository().resolve("refs/remotes/origin/test"));
500 		RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
501 				Constants.DEFAULT_REMOTE_NAME);
502 		List<RefSpec> specs = cfg.getFetchRefSpecs();
503 		assertEquals(1, specs.size());
504 		assertEquals(new RefSpec("+refs/heads/test:refs/remotes/origin/test"),
505 				specs.get(0));
506 	}
507 
508 	public static String allRefNames(List<Ref> refs) {
509 		StringBuilder sb = new StringBuilder();
510 		for (Ref f : refs) {
511 			if (sb.length() > 0)
512 				sb.append(", ");
513 			sb.append(f.getName());
514 		}
515 		return sb.toString();
516 	}
517 
518 	@Test
519 	public void testCloneRepositoryWhenDestinationDirectoryExistsAndIsNotEmpty()
520 			throws IOException, JGitInternalException, GitAPIException {
521 		String dirName = "testCloneTargetDirectoryNotEmpty";
522 		File directory = createTempDirectory(dirName);
523 		CloneCommand command = Git.cloneRepository();
524 		command.setDirectory(directory);
525 		command.setURI(fileUri());
526 		Git git2 = command.call();
527 		addRepoToClose(git2.getRepository());
528 		assertNotNull(git2);
529 		// clone again
530 		command = Git.cloneRepository();
531 		command.setDirectory(directory);
532 		command.setURI(fileUri());
533 		try {
534 			git2 = command.call();
535 			// we shouldn't get here
536 			fail("destination directory already exists and is not an empty folder, cloning should fail");
537 		} catch (JGitInternalException e) {
538 			assertTrue(e.getMessage().contains("not an empty directory"));
539 			assertTrue(e.getMessage().contains(dirName));
540 		}
541 	}
542 
543 	@Test
544 	public void testCloneRepositoryWithMultipleHeadBranches() throws Exception {
545 		git.checkout().setName(Constants.MASTER).call();
546 		git.branchCreate().setName("a").call();
547 
548 		File directory = createTempDirectory("testCloneRepositoryWithMultipleHeadBranches");
549 		CloneCommand clone = Git.cloneRepository();
550 		clone.setDirectory(directory);
551 		clone.setURI(fileUri());
552 		Git git2 = clone.call();
553 		addRepoToClose(git2.getRepository());
554 		assertNotNull(git2);
555 
556 		assertEquals(Constants.MASTER, git2.getRepository().getBranch());
557 	}
558 
559 	@Test
560 	public void testCloneRepositoryWithSubmodules() throws Exception {
561 		git.checkout().setName(Constants.MASTER).call();
562 
563 		String file = "file.txt";
564 		writeTrashFile(file, "content");
565 		git.add().addFilepattern(file).call();
566 		RevCommit commit = git.commit().setMessage("create file").call();
567 
568 		SubmoduleAddCommand command = new SubmoduleAddCommand(db);
569 		String path = "sub";
570 		command.setPath(path);
571 		String uri = db.getDirectory().toURI().toString();
572 		command.setURI(uri);
573 		Repository repo = command.call();
574 		assertNotNull(repo);
575 		addRepoToClose(repo);
576 		git.add().addFilepattern(path)
577 				.addFilepattern(Constants.DOT_GIT_MODULES).call();
578 		git.commit().setMessage("adding submodule").call();
579 		try (SubmoduleWalk walk = SubmoduleWalk.forIndex(git.getRepository())) {
580 			assertTrue(walk.next());
581 			Repository subRepo = walk.getRepository();
582 			addRepoToClose(subRepo);
583 			assertNotNull(subRepo);
584 			assertEquals(
585 					new File(git.getRepository().getWorkTree(), walk.getPath()),
586 					subRepo.getWorkTree());
587 			assertEquals(new File(new File(git.getRepository().getDirectory(),
588 					"modules"), walk.getPath()), subRepo.getDirectory());
589 		}
590 
591 		File directory = createTempDirectory("testCloneRepositoryWithSubmodules");
592 		CloneCommand clone = Git.cloneRepository();
593 		clone.setDirectory(directory);
594 		clone.setCloneSubmodules(true);
595 		clone.setURI(fileUri());
596 		Git git2 = clone.call();
597 		addRepoToClose(git2.getRepository());
598 		assertNotNull(git2);
599 
600 		assertEquals(Constants.MASTER, git2.getRepository().getBranch());
601 		assertTrue(new File(git2.getRepository().getWorkTree(), path
602 				+ File.separatorChar + file).exists());
603 
604 		SubmoduleStatusCommand status = new SubmoduleStatusCommand(
605 				git2.getRepository());
606 		Map<String, SubmoduleStatus> statuses = status.call();
607 		SubmoduleStatus pathStatus = statuses.get(path);
608 		assertNotNull(pathStatus);
609 		assertEquals(SubmoduleStatusType.INITIALIZED, pathStatus.getType());
610 		assertEquals(commit, pathStatus.getHeadId());
611 		assertEquals(commit, pathStatus.getIndexId());
612 
613 		try (SubmoduleWalk walk = SubmoduleWalk
614 				.forIndex(git2.getRepository())) {
615 			assertTrue(walk.next());
616 			Repository clonedSub1 = walk.getRepository();
617 			addRepoToClose(clonedSub1);
618 			assertNotNull(clonedSub1);
619 			assertEquals(new File(git2.getRepository().getWorkTree(),
620 					walk.getPath()), clonedSub1.getWorkTree());
621 			assertEquals(
622 					new File(new File(git2.getRepository().getDirectory(),
623 							"modules"), walk.getPath()),
624 					clonedSub1.getDirectory());
625 		}
626 	}
627 
628 	@Test
629 	public void testCloneRepositoryWithNestedSubmodules() throws Exception {
630 		git.checkout().setName(Constants.MASTER).call();
631 
632 		// Create submodule 1
633 		File submodule1 = createTempDirectory("testCloneRepositoryWithNestedSubmodules1");
634 		Git sub1Git = Git.init().setDirectory(submodule1).call();
635 		assertNotNull(sub1Git);
636 		Repository sub1 = sub1Git.getRepository();
637 		assertNotNull(sub1);
638 		addRepoToClose(sub1);
639 
640 		String file = "file.txt";
641 		String path = "sub";
642 
643 		write(new File(sub1.getWorkTree(), file), "content");
644 		sub1Git.add().addFilepattern(file).call();
645 		RevCommit commit = sub1Git.commit().setMessage("create file").call();
646 		assertNotNull(commit);
647 
648 		// Create submodule 2
649 		File submodule2 = createTempDirectory("testCloneRepositoryWithNestedSubmodules2");
650 		Git sub2Git = Git.init().setDirectory(submodule2).call();
651 		assertNotNull(sub2Git);
652 		Repository sub2 = sub2Git.getRepository();
653 		assertNotNull(sub2);
654 		addRepoToClose(sub2);
655 
656 		write(new File(sub2.getWorkTree(), file), "content");
657 		sub2Git.add().addFilepattern(file).call();
658 		RevCommit sub2Head = sub2Git.commit().setMessage("create file").call();
659 		assertNotNull(sub2Head);
660 
661 		// Add submodule 2 to submodule 1
662 		Repository r = sub1Git.submoduleAdd().setPath(path)
663 				.setURI(sub2.getDirectory().toURI().toString()).call();
664 		assertNotNull(r);
665 		addRepoToClose(r);
666 		RevCommit sub1Head = sub1Git.commit().setAll(true)
667 				.setMessage("Adding submodule").call();
668 		assertNotNull(sub1Head);
669 
670 		// Add submodule 1 to default repository
671 		r = git.submoduleAdd().setPath(path)
672 				.setURI(sub1.getDirectory().toURI().toString()).call();
673 		assertNotNull(r);
674 		addRepoToClose(r);
675 		assertNotNull(git.commit().setAll(true).setMessage("Adding submodule")
676 				.call());
677 
678 		// Clone default repository and include submodules
679 		File directory = createTempDirectory("testCloneRepositoryWithNestedSubmodules");
680 		CloneCommand clone = Git.cloneRepository();
681 		clone.setDirectory(directory);
682 		clone.setCloneSubmodules(true);
683 		clone.setURI(git.getRepository().getDirectory().toURI().toString());
684 		Git git2 = clone.call();
685 		addRepoToClose(git2.getRepository());
686 		assertNotNull(git2);
687 
688 		assertEquals(Constants.MASTER, git2.getRepository().getBranch());
689 		assertTrue(new File(git2.getRepository().getWorkTree(), path
690 				+ File.separatorChar + file).exists());
691 		assertTrue(new File(git2.getRepository().getWorkTree(), path
692 				+ File.separatorChar + path + File.separatorChar + file)
693 				.exists());
694 
695 		SubmoduleStatusCommand status = new SubmoduleStatusCommand(
696 				git2.getRepository());
697 		Map<String, SubmoduleStatus> statuses = status.call();
698 		SubmoduleStatus pathStatus = statuses.get(path);
699 		assertNotNull(pathStatus);
700 		assertEquals(SubmoduleStatusType.INITIALIZED, pathStatus.getType());
701 		assertEquals(sub1Head, pathStatus.getHeadId());
702 		assertEquals(sub1Head, pathStatus.getIndexId());
703 
704 		try (SubmoduleWalk walk = SubmoduleWalk
705 				.forIndex(git2.getRepository())) {
706 			assertTrue(walk.next());
707 			try (Repository clonedSub1 = walk.getRepository()) {
708 				assertNotNull(clonedSub1);
709 				assertEquals(new File(git2.getRepository().getWorkTree(),
710 						walk.getPath()), clonedSub1.getWorkTree());
711 				assertEquals(
712 						new File(new File(git2.getRepository().getDirectory(),
713 								"modules"), walk.getPath()),
714 						clonedSub1.getDirectory());
715 				status = new SubmoduleStatusCommand(clonedSub1);
716 				statuses = status.call();
717 			}
718 			assertFalse(walk.next());
719 		}
720 		pathStatus = statuses.get(path);
721 		assertNotNull(pathStatus);
722 		assertEquals(SubmoduleStatusType.INITIALIZED, pathStatus.getType());
723 		assertEquals(sub2Head, pathStatus.getHeadId());
724 		assertEquals(sub2Head, pathStatus.getIndexId());
725 	}
726 
727 	@Test
728 	public void testCloneWithAutoSetupRebase() throws Exception {
729 		File directory = createTempDirectory("testCloneRepository1");
730 		CloneCommand command = Git.cloneRepository();
731 		command.setDirectory(directory);
732 		command.setURI(fileUri());
733 		Git git2 = command.call();
734 		addRepoToClose(git2.getRepository());
735 		assertNull(git2.getRepository().getConfig().getEnum(
736 				BranchRebaseMode.values(),
737 				ConfigConstants.CONFIG_BRANCH_SECTION, "test",
738 				ConfigConstants.CONFIG_KEY_REBASE, null));
739 
740 		StoredConfig userConfig = SystemReader.getInstance()
741 				.getUserConfig();
742 		userConfig.setString(ConfigConstants.CONFIG_BRANCH_SECTION, null,
743 				ConfigConstants.CONFIG_KEY_AUTOSETUPREBASE,
744 				ConfigConstants.CONFIG_KEY_ALWAYS);
745 		userConfig.save();
746 		directory = createTempDirectory("testCloneRepository2");
747 		command = Git.cloneRepository();
748 		command.setDirectory(directory);
749 		command.setURI(fileUri());
750 		git2 = command.call();
751 		addRepoToClose(git2.getRepository());
752 		assertEquals(BranchRebaseMode.REBASE,
753 				git2.getRepository().getConfig().getEnum(
754 						BranchRebaseMode.values(),
755 						ConfigConstants.CONFIG_BRANCH_SECTION, "test",
756 						ConfigConstants.CONFIG_KEY_REBASE,
757 						BranchRebaseMode.NONE));
758 
759 		userConfig.setString(ConfigConstants.CONFIG_BRANCH_SECTION, null,
760 				ConfigConstants.CONFIG_KEY_AUTOSETUPREBASE,
761 				ConfigConstants.CONFIG_KEY_REMOTE);
762 		userConfig.save();
763 		directory = createTempDirectory("testCloneRepository2");
764 		command = Git.cloneRepository();
765 		command.setDirectory(directory);
766 		command.setURI(fileUri());
767 		git2 = command.call();
768 		addRepoToClose(git2.getRepository());
769 		assertEquals(BranchRebaseMode.REBASE,
770 				git2.getRepository().getConfig().getEnum(
771 						BranchRebaseMode.values(),
772 						ConfigConstants.CONFIG_BRANCH_SECTION, "test",
773 						ConfigConstants.CONFIG_KEY_REBASE,
774 						BranchRebaseMode.NONE));
775 
776 	}
777 
778 	@Test
779 	public void testCloneWithPullMerge() throws Exception {
780 		File directory = createTempDirectory("testCloneRepository1");
781 		try (Git g = Git.init().setDirectory(directory).setBare(false).call()) {
782 			g.remoteAdd().setName(Constants.DEFAULT_REMOTE_NAME)
783 					.setUri(new URIish(fileUri())).call();
784 			PullResult result = g.pull().setRebase(false).call();
785 			assertTrue(result.isSuccessful());
786 			assertEquals("refs/heads/master",
787 					g.getRepository().getFullBranch());
788 			checkFile(new File(directory, "Test.txt"), "Hello world");
789 		}
790 	}
791 
792 	@Test
793 	public void testCloneWithPullRebase() throws Exception {
794 		File directory = createTempDirectory("testCloneRepository1");
795 		try (Git g = Git.init().setDirectory(directory).setBare(false).call()) {
796 			g.remoteAdd().setName(Constants.DEFAULT_REMOTE_NAME)
797 					.setUri(new URIish(fileUri())).call();
798 			PullResult result = g.pull().setRebase(true).call();
799 			assertTrue(result.isSuccessful());
800 			assertEquals("refs/heads/master",
801 					g.getRepository().getFullBranch());
802 			checkFile(new File(directory, "Test.txt"), "Hello world");
803 		}
804 	}
805 
806 	@Test
807 	public void testCloneNoTags() throws IOException, JGitInternalException,
808 			GitAPIException, URISyntaxException {
809 		File directory = createTempDirectory("testCloneRepository");
810 		CloneCommand command = Git.cloneRepository();
811 		command.setDirectory(directory);
812 		command.setURI(fileUri());
813 		command.setNoTags();
814 		Git git2 = command.call();
815 		addRepoToClose(git2.getRepository());
816 		assertNotNull(git2);
817 		assertNotNull(git2.getRepository().resolve("refs/heads/test"));
818 		assertNull(git2.getRepository().resolve("tag-initial"));
819 		assertNull(git2.getRepository().resolve("tag-for-blob"));
820 		assertTagOption(git2.getRepository(), TagOpt.NO_TAGS);
821 	}
822 
823 	@Test
824 	public void testCloneFollowTags() throws IOException, JGitInternalException,
825 			GitAPIException, URISyntaxException {
826 		File directory = createTempDirectory("testCloneRepository");
827 		CloneCommand command = Git.cloneRepository();
828 		command.setDirectory(directory);
829 		command.setURI(fileUri());
830 		command.setBranch("refs/heads/master");
831 		command.setBranchesToClone(
832 				Collections.singletonList("refs/heads/master"));
833 		command.setTagOption(TagOpt.FETCH_TAGS);
834 		Git git2 = command.call();
835 		addRepoToClose(git2.getRepository());
836 		assertNotNull(git2);
837 		assertNull(git2.getRepository().resolve("refs/heads/test"));
838 		assertNotNull(git2.getRepository().resolve("tag-initial"));
839 		assertNotNull(git2.getRepository().resolve("tag-for-blob"));
840 		assertTagOption(git2.getRepository(), TagOpt.FETCH_TAGS);
841 	}
842 
843 	private void assertTagOption(Repository repo, TagOpt expectedTagOption)
844 			throws URISyntaxException {
845 		RemoteConfig remoteConfig = new RemoteConfig(
846 				repo.getConfig(), "origin");
847 		assertEquals(expectedTagOption, remoteConfig.getTagOpt());
848 	}
849 
850 	private String fileUri() {
851 		return "file://" + git.getRepository().getWorkTree().getAbsolutePath();
852 	}
853 }