From e7b4d108e19913362e92b17fa6ad5b7c9afba23f Mon Sep 17 00:00:00 2001 From: Thomas Wolf Date: Tue, 11 Dec 2018 00:47:13 +0100 Subject: [PATCH] Enable cloning only specific tags Single-branch-clone should be able to clone a single tag. Enhance CloneCommand to accept also full refs of tags in setBranchesToClone(). Make sure we also include fetch ref specs for the fetch command for tags. This mimics the behavior of native git's single-branch clone: git clone --branch --single-branch Bug: 542611 Change-Id: I285cf043751d9b0ba71258ee8214c0e5d1191428 Signed-off-by: Thomas Wolf --- .../eclipse/jgit/api/CloneCommandTest.java | 26 ++++++++++++ .../org/eclipse/jgit/api/CloneCommand.java | 42 +++++++++++++------ 2 files changed, 55 insertions(+), 13 deletions(-) diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java index 6b5fe502b..1523b49ec 100644 --- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java +++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java @@ -424,6 +424,32 @@ public class CloneCommandTest extends RepositoryTestCase { specs.get(0)); } + @Test + public void testCloneRepositoryOnlyOneTag() throws Exception { + File directory = createTempDirectory("testCloneRepositoryWithBranch"); + CloneCommand command = Git.cloneRepository(); + command.setBranch("tag-initial"); + command.setBranchesToClone( + Collections.singletonList("refs/tags/tag-initial")); + command.setDirectory(directory); + command.setURI(fileUri()); + Git git2 = command.call(); + addRepoToClose(git2.getRepository()); + assertNotNull(git2); + assertNull(git2.getRepository().resolve("tag-for-blob")); + assertNull(git2.getRepository().resolve("refs/heads/master")); + assertNotNull(git2.getRepository().resolve("tag-initial")); + ObjectId taggedCommit = db.resolve("tag-initial^{commit}"); + assertEquals(taggedCommit.name(), git2.getRepository().getFullBranch()); + RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(), + Constants.DEFAULT_REMOTE_NAME); + List specs = cfg.getFetchRefSpecs(); + assertEquals(1, specs.size()); + assertEquals( + new RefSpec("+refs/tags/tag-initial:refs/tags/tag-initial"), + specs.get(0)); + } + public static String allRefNames(List refs) { StringBuilder sb = new StringBuilder(); for (Ref f : refs) { diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java index 73af8ba16..0248ba279 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java @@ -303,18 +303,25 @@ public class CloneCommand extends TransportCommand { } private List calculateRefSpecs(boolean fetchAll, String dst) { - RefSpec wcrs = new RefSpec(); - wcrs = wcrs.setForceUpdate(true); - wcrs = wcrs.setSourceDestination(Constants.R_HEADS + '*', dst); + RefSpec heads = new RefSpec(); + heads = heads.setForceUpdate(true); + heads = heads.setSourceDestination(Constants.R_HEADS + '*', dst); List specs = new ArrayList<>(); if (!fetchAll) { + RefSpec tags = new RefSpec(); + tags = tags.setForceUpdate(true); + tags = tags.setSourceDestination(Constants.R_TAGS + '*', + Constants.R_TAGS + '*'); for (String selectedRef : branchesToClone) { - if (wcrs.matchSource(selectedRef)) { - specs.add(wcrs.expandFromSource(selectedRef)); + if (heads.matchSource(selectedRef)) { + specs.add(heads.expandFromSource(selectedRef)); + } else if (tags.matchSource(selectedRef)) { + specs.add(tags.expandFromSource(selectedRef)); } } } else { - specs.add(wcrs); + // We'll fetch the tags anyway. + specs.add(heads); } return specs; } @@ -590,11 +597,15 @@ public class CloneCommand extends TransportCommand { } /** - * Set whether all branches have to be fetched + * Set whether all branches have to be fetched. + *

+ * If {@code false}, use {@link #setBranchesToClone(Collection)} to define + * what will be cloned. If neither are set, all branches will be cloned. + *

* * @param cloneAllBranches - * true when all branches have to be fetched (indicates wildcard - * in created fetch refspec), false otherwise. + * {@code true} when all branches have to be fetched (indicates + * wildcard in created fetch refspec), {@code false} otherwise. * @return {@code this} */ public CloneCommand setCloneAllBranches(boolean cloneAllBranches) { @@ -616,12 +627,17 @@ public class CloneCommand extends TransportCommand { } /** - * Set branches to clone + * Set the branches or tags to clone. + *

+ * This is ignored if {@link #setCloneAllBranches(boolean) + * setCloneAllBranches(true)} is used. If {@code branchesToClone} is + * {@code null} or empty, it's also ignored and all branches will be cloned. + *

* * @param branchesToClone - * collection of branches to clone. Ignored when allSelected is - * true. Must be specified as full ref names (e.g. - * refs/heads/master). + * collection of branches to clone. Must be specified as full ref + * names (e.g. {@code refs/heads/master} or + * {@code refs/tags/v1.0.0}). * @return {@code this} */ public CloneCommand setBranchesToClone(Collection branchesToClone) {