Fix CloneCommand not to fetch into remote tracking branches when bare

When cloning into a bare repository we should not create remote
tracking branches (e.g refs/remotes/origin/testX). Branches of the
remote repository should but fetched into into branches of the same
name (e.g refs/heads/testX). Also add the noCheckout option which
would prevent checkout after fetch.

Change-Id: I5d4cc0389f3f30c53aa0065f38119af2a1430909
Signed-off-by: Christian Halstrick <christian.halstrick@sap.com>
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 f21dc4a..9d01291 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
@@ -49,12 +49,14 @@
 import java.io.File;
 import java.io.IOException;
 import java.util.Collections;
+import java.util.List;
 
 import org.eclipse.jgit.api.ListBranchCommand.ListMode;
 import org.eclipse.jgit.junit.TestRepository;
 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.RepositoryTestCase;
@@ -136,6 +138,42 @@ public void testCloneRepositoryWithBranch() {
 			assertNotNull(git2);
 			assertEquals(git2.getRepository().getFullBranch(),
 					"refs/heads/master");
+			assertEquals(
+					"refs/heads/master, refs/remotes/origin/master, refs/remotes/origin/test",
+					allRefNames(git2.branchList().setListMode(ListMode.ALL)
+							.call()));
+
+			// Same thing, but now without checkout
+			directory = createTempDirectory("testCloneRepositoryWithBranch_bare");
+			command = Git.cloneRepository();
+			command.setBranch("refs/heads/master");
+			command.setDirectory(directory);
+			command.setURI("file://"
+					+ git.getRepository().getWorkTree().getPath());
+			command.setNoCheckout(true);
+			git2 = command.call();
+			assertNotNull(git2);
+			assertEquals(git2.getRepository().getFullBranch(),
+					"refs/heads/master");
+			assertEquals(
+					"refs/remotes/origin/master, refs/remotes/origin/test",
+					allRefNames(git2.branchList().setListMode(ListMode.ALL)
+							.call()));
+
+			// Same thing, but now test with bare repo
+			directory = createTempDirectory("testCloneRepositoryWithBranch_bare");
+			command = Git.cloneRepository();
+			command.setBranch("refs/heads/master");
+			command.setDirectory(directory);
+			command.setURI("file://"
+					+ git.getRepository().getWorkTree().getPath());
+			command.setBare(true);
+			git2 = command.call();
+			assertNotNull(git2);
+			assertEquals(git2.getRepository().getFullBranch(),
+					"refs/heads/master");
+			assertEquals("refs/heads/master, refs/heads/test", allRefNames(git2
+					.branchList().setListMode(ListMode.ALL).call()));
 		} catch (Exception e) {
 			fail(e.getMessage());
 		}
@@ -156,13 +194,41 @@ public void testCloneRepositoryOnlyOneBranch() {
 			assertNotNull(git2);
 			assertEquals(git2.getRepository().getFullBranch(),
 					"refs/heads/master");
-			assertEquals(1, git2.branchList().setListMode(ListMode.REMOTE)
-					.call().size());
+			assertEquals("refs/remotes/origin/master",
+					allRefNames(git2.branchList()
+					.setListMode(ListMode.REMOTE).call()));
+
+			// Same thing, but now test with bare repo
+			directory = createTempDirectory("testCloneRepositoryWithBranch_bare");
+			command = Git.cloneRepository();
+			command.setBranch("refs/heads/master");
+			command.setBranchesToClone(Collections
+					.singletonList("refs/heads/master"));
+			command.setDirectory(directory);
+			command.setURI("file://"
+					+ git.getRepository().getWorkTree().getPath());
+			command.setBare(true);
+			git2 = command.call();
+			assertNotNull(git2);
+			assertEquals(git2.getRepository().getFullBranch(),
+					"refs/heads/master");
+			assertEquals("refs/heads/master", allRefNames(git2
+					.branchList().setListMode(ListMode.ALL).call()));
 		} catch (Exception e) {
 			fail(e.getMessage());
 		}
 	}
 
+	public static String allRefNames(List<Ref> refs) {
+		StringBuilder sb = new StringBuilder();
+		for (Ref f : refs) {
+			if (sb.length() > 0)
+				sb.append(", ");
+			sb.append(f.getName());
+		}
+		return sb.toString();
+	}
+
 	public static File createTempDirectory(String name) throws IOException {
 		final File temp;
 		temp = File.createTempFile(name, Long.toString(System.nanoTime()));
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GitConstructionTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GitConstructionTest.java
index 0e0b187..b6ba4c9 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GitConstructionTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/GitConstructionTest.java
@@ -79,7 +79,7 @@ public void testWrap() {
 		assertEquals(1, git.branchList().call().size());
 
 		git = Git.wrap(bareRepo);
-		assertEquals(2, git.branchList().setListMode(ListMode.ALL).call()
+		assertEquals(1, git.branchList().setListMode(ListMode.ALL).call()
 				.size());
 
 		try {
@@ -96,7 +96,7 @@ public void testOpen() throws IOException {
 		assertEquals(1, git.branchList().call().size());
 
 		git = Git.open(bareRepo.getDirectory());
-		assertEquals(2, git.branchList().setListMode(ListMode.ALL).call()
+		assertEquals(1, git.branchList().setListMode(ListMode.ALL).call()
 				.size());
 
 		git = Git.open(db.getWorkTree());
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 3965230..aa8cf6e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
@@ -98,6 +98,8 @@ public class CloneCommand implements Callable<Git> {
 
 	private boolean cloneAllBranches;
 
+	private boolean noCheckout;
+
 	private Collection<String> branchesToClone;
 
 	/**
@@ -112,7 +114,8 @@ public Git call() throws JGitInternalException {
 			URIish u = new URIish(uri);
 			Repository repository = init(u);
 			FetchResult result = fetch(repository, u);
-			checkout(repository, result);
+			if (!noCheckout)
+				checkout(repository, result);
 			return new Git(repository);
 		} catch (IOException ioe) {
 			throw new JGitInternalException(ioe.getMessage(), ioe);
@@ -140,7 +143,8 @@ private FetchResult fetch(Repository repo, URIish u)
 		RemoteConfig config = new RemoteConfig(repo.getConfig(), remote);
 		config.addURI(u);
 
-		final String dst = Constants.R_REMOTES + config.getName();
+		final String dst = bare ? Constants.R_HEADS : Constants.R_REMOTES
+				+ config.getName();
 		RefSpec refSpec = new RefSpec();
 		refSpec = refSpec.setForceUpdate(true);
 		refSpec = refSpec.setSourceDestination(Constants.R_HEADS + "*", dst + "/*"); //$NON-NLS-1$ //$NON-NLS-2$
@@ -368,4 +372,16 @@ public CloneCommand setBranchesToClone(Collection<String> branchesToClone) {
 		return this;
 	}
 
+	/**
+	 * @param noCheckout
+	 *            if set to <code>true</code> no branch will be checked out
+	 *            after the clone. This enhances performance of the clone
+	 *            command when there is no need for a checked out branch.
+	 * @return {@code this}
+	 */
+	public CloneCommand setNoCheckout(boolean noCheckout) {
+		this.noCheckout = noCheckout;
+		return this;
+	}
+
 }