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.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.time.Instant;
23 import java.util.Collections;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Set;
27 import java.util.stream.Collectors;
28 import java.util.stream.Stream;
29 import java.util.stream.StreamSupport;
30
31 import org.eclipse.jgit.api.ListBranchCommand.ListMode;
32 import org.eclipse.jgit.api.errors.GitAPIException;
33 import org.eclipse.jgit.api.errors.JGitInternalException;
34 import org.eclipse.jgit.errors.NoWorkTreeException;
35 import org.eclipse.jgit.junit.RepositoryTestCase;
36 import org.eclipse.jgit.junit.TestRepository;
37 import org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode;
38 import org.eclipse.jgit.lib.ConfigConstants;
39 import org.eclipse.jgit.lib.Constants;
40 import org.eclipse.jgit.lib.ObjectId;
41 import org.eclipse.jgit.lib.Ref;
42 import org.eclipse.jgit.lib.RefUpdate;
43 import org.eclipse.jgit.lib.Repository;
44 import org.eclipse.jgit.lib.StoredConfig;
45 import org.eclipse.jgit.revwalk.RevBlob;
46 import org.eclipse.jgit.revwalk.RevCommit;
47 import org.eclipse.jgit.revwalk.RevObject;
48 import org.eclipse.jgit.submodule.SubmoduleStatus;
49 import org.eclipse.jgit.submodule.SubmoduleStatusType;
50 import org.eclipse.jgit.submodule.SubmoduleWalk;
51 import org.eclipse.jgit.transport.RefSpec;
52 import org.eclipse.jgit.transport.RemoteConfig;
53 import org.eclipse.jgit.transport.TagOpt;
54 import org.eclipse.jgit.transport.URIish;
55 import org.eclipse.jgit.util.SystemReader;
56 import org.junit.Test;
57
58 public class CloneCommandTest extends RepositoryTestCase {
59
60 private Git git;
61
62 private TestRepository<Repository> tr;
63
64 @Override
65 public void setUp() throws Exception {
66 super.setUp();
67 tr = new TestRepository<>(db);
68
69 git = new Git(db);
70
71 writeTrashFile("Test.txt", "Hello world");
72 git.add().addFilepattern("Test.txt").call();
73 git.commit().setMessage("Initial commit").call();
74 Ref head = git.tag().setName("tag-initial").setMessage("Tag initial")
75 .call();
76
77
78 git.checkout().setCreateBranch(true).setName("test").call();
79
80 RefUpdate ru = db.updateRef("refs/meta/foo/bar");
81 ru.setNewObjectId(head.getObjectId());
82 ru.update();
83
84
85 writeTrashFile("Test.txt", "Some change");
86 git.add().addFilepattern("Test.txt").call();
87 git.commit().setMessage("Second commit").call();
88 RevBlob blob = tr.blob("blob-not-in-master-branch");
89 git.tag().setName("tag-for-blob").setObjectId(blob).call();
90 }
91
92 @Test
93 public void testCloneRepository() throws IOException,
94 JGitInternalException, GitAPIException, URISyntaxException {
95 File directory = createTempDirectory("testCloneRepository");
96 CloneCommand command = Git.cloneRepository();
97 command.setDirectory(directory);
98 command.setURI(fileUri());
99 Git git2 = command.call();
100 addRepoToClose(git2.getRepository());
101 ObjectId id = git2.getRepository().resolve("tag-for-blob");
102 assertNotNull(id);
103 assertEquals(git2.getRepository().getFullBranch(), "refs/heads/test");
104 assertEquals(
105 "origin",
106 git2.getRepository()
107 .getConfig()
108 .getString(ConfigConstants.CONFIG_BRANCH_SECTION,
109 "test", ConfigConstants.CONFIG_KEY_REMOTE));
110 assertEquals(
111 "refs/heads/test",
112 git2.getRepository()
113 .getConfig()
114 .getString(ConfigConstants.CONFIG_BRANCH_SECTION,
115 "test", ConfigConstants.CONFIG_KEY_MERGE));
116 assertEquals(2, git2.branchList().setListMode(ListMode.REMOTE).call()
117 .size());
118 assertEquals(new RefSpec("+refs/heads/*:refs/remotes/origin/*"),
119 fetchRefSpec(git2.getRepository()));
120 assertTagOption(git2.getRepository(), TagOpt.AUTO_FOLLOW);
121 }
122
123 @Test
124 public void testCloneRepository_refLogForLocalRefs()
125 throws IOException, JGitInternalException, GitAPIException {
126 File directory = createTempDirectory("testCloneRepository");
127 CloneCommand command = Git.cloneRepository();
128 command.setDirectory(directory);
129 command.setURI(fileUri());
130 Git git2 = command.call();
131 Repository clonedRepo = git2.getRepository();
132 addRepoToClose(clonedRepo);
133
134 List<Ref> clonedRefs = clonedRepo.getRefDatabase().getRefs();
135 Stream<Ref> remoteRefs = clonedRefs.stream()
136 .filter(CloneCommandTest::isRemote);
137 Stream<Ref> localHeadsRefs = clonedRefs.stream()
138 .filter(CloneCommandTest::isLocalHead);
139
140 remoteRefs.forEach(ref -> assertFalse(
141 "Ref " + ref.getName()
142 + " is remote and should not have a reflog",
143 hasRefLog(clonedRepo, ref)));
144 localHeadsRefs.forEach(ref -> assertTrue(
145 "Ref " + ref.getName()
146 + " is local head and should have a reflog",
147 hasRefLog(clonedRepo, ref)));
148 }
149
150 private static boolean isRemote(Ref ref) {
151 return ref.getName().startsWith(Constants.R_REMOTES);
152 }
153
154 private static boolean isLocalHead(Ref ref) {
155 return !isRemote(ref) && ref.getName().startsWith(Constants.R_HEADS);
156 }
157
158 private static boolean hasRefLog(Repository repo, Ref ref) {
159 try {
160 return repo.getReflogReader(ref.getName()).getLastEntry() != null;
161 } catch (IOException ioe) {
162 throw new IllegalStateException(ioe);
163 }
164 }
165
166 @Test
167 public void testCloneRepositoryExplicitGitDir() throws IOException,
168 JGitInternalException, GitAPIException {
169 File directory = createTempDirectory("testCloneRepository");
170 CloneCommand command = Git.cloneRepository();
171 command.setDirectory(directory);
172 command.setGitDir(new File(directory, Constants.DOT_GIT));
173 command.setURI(fileUri());
174 Git git2 = command.call();
175 addRepoToClose(git2.getRepository());
176 assertEquals(directory, git2.getRepository().getWorkTree());
177 assertEquals(new File(directory, Constants.DOT_GIT), git2.getRepository()
178 .getDirectory());
179 }
180
181 @Test
182 public void testCloneRepositoryDefaultDirectory()
183 throws URISyntaxException, JGitInternalException {
184 CloneCommand command = Git.cloneRepository().setURI(fileUri());
185
186 command.verifyDirectories(new URIish(fileUri()));
187 File directory = command.getDirectory();
188 assertEquals(git.getRepository().getWorkTree().getName(), directory.getName());
189 }
190
191 @Test
192 public void testCloneBareRepositoryDefaultDirectory()
193 throws URISyntaxException, JGitInternalException {
194 CloneCommand command = Git.cloneRepository().setURI(fileUri()).setBare(true);
195
196 command.verifyDirectories(new URIish(fileUri()));
197 File directory = command.getDirectory();
198 assertEquals(git.getRepository().getWorkTree().getName() + Constants.DOT_GIT_EXT, directory.getName());
199 }
200
201 @Test
202 public void testCloneRepositoryExplicitGitDirNonStd() throws IOException,
203 JGitInternalException, GitAPIException {
204 File directory = createTempDirectory("testCloneRepository");
205 File gDir = createTempDirectory("testCloneRepository.git");
206 CloneCommand command = Git.cloneRepository();
207 command.setDirectory(directory);
208 command.setGitDir(gDir);
209 command.setURI(fileUri());
210 Git git2 = command.call();
211 addRepoToClose(git2.getRepository());
212 assertEquals(directory, git2.getRepository().getWorkTree());
213 assertEquals(gDir, git2.getRepository()
214 .getDirectory());
215 assertTrue(new File(directory, Constants.DOT_GIT).isFile());
216 assertFalse(new File(gDir, Constants.DOT_GIT).exists());
217 }
218
219 @Test
220 public void testCloneRepositoryExplicitGitDirBare() throws IOException,
221 JGitInternalException, GitAPIException {
222 File gDir = createTempDirectory("testCloneRepository.git");
223 CloneCommand command = Git.cloneRepository();
224 command.setBare(true);
225 command.setGitDir(gDir);
226 command.setURI(fileUri());
227 Git git2 = command.call();
228 addRepoToClose(git2.getRepository());
229 try {
230 assertNull(null, git2.getRepository().getWorkTree());
231 fail("Expected NoWorkTreeException");
232 } catch (NoWorkTreeException e) {
233 assertEquals(gDir, git2.getRepository().getDirectory());
234 }
235 }
236
237 @Test
238 public void testBareCloneRepository() throws IOException,
239 JGitInternalException, GitAPIException, URISyntaxException {
240 File directory = createTempDirectory("testCloneRepository_bare");
241 CloneCommand command = Git.cloneRepository();
242 command.setBare(true);
243 command.setDirectory(directory);
244 command.setURI(fileUri());
245 Git git2 = command.call();
246 addRepoToClose(git2.getRepository());
247 assertEquals(new RefSpec("+refs/heads/*:refs/heads/*"),
248 fetchRefSpec(git2.getRepository()));
249 }
250
251 @Test
252 public void testCloneRepositoryCustomRemote() throws Exception {
253 File directory = createTempDirectory("testCloneRemoteUpstream");
254 CloneCommand command = Git.cloneRepository();
255 command.setDirectory(directory);
256 command.setRemote("upstream");
257 command.setURI(fileUri());
258 Git git2 = command.call();
259 addRepoToClose(git2.getRepository());
260 assertEquals("+refs/heads/*:refs/remotes/upstream/*",
261 git2.getRepository()
262 .getConfig()
263 .getStringList("remote", "upstream",
264 "fetch")[0]);
265 assertEquals("upstream",
266 git2.getRepository()
267 .getConfig()
268 .getString("branch", "test", "remote"));
269 assertEquals(db.resolve("test"),
270 git2.getRepository().resolve("upstream/test"));
271 }
272
273 @Test
274 public void testBareCloneRepositoryCustomRemote() throws Exception {
275 File directory = createTempDirectory("testCloneRemoteUpstream_bare");
276 CloneCommand command = Git.cloneRepository();
277 command.setBare(true);
278 command.setDirectory(directory);
279 command.setRemote("upstream");
280 command.setURI(fileUri());
281 Git git2 = command.call();
282 addRepoToClose(git2.getRepository());
283 assertEquals("+refs/heads/*:refs/heads/*",
284 git2.getRepository()
285 .getConfig()
286 .getStringList("remote", "upstream",
287 "fetch")[0]);
288 assertEquals("upstream",
289 git2.getRepository()
290 .getConfig()
291 .getString("branch", "test", "remote"));
292 assertNull(git2.getRepository().resolve("upstream/test"));
293 }
294
295 @Test
296 public void testBareCloneRepositoryNullRemote() throws Exception {
297 File directory = createTempDirectory("testCloneRemoteNull_bare");
298 CloneCommand command = Git.cloneRepository();
299 command.setBare(true);
300 command.setDirectory(directory);
301 command.setRemote(null);
302 command.setURI(fileUri());
303 Git git2 = command.call();
304 addRepoToClose(git2.getRepository());
305 assertEquals("+refs/heads/*:refs/heads/*", git2.getRepository()
306 .getConfig().getStringList("remote", "origin", "fetch")[0]);
307 assertEquals("origin", git2.getRepository().getConfig()
308 .getString("branch", "test", "remote"));
309 }
310
311 public static RefSpec fetchRefSpec(Repository r) throws URISyntaxException {
312 RemoteConfig remoteConfig =
313 new RemoteConfig(r.getConfig(), Constants.DEFAULT_REMOTE_NAME);
314 return remoteConfig.getFetchRefSpecs().get(0);
315 }
316
317 @Test
318 public void testCloneRepositoryWithBranch() throws IOException,
319 JGitInternalException, GitAPIException {
320 File directory = createTempDirectory("testCloneRepositoryWithBranch");
321 CloneCommand command = Git.cloneRepository();
322 command.setBranch("refs/heads/master");
323 command.setDirectory(directory);
324 command.setURI(fileUri());
325 Git git2 = command.call();
326 addRepoToClose(git2.getRepository());
327
328 assertEquals("refs/heads/master", git2.getRepository().getFullBranch());
329 assertEquals(
330 "refs/heads/master, refs/remotes/origin/master, refs/remotes/origin/test",
331 allRefNames(git2.branchList().setListMode(ListMode.ALL).call()));
332
333
334 directory = createTempDirectory("testCloneRepositoryWithBranch_bare");
335 command = Git.cloneRepository();
336 command.setBranch("refs/heads/master");
337 command.setDirectory(directory);
338 command.setURI(fileUri());
339 command.setNoCheckout(true);
340 git2 = command.call();
341 addRepoToClose(git2.getRepository());
342
343 assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
344 assertEquals("refs/remotes/origin/master, refs/remotes/origin/test",
345 allRefNames(git2.branchList().setListMode(ListMode.ALL).call()));
346
347
348 directory = createTempDirectory("testCloneRepositoryWithBranch_bare");
349 command = Git.cloneRepository();
350 command.setBranch("refs/heads/master");
351 command.setDirectory(directory);
352 command.setURI(fileUri());
353 command.setBare(true);
354 git2 = command.call();
355 addRepoToClose(git2.getRepository());
356
357 assertEquals("refs/heads/master", git2.getRepository().getFullBranch());
358 assertEquals("refs/heads/master, refs/heads/test", allRefNames(git2
359 .branchList().setListMode(ListMode.ALL).call()));
360 }
361
362 @Test
363 public void testCloneRepositoryWithBranchShortName() throws Exception {
364 File directory = createTempDirectory("testCloneRepositoryWithBranch");
365 CloneCommand command = Git.cloneRepository();
366 command.setBranch("test");
367 command.setDirectory(directory);
368 command.setURI(fileUri());
369 Git git2 = command.call();
370 addRepoToClose(git2.getRepository());
371
372 assertEquals("refs/heads/test", git2.getRepository().getFullBranch());
373 }
374
375 @Test
376 public void testCloneRepositoryWithTagName() throws Exception {
377 File directory = createTempDirectory("testCloneRepositoryWithBranch");
378 CloneCommand command = Git.cloneRepository();
379 command.setBranch("tag-initial");
380 command.setDirectory(directory);
381 command.setURI(fileUri());
382 Git git2 = command.call();
383 addRepoToClose(git2.getRepository());
384
385 ObjectId taggedCommit = db.resolve("tag-initial^{commit}");
386 assertEquals(taggedCommit.name(), git2
387 .getRepository().getFullBranch());
388 }
389
390 @Test
391 public void testCloneRepositoryOnlyOneBranch() throws Exception {
392 File directory = createTempDirectory("testCloneRepositoryWithBranch");
393 CloneCommand command = Git.cloneRepository();
394 command.setBranch("refs/heads/master");
395 command.setBranchesToClone(Collections
396 .singletonList("refs/heads/master"));
397 command.setDirectory(directory);
398 command.setURI(fileUri());
399 Git git2 = command.call();
400 addRepoToClose(git2.getRepository());
401 assertNull(git2.getRepository().resolve("tag-for-blob"));
402 assertNotNull(git2.getRepository().resolve("tag-initial"));
403 assertEquals("refs/heads/master", git2.getRepository().getFullBranch());
404 assertEquals("refs/remotes/origin/master", allRefNames(git2
405 .branchList().setListMode(ListMode.REMOTE).call()));
406 RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
407 Constants.DEFAULT_REMOTE_NAME);
408 List<RefSpec> specs = cfg.getFetchRefSpecs();
409 assertEquals(1, specs.size());
410 assertEquals(
411 new RefSpec("+refs/heads/master:refs/remotes/origin/master"),
412 specs.get(0));
413 }
414
415 @Test
416 public void testBareCloneRepositoryOnlyOneBranch() throws Exception {
417 File directory = createTempDirectory(
418 "testCloneRepositoryWithBranch_bare");
419 CloneCommand command = Git.cloneRepository();
420 command.setBranch("refs/heads/master");
421 command.setBranchesToClone(Collections
422 .singletonList("refs/heads/master"));
423 command.setDirectory(directory);
424 command.setURI(fileUri());
425 command.setBare(true);
426 Git git2 = command.call();
427 addRepoToClose(git2.getRepository());
428 assertNull(git2.getRepository().resolve("tag-for-blob"));
429 assertNotNull(git2.getRepository().resolve("tag-initial"));
430 assertEquals("refs/heads/master", git2.getRepository().getFullBranch());
431 assertEquals("refs/heads/master", allRefNames(git2.branchList()
432 .setListMode(ListMode.ALL).call()));
433 RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
434 Constants.DEFAULT_REMOTE_NAME);
435 List<RefSpec> specs = cfg.getFetchRefSpecs();
436 assertEquals(1, specs.size());
437 assertEquals(
438 new RefSpec("+refs/heads/master:refs/heads/master"),
439 specs.get(0));
440 }
441
442 @Test
443 public void testBareCloneRepositoryMirror() throws Exception {
444 File directory = createTempDirectory(
445 "testCloneRepositoryWithBranch_mirror");
446 CloneCommand command = Git.cloneRepository();
447 command.setBranch("refs/heads/master");
448 command.setMirror(true);
449 command.setDirectory(directory);
450 command.setURI(fileUri());
451 Git git2 = command.call();
452 addRepoToClose(git2.getRepository());
453 assertTrue(git2.getRepository().isBare());
454 assertNotNull(git2.getRepository().resolve("tag-for-blob"));
455 assertNotNull(git2.getRepository().resolve("tag-initial"));
456 assertEquals("refs/heads/master", git2.getRepository().getFullBranch());
457 assertEquals("refs/heads/master, refs/heads/test", allRefNames(
458 git2.branchList().setListMode(ListMode.ALL).call()));
459 assertNotNull(git2.getRepository().exactRef("refs/meta/foo/bar"));
460 RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
461 Constants.DEFAULT_REMOTE_NAME);
462 List<RefSpec> specs = cfg.getFetchRefSpecs();
463 assertEquals(1, specs.size());
464 assertEquals(new RefSpec("+refs/*:refs/*"),
465 specs.get(0));
466 }
467
468 @Test
469 public void testCloneRepositoryOnlyOneTag() throws Exception {
470 File directory = createTempDirectory("testCloneRepositoryWithBranch");
471 CloneCommand command = Git.cloneRepository();
472 command.setBranch("tag-initial");
473 command.setBranchesToClone(
474 Collections.singletonList("refs/tags/tag-initial"));
475 command.setDirectory(directory);
476 command.setURI(fileUri());
477 Git git2 = command.call();
478 addRepoToClose(git2.getRepository());
479 assertNull(git2.getRepository().resolve("tag-for-blob"));
480 assertNull(git2.getRepository().resolve("refs/heads/master"));
481 assertNotNull(git2.getRepository().resolve("tag-initial"));
482 ObjectId taggedCommit = db.resolve("tag-initial^{commit}");
483 assertEquals(taggedCommit.name(), git2.getRepository().getFullBranch());
484 RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
485 Constants.DEFAULT_REMOTE_NAME);
486 List<RefSpec> specs = cfg.getFetchRefSpecs();
487 assertEquals(1, specs.size());
488 assertEquals(
489 new RefSpec("+refs/tags/tag-initial:refs/tags/tag-initial"),
490 specs.get(0));
491 }
492
493 @Test
494 public void testCloneRepositoryAllBranchesTakesPreference()
495 throws Exception {
496 File directory = createTempDirectory(
497 "testCloneRepositoryAllBranchesTakesPreference");
498 CloneCommand command = Git.cloneRepository();
499 command.setCloneAllBranches(true);
500 command.setBranchesToClone(
501 Collections.singletonList("refs/heads/test"));
502 command.setDirectory(directory);
503 command.setURI(fileUri());
504 Git git2 = command.call();
505 addRepoToClose(git2.getRepository());
506 assertEquals("refs/heads/test", git2.getRepository().getFullBranch());
507
508
509 assertNotNull(
510 git2.getRepository().resolve("refs/remotes/origin/master"));
511 assertNotNull(git2.getRepository().resolve("refs/remotes/origin/test"));
512 RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
513 Constants.DEFAULT_REMOTE_NAME);
514 List<RefSpec> specs = cfg.getFetchRefSpecs();
515 assertEquals(1, specs.size());
516 assertEquals(new RefSpec("+refs/heads/*:refs/remotes/origin/*"),
517 specs.get(0));
518 }
519
520 @Test
521 public void testCloneRepositoryAllBranchesIndependent() throws Exception {
522 File directory = createTempDirectory(
523 "testCloneRepositoryAllBranchesIndependent");
524 CloneCommand command = Git.cloneRepository();
525 command.setCloneAllBranches(true);
526 command.setBranchesToClone(
527 Collections.singletonList("refs/heads/test"));
528 command.setCloneAllBranches(false);
529 command.setDirectory(directory);
530 command.setURI(fileUri());
531 Git git2 = command.call();
532 addRepoToClose(git2.getRepository());
533 assertEquals("refs/heads/test", git2.getRepository().getFullBranch());
534
535 assertNull(git2.getRepository().resolve("refs/remotes/origin/master"));
536 assertNotNull(git2.getRepository().resolve("refs/remotes/origin/test"));
537 RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
538 Constants.DEFAULT_REMOTE_NAME);
539 List<RefSpec> specs = cfg.getFetchRefSpecs();
540 assertEquals(1, specs.size());
541 assertEquals(new RefSpec("+refs/heads/test:refs/remotes/origin/test"),
542 specs.get(0));
543 }
544
545 public static String allRefNames(List<Ref> refs) {
546 StringBuilder sb = new StringBuilder();
547 for (Ref f : refs) {
548 if (sb.length() > 0)
549 sb.append(", ");
550 sb.append(f.getName());
551 }
552 return sb.toString();
553 }
554
555 @Test
556 public void testCloneRepositoryWhenDestinationDirectoryExistsAndIsNotEmpty()
557 throws IOException, JGitInternalException, GitAPIException {
558 String dirName = "testCloneTargetDirectoryNotEmpty";
559 File directory = createTempDirectory(dirName);
560 CloneCommand command = Git.cloneRepository();
561 command.setDirectory(directory);
562 command.setURI(fileUri());
563 Git git2 = command.call();
564 addRepoToClose(git2.getRepository());
565
566 command = Git.cloneRepository();
567 command.setDirectory(directory);
568 command.setURI(fileUri());
569 try {
570 git2 = command.call();
571
572 fail("destination directory already exists and is not an empty folder, cloning should fail");
573 } catch (JGitInternalException e) {
574 assertTrue(e.getMessage().contains("not an empty directory"));
575 assertTrue(e.getMessage().contains(dirName));
576 }
577 }
578
579 @Test
580 public void testCloneRepositoryWithMultipleHeadBranches() throws Exception {
581 git.checkout().setName(Constants.MASTER).call();
582 git.branchCreate().setName("a").call();
583
584 File directory = createTempDirectory("testCloneRepositoryWithMultipleHeadBranches");
585 CloneCommand clone = Git.cloneRepository();
586 clone.setDirectory(directory);
587 clone.setURI(fileUri());
588 Git git2 = clone.call();
589 addRepoToClose(git2.getRepository());
590
591 assertEquals(Constants.MASTER, git2.getRepository().getBranch());
592 }
593
594 @Test
595 public void testCloneRepositoryWithSubmodules() throws Exception {
596 git.checkout().setName(Constants.MASTER).call();
597
598 String file = "file.txt";
599 writeTrashFile(file, "content");
600 git.add().addFilepattern(file).call();
601 RevCommit commit = git.commit().setMessage("create file").call();
602
603 SubmoduleAddCommand command = new SubmoduleAddCommand(db);
604 String path = "sub";
605 command.setPath(path);
606 String uri = db.getDirectory().toURI().toString();
607 command.setURI(uri);
608 Repository repo = command.call();
609 assertNotNull(repo);
610 addRepoToClose(repo);
611 git.add().addFilepattern(path)
612 .addFilepattern(Constants.DOT_GIT_MODULES).call();
613 git.commit().setMessage("adding submodule").call();
614 try (SubmoduleWalk walk = SubmoduleWalk.forIndex(git.getRepository())) {
615 assertTrue(walk.next());
616 Repository subRepo = walk.getRepository();
617 addRepoToClose(subRepo);
618 assertNotNull(subRepo);
619 assertEquals(
620 new File(git.getRepository().getWorkTree(), walk.getPath()),
621 subRepo.getWorkTree());
622 assertEquals(new File(new File(git.getRepository().getDirectory(),
623 "modules"), walk.getPath()), subRepo.getDirectory());
624 }
625
626 File directory = createTempDirectory("testCloneRepositoryWithSubmodules");
627 CloneCommand clone = Git.cloneRepository();
628 clone.setDirectory(directory);
629 clone.setCloneSubmodules(true);
630 clone.setURI(fileUri());
631 Git git2 = clone.call();
632 addRepoToClose(git2.getRepository());
633
634 assertEquals(Constants.MASTER, git2.getRepository().getBranch());
635 assertTrue(new File(git2.getRepository().getWorkTree(), path
636 + File.separatorChar + file).exists());
637
638 SubmoduleStatusCommand status = new SubmoduleStatusCommand(
639 git2.getRepository());
640 Map<String, SubmoduleStatus> statuses = status.call();
641 SubmoduleStatus pathStatus = statuses.get(path);
642 assertNotNull(pathStatus);
643 assertEquals(SubmoduleStatusType.INITIALIZED, pathStatus.getType());
644 assertEquals(commit, pathStatus.getHeadId());
645 assertEquals(commit, pathStatus.getIndexId());
646
647 try (SubmoduleWalk walk = SubmoduleWalk
648 .forIndex(git2.getRepository())) {
649 assertTrue(walk.next());
650 Repository clonedSub1 = walk.getRepository();
651 addRepoToClose(clonedSub1);
652 assertNotNull(clonedSub1);
653 assertEquals(new File(git2.getRepository().getWorkTree(),
654 walk.getPath()), clonedSub1.getWorkTree());
655 assertEquals(
656 new File(new File(git2.getRepository().getDirectory(),
657 "modules"), walk.getPath()),
658 clonedSub1.getDirectory());
659 }
660 }
661
662 @Test
663 public void testCloneRepositoryWithNestedSubmodules() throws Exception {
664 git.checkout().setName(Constants.MASTER).call();
665
666
667 File submodule1 = createTempDirectory("testCloneRepositoryWithNestedSubmodules1");
668 Git sub1Git = Git.init().setDirectory(submodule1).call();
669 assertNotNull(sub1Git);
670 Repository sub1 = sub1Git.getRepository();
671 assertNotNull(sub1);
672 addRepoToClose(sub1);
673
674 String file = "file.txt";
675 String path = "sub";
676
677 write(new File(sub1.getWorkTree(), file), "content");
678 sub1Git.add().addFilepattern(file).call();
679 RevCommit commit = sub1Git.commit().setMessage("create file").call();
680 assertNotNull(commit);
681
682
683 File submodule2 = createTempDirectory("testCloneRepositoryWithNestedSubmodules2");
684 Git sub2Git = Git.init().setDirectory(submodule2).call();
685 assertNotNull(sub2Git);
686 Repository sub2 = sub2Git.getRepository();
687 assertNotNull(sub2);
688 addRepoToClose(sub2);
689
690 write(new File(sub2.getWorkTree(), file), "content");
691 sub2Git.add().addFilepattern(file).call();
692 RevCommit sub2Head = sub2Git.commit().setMessage("create file").call();
693 assertNotNull(sub2Head);
694
695
696 Repository r = sub1Git.submoduleAdd().setPath(path)
697 .setURI(sub2.getDirectory().toURI().toString()).call();
698 assertNotNull(r);
699 addRepoToClose(r);
700 RevCommit sub1Head = sub1Git.commit().setAll(true)
701 .setMessage("Adding submodule").call();
702 assertNotNull(sub1Head);
703
704
705 r = git.submoduleAdd().setPath(path)
706 .setURI(sub1.getDirectory().toURI().toString()).call();
707 assertNotNull(r);
708 addRepoToClose(r);
709 assertNotNull(git.commit().setAll(true).setMessage("Adding submodule")
710 .call());
711
712
713 File directory = createTempDirectory("testCloneRepositoryWithNestedSubmodules");
714 CloneCommand clone = Git.cloneRepository();
715 clone.setDirectory(directory);
716 clone.setCloneSubmodules(true);
717 clone.setURI(git.getRepository().getDirectory().toURI().toString());
718 Git git2 = clone.call();
719 addRepoToClose(git2.getRepository());
720
721 assertEquals(Constants.MASTER, git2.getRepository().getBranch());
722 assertTrue(new File(git2.getRepository().getWorkTree(), path
723 + File.separatorChar + file).exists());
724 assertTrue(new File(git2.getRepository().getWorkTree(), path
725 + File.separatorChar + path + File.separatorChar + file)
726 .exists());
727
728 SubmoduleStatusCommand status = new SubmoduleStatusCommand(
729 git2.getRepository());
730 Map<String, SubmoduleStatus> statuses = status.call();
731 SubmoduleStatus pathStatus = statuses.get(path);
732 assertNotNull(pathStatus);
733 assertEquals(SubmoduleStatusType.INITIALIZED, pathStatus.getType());
734 assertEquals(sub1Head, pathStatus.getHeadId());
735 assertEquals(sub1Head, pathStatus.getIndexId());
736
737 try (SubmoduleWalk walk = SubmoduleWalk
738 .forIndex(git2.getRepository())) {
739 assertTrue(walk.next());
740 try (Repository clonedSub1 = walk.getRepository()) {
741 assertNotNull(clonedSub1);
742 assertEquals(new File(git2.getRepository().getWorkTree(),
743 walk.getPath()), clonedSub1.getWorkTree());
744 assertEquals(
745 new File(new File(git2.getRepository().getDirectory(),
746 "modules"), walk.getPath()),
747 clonedSub1.getDirectory());
748 status = new SubmoduleStatusCommand(clonedSub1);
749 statuses = status.call();
750 }
751 assertFalse(walk.next());
752 }
753 pathStatus = statuses.get(path);
754 assertNotNull(pathStatus);
755 assertEquals(SubmoduleStatusType.INITIALIZED, pathStatus.getType());
756 assertEquals(sub2Head, pathStatus.getHeadId());
757 assertEquals(sub2Head, pathStatus.getIndexId());
758 }
759
760 @Test
761 public void testCloneWithAutoSetupRebase() throws Exception {
762 File directory = createTempDirectory("testCloneRepository1");
763 CloneCommand command = Git.cloneRepository();
764 command.setDirectory(directory);
765 command.setURI(fileUri());
766 Git git2 = command.call();
767 addRepoToClose(git2.getRepository());
768 assertNull(git2.getRepository().getConfig().getEnum(
769 BranchRebaseMode.values(),
770 ConfigConstants.CONFIG_BRANCH_SECTION, "test",
771 ConfigConstants.CONFIG_KEY_REBASE, null));
772
773 StoredConfig userConfig = SystemReader.getInstance()
774 .getUserConfig();
775 userConfig.setString(ConfigConstants.CONFIG_BRANCH_SECTION, null,
776 ConfigConstants.CONFIG_KEY_AUTOSETUPREBASE,
777 ConfigConstants.CONFIG_KEY_ALWAYS);
778 userConfig.save();
779 directory = createTempDirectory("testCloneRepository2");
780 command = Git.cloneRepository();
781 command.setDirectory(directory);
782 command.setURI(fileUri());
783 git2 = command.call();
784 addRepoToClose(git2.getRepository());
785 assertEquals(BranchRebaseMode.REBASE,
786 git2.getRepository().getConfig().getEnum(
787 BranchRebaseMode.values(),
788 ConfigConstants.CONFIG_BRANCH_SECTION, "test",
789 ConfigConstants.CONFIG_KEY_REBASE,
790 BranchRebaseMode.NONE));
791
792 userConfig.setString(ConfigConstants.CONFIG_BRANCH_SECTION, null,
793 ConfigConstants.CONFIG_KEY_AUTOSETUPREBASE,
794 ConfigConstants.CONFIG_KEY_REMOTE);
795 userConfig.save();
796 directory = createTempDirectory("testCloneRepository2");
797 command = Git.cloneRepository();
798 command.setDirectory(directory);
799 command.setURI(fileUri());
800 git2 = command.call();
801 addRepoToClose(git2.getRepository());
802 assertEquals(BranchRebaseMode.REBASE,
803 git2.getRepository().getConfig().getEnum(
804 BranchRebaseMode.values(),
805 ConfigConstants.CONFIG_BRANCH_SECTION, "test",
806 ConfigConstants.CONFIG_KEY_REBASE,
807 BranchRebaseMode.NONE));
808
809 }
810
811 @Test
812 public void testCloneWithPullMerge() throws Exception {
813 File directory = createTempDirectory("testCloneRepository1");
814 try (Git g = Git.init().setDirectory(directory).setBare(false).call()) {
815 g.remoteAdd().setName(Constants.DEFAULT_REMOTE_NAME)
816 .setUri(new URIish(fileUri())).call();
817 PullResult result = g.pull().setRebase(false).call();
818 assertTrue(result.isSuccessful());
819 assertEquals("refs/heads/master",
820 g.getRepository().getFullBranch());
821 checkFile(new File(directory, "Test.txt"), "Hello world");
822 }
823 }
824
825 @Test
826 public void testCloneWithPullRebase() throws Exception {
827 File directory = createTempDirectory("testCloneRepository1");
828 try (Git g = Git.init().setDirectory(directory).setBare(false).call()) {
829 g.remoteAdd().setName(Constants.DEFAULT_REMOTE_NAME)
830 .setUri(new URIish(fileUri())).call();
831 PullResult result = g.pull().setRebase(true).call();
832 assertTrue(result.isSuccessful());
833 assertEquals("refs/heads/master",
834 g.getRepository().getFullBranch());
835 checkFile(new File(directory, "Test.txt"), "Hello world");
836 }
837 }
838
839 @Test
840 public void testCloneNoTags() throws IOException, JGitInternalException,
841 GitAPIException, URISyntaxException {
842 File directory = createTempDirectory("testCloneRepository");
843 CloneCommand command = Git.cloneRepository();
844 command.setDirectory(directory);
845 command.setURI(fileUri());
846 command.setNoTags();
847 Git git2 = command.call();
848 addRepoToClose(git2.getRepository());
849 assertNotNull(git2.getRepository().resolve("refs/heads/test"));
850 assertNull(git2.getRepository().resolve("tag-initial"));
851 assertNull(git2.getRepository().resolve("tag-for-blob"));
852 assertTagOption(git2.getRepository(), TagOpt.NO_TAGS);
853 }
854
855 @Test
856 public void testCloneFollowTags() throws IOException, JGitInternalException,
857 GitAPIException, URISyntaxException {
858 File directory = createTempDirectory("testCloneRepository");
859 CloneCommand command = Git.cloneRepository();
860 command.setDirectory(directory);
861 command.setURI(fileUri());
862 command.setBranch("refs/heads/master");
863 command.setBranchesToClone(
864 Collections.singletonList("refs/heads/master"));
865 command.setTagOption(TagOpt.FETCH_TAGS);
866 Git git2 = command.call();
867 addRepoToClose(git2.getRepository());
868 assertNull(git2.getRepository().resolve("refs/heads/test"));
869 assertNotNull(git2.getRepository().resolve("tag-initial"));
870 assertNotNull(git2.getRepository().resolve("tag-for-blob"));
871 assertTagOption(git2.getRepository(), TagOpt.FETCH_TAGS);
872 }
873
874 @Test
875 public void testCloneWithHeadSymRefIsMasterCopy() throws IOException, GitAPIException {
876
877 git.checkout().setStartPoint("master").setCreateBranch(true).setName("master-copy").call();
878
879
880 File directory = createTempDirectory("testCloneRepositorySymRef_master-copy");
881 CloneCommand command = Git.cloneRepository();
882 command.setDirectory(directory);
883 command.setURI(fileUri());
884 Git git2 = command.call();
885 addRepoToClose(git2.getRepository());
886 assertEquals("refs/heads/master-copy", git2.getRepository().getFullBranch());
887 }
888
889 @Test
890 public void testCloneWithHeadSymRefIsNonMasterCopy() throws IOException, GitAPIException {
891
892 git.checkout().setStartPoint("test").setCreateBranch(true).setName("test-copy").call();
893
894 File directory = createTempDirectory("testCloneRepositorySymRef_test-copy");
895 CloneCommand command = Git.cloneRepository();
896 command.setDirectory(directory);
897 command.setURI(fileUri());
898 Git git2 = command.call();
899 addRepoToClose(git2.getRepository());
900 assertEquals("refs/heads/test-copy", git2.getRepository().getFullBranch());
901 }
902
903 @Test
904 public void testCloneRepositoryWithDepth() throws IOException, JGitInternalException, GitAPIException {
905 File directory = createTempDirectory("testCloneRepositoryWithDepth");
906 CloneCommand command = Git.cloneRepository();
907 command.setDirectory(directory);
908 command.setURI(fileUri());
909 command.setDepth(1);
910 command.setBranchesToClone(Set.of("refs/heads/test"));
911 Git git2 = command.call();
912 addRepoToClose(git2.getRepository());
913
914 List<RevCommit> log = StreamSupport.stream(git2.log().all().call().spliterator(), false)
915 .collect(Collectors.toList());
916 assertEquals(1, log.size());
917 RevCommit commit = log.get(0);
918 assertEquals(Set.of(commit.getId()),
919 git2.getRepository().getObjectDatabase().getShallowCommits());
920 assertEquals("Second commit", commit.getFullMessage());
921 assertEquals(0, commit.getParentCount());
922 }
923
924 @Test
925 public void testCloneRepositoryWithDepthAndAllBranches() throws IOException, JGitInternalException, GitAPIException {
926 File directory = createTempDirectory("testCloneRepositoryWithDepthAndAllBranches");
927 CloneCommand command = Git.cloneRepository();
928 command.setDirectory(directory);
929 command.setURI(fileUri());
930 command.setDepth(1);
931 command.setCloneAllBranches(true);
932 Git git2 = command.call();
933 addRepoToClose(git2.getRepository());
934
935 List<RevCommit> log = StreamSupport.stream(git2.log().all().call().spliterator(), false)
936 .collect(Collectors.toList());
937 assertEquals(2, log.size());
938 assertEquals(log.stream().map(RevCommit::getId).collect(Collectors.toSet()),
939 git2.getRepository().getObjectDatabase().getShallowCommits());
940 assertEquals(List.of("Second commit", "Initial commit"),
941 log.stream().map(RevCommit::getFullMessage).collect(Collectors.toList()));
942 for (RevCommit commit : log) {
943 assertEquals(0, commit.getParentCount());
944 }
945 }
946
947 @Test
948 public void testCloneRepositoryWithDepth2() throws Exception {
949 RevCommit parent = tr.git().log().call().iterator().next();
950 RevCommit commit = tr.commit()
951 .parent(parent)
952 .message("Third commit")
953 .add("test.txt", "Hello world")
954 .create();
955 tr.update("refs/heads/test", commit);
956
957 File directory = createTempDirectory("testCloneRepositoryWithDepth2");
958 CloneCommand command = Git.cloneRepository();
959 command.setDirectory(directory);
960 command.setURI(fileUri());
961 command.setDepth(2);
962 command.setBranchesToClone(Set.of("refs/heads/test"));
963 Git git2 = command.call();
964 addRepoToClose(git2.getRepository());
965
966 List<RevCommit> log = StreamSupport
967 .stream(git2.log().all().call().spliterator(), false)
968 .collect(Collectors.toList());
969 assertEquals(2, log.size());
970 assertEquals(Set.of(parent.getId()),
971 git2.getRepository().getObjectDatabase().getShallowCommits());
972 assertEquals(List.of("Third commit", "Second commit"), log.stream()
973 .map(RevCommit::getFullMessage).collect(Collectors.toList()));
974 assertEquals(List.of(Integer.valueOf(1), Integer.valueOf(0)),
975 log.stream().map(RevCommit::getParentCount)
976 .collect(Collectors.toList()));
977 }
978
979 @Test
980 public void testCloneRepositoryWithDepthAndFetch() throws Exception {
981 File directory = createTempDirectory("testCloneRepositoryWithDepthAndFetch");
982 CloneCommand command = Git.cloneRepository();
983 command.setDirectory(directory);
984 command.setURI(fileUri());
985 command.setDepth(1);
986 command.setBranchesToClone(Set.of("refs/heads/test"));
987 Git git2 = command.call();
988 addRepoToClose(git2.getRepository());
989
990 RevCommit parent = tr.git().log().call().iterator().next();
991 RevCommit commit = tr.commit()
992 .parent(parent)
993 .message("Third commit")
994 .add("test.txt", "Hello world")
995 .create();
996 tr.update("refs/heads/test", commit);
997
998 git2.fetch().call();
999
1000 List<RevCommit> log = StreamSupport
1001 .stream(git2.log().all().call().spliterator(), false)
1002 .collect(Collectors.toList());
1003 assertEquals(2, log.size());
1004 assertEquals(Set.of(parent.getId()),
1005 git2.getRepository().getObjectDatabase().getShallowCommits());
1006 assertEquals(List.of("Third commit", "Second commit"), log.stream()
1007 .map(RevCommit::getFullMessage).collect(Collectors.toList()));
1008 assertEquals(List.of(Integer.valueOf(1), Integer.valueOf(0)),
1009 log.stream().map(RevCommit::getParentCount)
1010 .collect(Collectors.toList()));
1011 }
1012
1013 @Test
1014 public void testCloneRepositoryWithDepthAndFetchWithDepth() throws Exception {
1015 File directory = createTempDirectory("testCloneRepositoryWithDepthAndFetchWithDepth");
1016 CloneCommand command = Git.cloneRepository();
1017 command.setDirectory(directory);
1018 command.setURI(fileUri());
1019 command.setDepth(1);
1020 command.setBranchesToClone(Set.of("refs/heads/test"));
1021 Git git2 = command.call();
1022 addRepoToClose(git2.getRepository());
1023
1024 RevCommit parent = tr.git().log().call().iterator().next();
1025 RevCommit commit = tr.commit()
1026 .parent(parent)
1027 .message("Third commit")
1028 .add("test.txt", "Hello world")
1029 .create();
1030 tr.update("refs/heads/test", commit);
1031
1032 git2.fetch().setDepth(1).call();
1033
1034 List<RevCommit> log = StreamSupport
1035 .stream(git2.log().all().call().spliterator(), false)
1036 .collect(Collectors.toList());
1037 assertEquals(2, log.size());
1038 assertEquals(
1039 log.stream().map(RevObject::getId).collect(Collectors.toSet()),
1040 git2.getRepository().getObjectDatabase().getShallowCommits());
1041 assertEquals(List.of("Third commit", "Second commit"), log.stream()
1042 .map(RevCommit::getFullMessage).collect(Collectors.toList()));
1043 assertEquals(List.of(Integer.valueOf(0), Integer.valueOf(0)),
1044 log.stream().map(RevCommit::getParentCount)
1045 .collect(Collectors.toList()));
1046 }
1047
1048 @Test
1049 public void testCloneRepositoryWithDepthAndFetchUnshallow() throws Exception {
1050 File directory = createTempDirectory("testCloneRepositoryWithDepthAndFetchUnshallow");
1051 CloneCommand command = Git.cloneRepository();
1052 command.setDirectory(directory);
1053 command.setURI(fileUri());
1054 command.setDepth(1);
1055 command.setBranchesToClone(Set.of("refs/heads/test"));
1056 Git git2 = command.call();
1057 addRepoToClose(git2.getRepository());
1058
1059 git2.fetch().setUnshallow(true).call();
1060
1061 List<RevCommit> log = StreamSupport
1062 .stream(git2.log().all().call().spliterator(), false)
1063 .collect(Collectors.toList());
1064 assertEquals(2, log.size());
1065 assertEquals(Set.of(),
1066 git2.getRepository().getObjectDatabase().getShallowCommits());
1067 assertEquals(List.of("Second commit", "Initial commit"), log.stream()
1068 .map(RevCommit::getFullMessage).collect(Collectors.toList()));
1069 assertEquals(List.of(Integer.valueOf(1), Integer.valueOf(0)),
1070 log.stream().map(RevCommit::getParentCount)
1071 .collect(Collectors.toList()));
1072 }
1073
1074 @Test
1075 public void testCloneRepositoryWithShallowSince() throws Exception {
1076 RevCommit commit = tr.commit()
1077 .parent(tr.git().log().call().iterator().next())
1078 .message("Third commit").add("test.txt", "Hello world")
1079 .create();
1080 tr.update("refs/heads/test", commit);
1081
1082 File directory = createTempDirectory("testCloneRepositoryWithShallowSince");
1083 CloneCommand command = Git.cloneRepository();
1084 command.setDirectory(directory);
1085 command.setURI(fileUri());
1086 command.setShallowSince(Instant.ofEpochSecond(commit.getCommitTime()));
1087 command.setBranchesToClone(Set.of("refs/heads/test"));
1088 Git git2 = command.call();
1089 addRepoToClose(git2.getRepository());
1090
1091 List<RevCommit> log = StreamSupport
1092 .stream(git2.log().all().call().spliterator(), false)
1093 .collect(Collectors.toList());
1094 assertEquals(1, log.size());
1095 assertEquals(Set.of(commit.getId()),
1096 git2.getRepository().getObjectDatabase().getShallowCommits());
1097 assertEquals("Third commit", log.get(0).getFullMessage());
1098 assertEquals(0, log.get(0).getParentCount());
1099 }
1100
1101 @Test
1102 public void testCloneRepositoryWithShallowExclude() throws Exception {
1103 RevCommit parent = tr.git().log().call().iterator().next();
1104 tr.update("refs/heads/test",
1105 tr.commit()
1106 .parent(parent)
1107 .message("Third commit")
1108 .add("test.txt", "Hello world")
1109 .create());
1110
1111 File directory = createTempDirectory("testCloneRepositoryWithShallowExclude");
1112 CloneCommand command = Git.cloneRepository();
1113 command.setDirectory(directory);
1114 command.setURI(fileUri());
1115 command.addShallowExclude(parent.getId());
1116 command.setBranchesToClone(Set.of("refs/heads/test"));
1117 Git git2 = command.call();
1118 addRepoToClose(git2.getRepository());
1119
1120 List<RevCommit> log = StreamSupport
1121 .stream(git2.log().all().call().spliterator(), false)
1122 .collect(Collectors.toList());
1123 assertEquals(1, log.size());
1124 RevCommit commit = log.get(0);
1125 assertEquals(Set.of(commit.getId()),
1126 git2.getRepository().getObjectDatabase().getShallowCommits());
1127 assertEquals("Third commit", commit.getFullMessage());
1128 assertEquals(0, commit.getParentCount());
1129 }
1130
1131 private void assertTagOption(Repository repo, TagOpt expectedTagOption)
1132 throws URISyntaxException {
1133 RemoteConfig remoteConfig = new RemoteConfig(
1134 repo.getConfig(), "origin");
1135 assertEquals(expectedTagOption, remoteConfig.getTagOpt());
1136 }
1137
1138 private String fileUri() {
1139 return "file://" + git.getRepository().getWorkTree().getAbsolutePath();
1140 }
1141 }