diff options
author | Matthias Sohn <matthias.sohn@sap.com> | 2019-10-19 01:52:51 +0200 |
---|---|---|
committer | Matthias Sohn <matthias.sohn@sap.com> | 2019-10-21 09:27:13 +0200 |
commit | 6216b0de8a829fa764b8c8c51095cf0c5964213f (patch) | |
tree | 0f9f0d148305799bf7739fe8085348150dd47eee | |
parent | 8e356fc45e2b169572088ebdfb931ca788a5e220 (diff) | |
download | jgit-6216b0de8a829fa764b8c8c51095cf0c5964213f.tar.gz jgit-6216b0de8a829fa764b8c8c51095cf0c5964213f.zip |
Implement mirror option in CloneCommand
Bug: 552173
Change-Id: If79adf578b303890314a3285d7a6d2c71f48d091
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
-rw-r--r-- | org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java | 34 | ||||
-rw-r--r-- | org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java | 92 |
2 files changed, 99 insertions, 27 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 b4abb53d84..63fe4212ba 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 @@ -67,6 +67,7 @@ import org.eclipse.jgit.lib.ConfigConstants; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; +import org.eclipse.jgit.lib.RefUpdate; import org.eclipse.jgit.lib.Repository; import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.revwalk.RevBlob; @@ -96,10 +97,15 @@ public class CloneCommandTest extends RepositoryTestCase { writeTrashFile("Test.txt", "Hello world"); git.add().addFilepattern("Test.txt").call(); git.commit().setMessage("Initial commit").call(); - git.tag().setName("tag-initial").setMessage("Tag initial").call(); + Ref head = git.tag().setName("tag-initial").setMessage("Tag initial") + .call(); // create a test branch and switch to it git.checkout().setCreateBranch(true).setName("test").call(); + // create a non-standard ref + RefUpdate ru = db.updateRef("refs/meta/foo/bar"); + ru.setNewObjectId(head.getObjectId()); + ru.update(); // commit something on the test branch writeTrashFile("Test.txt", "Some change"); @@ -425,6 +431,32 @@ public class CloneCommandTest extends RepositoryTestCase { } @Test + public void testBareCloneRepositoryMirror() throws Exception { + File directory = createTempDirectory( + "testCloneRepositoryWithBranch_mirror"); + CloneCommand command = Git.cloneRepository(); + command.setBranch("refs/heads/master"); + command.setMirror(true); // implies bare repository + command.setDirectory(directory); + command.setURI(fileUri()); + Git git2 = command.call(); + addRepoToClose(git2.getRepository()); + assertNotNull(git2); + assertNotNull(git2.getRepository().resolve("tag-for-blob")); + assertNotNull(git2.getRepository().resolve("tag-initial")); + assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master"); + assertEquals("refs/heads/master, refs/heads/test", allRefNames( + git2.branchList().setListMode(ListMode.ALL).call())); + assertNotNull(git2.getRepository().exactRef("refs/meta/foo/bar")); + RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(), + Constants.DEFAULT_REMOTE_NAME); + List<RefSpec> specs = cfg.getFetchRefSpecs(); + assertEquals(1, specs.size()); + assertEquals(new RefSpec("+refs/*:refs/*"), + specs.get(0)); + } + + @Test public void testCloneRepositoryOnlyOneTag() throws Exception { File directory = createTempDirectory("testCloneRepositoryWithBranch"); CloneCommand command = Git.cloneRepository(); 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 9f63d0f005..809f2d111a 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java @@ -77,8 +77,8 @@ import org.eclipse.jgit.transport.RefSpec; import org.eclipse.jgit.transport.RemoteConfig; import org.eclipse.jgit.transport.TagOpt; import org.eclipse.jgit.transport.URIish; -import org.eclipse.jgit.util.FileUtils; import org.eclipse.jgit.util.FS; +import org.eclipse.jgit.util.FileUtils; /** * Clone a repository into a new working directory @@ -104,7 +104,7 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> { private ProgressMonitor monitor = NullProgressMonitor.INSTANCE; - private boolean cloneAllBranches; + private FETCH_TYPE fetchType = FETCH_TYPE.ALL_BRANCHES; private boolean cloneSubmodules; @@ -118,6 +118,10 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> { private boolean gitDirExistsInitially; + private enum FETCH_TYPE { + MULTIPLE_BRANCHES, ALL_BRANCHES, MIRROR + } + /** * Callback for status of clone operation. * @@ -282,12 +286,11 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> { RemoteConfig config = new RemoteConfig(clonedRepo.getConfig(), remote); config.addURI(u); - final String dst = (bare ? Constants.R_HEADS : Constants.R_REMOTES - + config.getName() + '/') + '*'; - boolean fetchAll = cloneAllBranches || branchesToClone == null - || branchesToClone.isEmpty(); + boolean fetchAll = fetchType == FETCH_TYPE.ALL_BRANCHES + || fetchType == FETCH_TYPE.MIRROR; - config.setFetchRefSpecs(calculateRefSpecs(fetchAll, dst)); + config.setFetchRefSpecs(calculateRefSpecs(fetchType, config.getName())); + config.setMirror(fetchType == FETCH_TYPE.MIRROR); config.update(clonedRepo.getConfig()); clonedRepo.getConfig().save(); @@ -302,26 +305,33 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> { return command.call(); } - private List<RefSpec> calculateRefSpecs(boolean fetchAll, String dst) { - RefSpec heads = new RefSpec(); - heads = heads.setForceUpdate(true); - heads = heads.setSourceDestination(Constants.R_HEADS + '*', dst); + private List<RefSpec> calculateRefSpecs(FETCH_TYPE type, + String remoteName) { List<RefSpec> 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 (heads.matchSource(selectedRef)) { - specs.add(heads.expandFromSource(selectedRef)); - } else if (tags.matchSource(selectedRef)) { - specs.add(tags.expandFromSource(selectedRef)); + if (type == FETCH_TYPE.MIRROR) { + specs.add(new RefSpec().setForceUpdate(true).setSourceDestination( + Constants.R_REFS + '*', Constants.R_REFS + '*')); + } else { + RefSpec heads = new RefSpec(); + heads = heads.setForceUpdate(true); + final String dst = (bare ? Constants.R_HEADS + : Constants.R_REMOTES + remoteName + '/') + '*'; + heads = heads.setSourceDestination(Constants.R_HEADS + '*', dst); + if (type == FETCH_TYPE.MULTIPLE_BRANCHES) { + RefSpec tags = new RefSpec().setForceUpdate(true) + .setSourceDestination(Constants.R_TAGS + '*', + Constants.R_TAGS + '*'); + for (String selectedRef : branchesToClone) { + if (heads.matchSource(selectedRef)) { + specs.add(heads.expandFromSource(selectedRef)); + } else if (tags.matchSource(selectedRef)) { + specs.add(tags.expandFromSource(selectedRef)); + } } + } else { + // We'll fetch the tags anyway. + specs.add(heads); } - } else { - // We'll fetch the tags anyway. - specs.add(heads); } return specs; } @@ -609,7 +619,31 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> { * @return {@code this} */ public CloneCommand setCloneAllBranches(boolean cloneAllBranches) { - this.cloneAllBranches = cloneAllBranches; + this.fetchType = cloneAllBranches ? FETCH_TYPE.ALL_BRANCHES + : this.fetchType; + return this; + } + + /** + * Set up a mirror of the source repository. This implies that a bare + * repository will be created. Compared to {@link #setBare}, + * {@code #setMirror} not only maps local branches of the source to local + * branches of the target, it maps all refs (including remote-tracking + * branches, notes etc.) and sets up a refspec configuration such that all + * these refs are overwritten by a git remote update in the target + * repository. + * + * @param mirror + * whether to mirror all refs from the source repository + * + * @return {@code this} + * @since 5.6 + */ + public CloneCommand setMirror(boolean mirror) { + if (mirror) { + this.fetchType = FETCH_TYPE.MIRROR; + setBare(true); + } return this; } @@ -641,7 +675,13 @@ public class CloneCommand extends TransportCommand<CloneCommand, Git> { * @return {@code this} */ public CloneCommand setBranchesToClone(Collection<String> branchesToClone) { - this.branchesToClone = branchesToClone; + if (branchesToClone == null || branchesToClone.isEmpty()) { + // fallback to default + fetchType = FETCH_TYPE.ALL_BRANCHES; + } else { + this.fetchType = FETCH_TYPE.MULTIPLE_BRANCHES; + this.branchesToClone = branchesToClone; + } return this; } |