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