Merge "Constants for objects and info/{http-,}alternates"
diff --git a/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java b/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java
index a830ff2..befb7f6 100644
--- a/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java
+++ b/org.eclipse.jgit.pgm.test/src/org/eclipse/jgit/lib/CLIRepositoryTestCase.java
@@ -211,6 +211,14 @@
 				.replaceAll("\t", "\\\\t");
 	}
 
+	protected String shellQuote(String s) {
+		return "'" + s.replace("'", "'\\''") + "'";
+	}
+
+	protected String shellQuote(File f) {
+		return "'" + f.getPath().replace("'", "'\\''") + "'";
+	}
+
 	protected void assertStringArrayEquals(String expected, String[] actual) {
 		// if there is more than one line, ignore last one if empty
 		assertEquals(1,
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java
index e07fdd5..03aa469 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/ArchiveTest.java
@@ -139,10 +139,6 @@
 				listTarEntries(result));
 	}
 
-	private static String shellQuote(String s) {
-		return "'" + s.replace("'", "'\\''") + "'";
-	}
-
 	@Test
 	public void testFormatOverridesFilename() throws Exception {
 		File archive = new File(db.getWorkTree(), "format-overrides-name.tar");
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java
index 2c0abd7..c31f28c 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/CloneTest.java
@@ -78,9 +78,9 @@
 		File gitDir = db.getDirectory();
 		String sourceURI = gitDir.toURI().toString();
 		File target = createTempDirectory("target");
-		StringBuilder cmd = new StringBuilder("git clone ").append(sourceURI
-				+ " " + target.getPath());
-		String[] result = execute(cmd.toString());
+		String cmd = "git clone " + sourceURI + " "
+				+ shellQuote(target.getPath());
+		String[] result = execute(cmd);
 		assertArrayEquals(new String[] {
 				"Cloning into '" + target.getPath() + "'...",
 						"", "" }, result);
@@ -101,9 +101,9 @@
 		File gitDir = db.getDirectory();
 		String sourceURI = gitDir.toURI().toString();
 		File target = createTempDirectory("target");
-		StringBuilder cmd = new StringBuilder("git clone ").append(sourceURI
-				+ " " + target.getPath());
-		String[] result = execute(cmd.toString());
+		String cmd = "git clone " + sourceURI + " "
+				+ shellQuote(target.getPath());
+		String[] result = execute(cmd);
 		assertArrayEquals(new String[] {
 				"Cloning into '" + target.getPath() + "'...",
 				"warning: You appear to have cloned an empty repository.", "",
@@ -125,8 +125,8 @@
 		File gitDir = db.getDirectory();
 		String sourceURI = gitDir.toURI().toString();
 		String name = new URIish(sourceURI).getHumanishName();
-		StringBuilder cmd = new StringBuilder("git clone ").append(sourceURI);
-		String[] result = execute(cmd.toString());
+		String cmd = "git clone " + sourceURI;
+		String[] result = execute(cmd);
 		assertArrayEquals(new String[] {
 				"Cloning into '" + new File(target, name).getName() + "'...",
 				"", "" }, result);
@@ -143,10 +143,10 @@
 		String sourcePath = gitDir.getAbsolutePath();
 		String targetPath = (new File(sourcePath)).getParentFile()
 				.getParentFile().getAbsolutePath()
-				+ "/target.git";
-		StringBuilder cmd = new StringBuilder("git clone --bare ")
-				.append(sourcePath + " " + targetPath);
-		String[] result = execute(cmd.toString());
+				+ File.separator + "target.git";
+		String cmd = "git clone --bare " + shellQuote(sourcePath) + " "
+				+ shellQuote(targetPath);
+		String[] result = execute(cmd);
 		assertArrayEquals(new String[] {
 				"Cloning into '" + targetPath + "'...", "", "" }, result);
 		Git git2 = Git.open(new File(targetPath));
diff --git a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/LsRemoteTest.java b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/LsRemoteTest.java
index ba6b771..fd3c383 100644
--- a/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/LsRemoteTest.java
+++ b/org.eclipse.jgit.pgm.test/tst/org/eclipse/jgit/pgm/LsRemoteTest.java
@@ -80,7 +80,7 @@
 	@Test
 	public void testLsRemote() throws Exception {
 		final List<String> result = CLIGitCommand.execute(
-				"git ls-remote " + db.getDirectory(), db);
+				"git ls-remote " + shellQuote(db.getDirectory()), db);
 		assertArrayEquals(new String[] {
 				"d0b1ef2b3dea02bb2ca824445c04e6def012c32c	HEAD",
 				"d0b1ef2b3dea02bb2ca824445c04e6def012c32c	refs/heads/master",
@@ -98,7 +98,8 @@
 	public void testLsRemoteHeads() throws Exception {
 		final List<String> result = CLIGitCommand.execute(
 				"git ls-remote --heads "
-				+ db.getDirectory(), db);
+						+ shellQuote(db.getDirectory()),
+				db);
 		assertArrayEquals(new String[] {
 				"d0b1ef2b3dea02bb2ca824445c04e6def012c32c	refs/heads/master",
 				"d0b1ef2b3dea02bb2ca824445c04e6def012c32c	refs/heads/test",
@@ -108,7 +109,7 @@
 	@Test
 	public void testLsRemoteTags() throws Exception {
 		final List<String> result = CLIGitCommand.execute(
-				"git ls-remote --tags " + db.getDirectory(), db);
+				"git ls-remote --tags " + shellQuote(db.getDirectory()), db);
 		assertArrayEquals(new String[] {
 				"efc02078d83a5226986ae917323acec7e1e8b7cb	refs/tags/tag1",
 				"d0b1ef2b3dea02bb2ca824445c04e6def012c32c	refs/tags/tag1^{}",
@@ -122,7 +123,8 @@
 	@Test
 	public void testLsRemoteHeadsTags() throws Exception {
 		final List<String> result = CLIGitCommand.execute(
-				"git ls-remote --heads --tags " + db.getDirectory(), db);
+				"git ls-remote --heads --tags " + shellQuote(db.getDirectory()),
+				db);
 		assertArrayEquals(new String[] {
 				"d0b1ef2b3dea02bb2ca824445c04e6def012c32c	refs/heads/master",
 				"d0b1ef2b3dea02bb2ca824445c04e6def012c32c	refs/heads/test",
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
index 65df6e3..22c67c1 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/UploadPackTest.java
@@ -2138,7 +2138,14 @@
 				PacketLineIn.END);
 		PacketLineIn pckIn = new PacketLineIn(recvStream);
 
-		assertThat(pckIn.readString(), is("\001packfile"));
+		String s;
+		// When sideband-all is used, object counting happens before
+		// "packfile" is written, and object counting outputs progress
+		// in sideband 2. Skip all these lines.
+		for (s = pckIn.readString(); s.startsWith("\002"); s = pckIn.readString()) {
+			// do nothing
+		}
+		assertThat(s, is("\001packfile"));
 		parsePack(recvStream);
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java
index b07b6f6..7f837bb 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PacketLineOut.java
@@ -74,7 +74,7 @@
 
 	private boolean flushOnEnd;
 
-	private boolean useSideband;
+	private boolean usingSideband;
 
 	/**
 	 * Create a new packet line writer.
@@ -100,13 +100,25 @@
 	}
 
 	/**
-	 * When writing packet lines, use the first byte of each non-flush and
-	 * non-delim packet as a sideband designator.
-	 *
+	 * @return whether to add a sideband designator to each non-flush and
+	 *     non-delim packet
+	 * @see #setUsingSideband
 	 * @since 5.5
 	 */
-	public void useSidebandFormat() {
-		this.useSideband = true;
+	public boolean isUsingSideband() {
+		return usingSideband;
+	}
+
+	/**
+	 * @param value If true, when writing packet lines, add, as the first
+	 *     byte, a sideband designator to each non-flush and non-delim
+	 *     packet. See pack-protocol.txt and protocol-v2.txt from the Git
+	 *     project for more information, specifically the "side-band" and
+	 *     "sideband-all" sections.
+	 * @since 5.5
+	 */
+	public void setUsingSideband(boolean value) {
+		this.usingSideband = value;
 	}
 
 	/**
@@ -151,7 +163,7 @@
 	 * @since 4.5
 	 */
 	public void writePacket(byte[] buf, int pos, int len) throws IOException {
-		if (useSideband) {
+		if (usingSideband) {
 			formatLength(len + 5);
 			out.write(lenbuffer, 0, 4);
 			out.write(1);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
index c580ed0..2194f2f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -1136,7 +1136,7 @@
 		protocolV2Hook.onFetch(req);
 
 		if (req.getSidebandAll()) {
-			pckOut.useSidebandFormat();
+			pckOut.setUsingSideband(true);
 		}
 
 		// TODO(ifrade): Refactor to pass around the Request object, instead of
@@ -1224,7 +1224,11 @@
 
 			if (sectionSent)
 				pckOut.writeDelim();
-			pckOut.writeString("packfile\n"); //$NON-NLS-1$
+			if (!pckOut.isUsingSideband()) {
+				// sendPack will write "packfile\n" for us if sideband-all is used.
+				// But sideband-all is not used, so we have to write it ourselves.
+				pckOut.writeString("packfile\n"); //$NON-NLS-1$
+			}
 			sendPack(new PackStatistics.Accumulator(),
 					req,
 					req.getClientCapabilities().contains(OPTION_INCLUDE_TAG)
@@ -2293,6 +2297,9 @@
 				}
 			}
 
+			if (pckOut.isUsingSideband()) {
+				pckOut.writeString("packfile\n"); //$NON-NLS-1$
+			}
 			pw.writePack(pm, NullProgressMonitor.INSTANCE, packOut);
 
 			if (msgOut != NullOutputStream.INSTANCE) {