Merge "Add the intended file to avoid breakage"
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java
index 731b4ca..91e749e 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/FileSender.java
@@ -220,7 +220,6 @@ private boolean initRangeRequest(final HttpServletRequest req,
 		return true;
 	}
 
-	@SuppressWarnings("unchecked")
 	private static Enumeration<String> getRange(final HttpServletRequest req) {
 		return req.getHeaders(HDR_RANGE);
 	}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
index eee98d4..8c769e6 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Merge.java
@@ -87,7 +87,7 @@ protected void run() throws Exception {
 
 		switch (result.getMergeStatus()) {
 		case ALREADY_UP_TO_DATE:
-			out.println(CLIText.get().alreadyUpToDate);
+			outw.println(CLIText.get().alreadyUpToDate);
 			break;
 		case FAST_FORWARD:
 			outw.println(result.getMergeStatus().toString());
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java
index 2c10cf9..534e6de 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Push.java
@@ -252,7 +252,7 @@ private String safeAbbreviate(ObjectReader reader, ObjectId id) {
 	private void printUpdateLine(final char flag, final String summary,
 			final String srcRef, final String destRef, final String message)
 			throws IOException {
-		out.format(" %c %-17s", valueOf(flag), summary);
+		outw.format(" %c %-17s", valueOf(flag), summary);
 
 		if (srcRef != null)
 			outw.format(" %s ->", abbreviateRef(srcRef, true));
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
index 64e3859..6abbfb0 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Status.java
@@ -43,6 +43,7 @@
 
 package org.eclipse.jgit.pgm;
 
+import java.io.IOException;
 import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -69,10 +70,10 @@ protected void run() throws Exception {
 		boolean firstHeader = true;
 		if (head != null && head.isSymbolic()) {
 			String branch = Repository.shortenRefName(head.getLeaf().getName());
-			out.println(CLIText.formatLine(
+			outw.println(CLIText.formatLine(
 					MessageFormat.format(CLIText.get().onBranch, branch)));
 		} else
-			out.println(CLIText.formatLine(CLIText.get().notOnAnyBranch));
+			outw.println(CLIText.formatLine(CLIText.get().notOnAnyBranch));
 		// List changes
 		org.eclipse.jgit.api.Status status = new Git(db).status().call();
 		Collection<String> added = status.getAdded();
@@ -122,22 +123,24 @@ protected void run() throws Exception {
 		}
 	}
 
-	protected void printSectionHeader(String pattern, Object... arguments) {
-		out.println(CLIText.formatLine(MessageFormat.format(pattern, arguments)));
+	protected void printSectionHeader(String pattern, Object... arguments)
+			throws IOException {
+		outw.println(CLIText.formatLine(MessageFormat
+				.format(pattern, arguments)));
 		if (!pattern.equals(""))
-			out.println(CLIText.formatLine(""));
-		out.flush();
+			outw.println(CLIText.formatLine(""));
+		outw.flush();
 	}
 
-	protected int printList(Collection<String> list) {
+	protected int printList(Collection<String> list) throws IOException {
 		if (!list.isEmpty()) {
 			List<String> sortedList = new ArrayList<String>(list);
 			java.util.Collections.sort(sortedList);
 			for (String filename : sortedList) {
-				out.println(CLIText.formatLine(String.format(
+				outw.println(CLIText.formatLine(String.format(
 						statusFileListFormat, filename)));
 			}
-			out.flush();
+			outw.flush();
 			return list.size();
 		} else
 			return 0;
@@ -146,7 +149,8 @@ protected int printList(Collection<String> list) {
 	protected int printList(String status1, String status2, String status3,
 			Collection<String> list, Collection<String> set1,
 			Collection<String> set2,
-			@SuppressWarnings("unused") Collection<String> set3) {
+			@SuppressWarnings("unused") Collection<String> set3)
+			throws IOException {
 		List<String> sortedList = new ArrayList<String>(list);
 		java.util.Collections.sort(sortedList);
 		for (String filename : sortedList) {
@@ -158,9 +162,9 @@ else if (set2.contains(filename))
 			else
 				// if (set3.contains(filename))
 				prefix = status3;
-			out.println(CLIText.formatLine(String.format(
+			outw.println(CLIText.formatLine(String.format(
 					statusFileListFormatWithPrefix, prefix, filename)));
-			out.flush();
+			outw.flush();
 		}
 		return list.size();
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java
index 243d791..d37f572 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PathCheckoutCommandTest.java
@@ -47,11 +47,13 @@
 import java.io.File;
 import java.io.IOException;
 
+import org.eclipse.jgit.api.errors.JGitInternalException;
 import org.eclipse.jgit.dircache.DirCache;
 import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.errors.NoWorkTreeException;
 import org.eclipse.jgit.lib.ConfigConstants;
 import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.RepositoryState;
 import org.eclipse.jgit.lib.RepositoryTestCase;
 import org.eclipse.jgit.lib.StoredConfig;
 import org.eclipse.jgit.revwalk.RevCommit;
@@ -243,4 +245,23 @@ public void testCheckoutRepository() throws Exception {
 		assertEquals("1", read(test));
 		assertEquals("a", read(test2));
 	}
+
+	@Test(expected = JGitInternalException.class)
+	public void testCheckoutOfConflictingFileShouldThrow()
+			throws Exception {
+		// Setup
+		git.checkout().setCreateBranch(true).setName("conflict")
+				.setStartPoint(initialCommit).call();
+		writeTrashFile(FILE1, "Conflicting");
+		RevCommit conflict = git.commit().setAll(true)
+				.setMessage("Conflicting change").call();
+
+		git.checkout().setName("master").call();
+
+		git.merge().include(conflict).call();
+		assertEquals(RepositoryState.MERGING, db.getRepositoryState());
+
+		// Now check out the conflicting path
+		git.checkout().addPath(FILE1).call();
+	}
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogResolveTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogResolveTest.java
index fe28b47..80cd163 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogResolveTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogResolveTest.java
@@ -152,6 +152,7 @@ public void resolvePreviousBranch() throws Exception {
 			db.resolve("@{-1}@{0}");
 			fail();
 		} catch (RevisionSyntaxException e) {
+			// good
 		}
 		assertEquals(c1.getName(), db.resolve("@{-2}@{0}").getName());
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java
index defd93b..91364ce 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/RepositoryResolveTest.java
@@ -47,14 +47,18 @@
 package org.eclipse.jgit.lib;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.io.IOException;
 
 import org.eclipse.jgit.api.Git;
+import org.eclipse.jgit.errors.AmbiguousObjectException;
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.RevisionSyntaxException;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.junit.Test;
 
@@ -133,9 +137,11 @@ public void testDistance() throws IOException {
 	public void testDistance_past_root() throws IOException {
 		assertEquals("42e4e7c5e507e113ebbb7801b16b52cf867b7ce1",db.resolve("6462e7d8024396b14d7651e2ec11e2bbf07a05c4~1").name());
 		assertNull(db.resolve("6462e7d8024396b14d7651e2ec11e2bbf07a05c4~~"));
+		assertNull(db.resolve("6462e7d8024396b14d7651e2ec11e2bbf07a05c4^^"));
 		assertNull(db.resolve("6462e7d8024396b14d7651e2ec11e2bbf07a05c4~2"));
 		assertNull(db.resolve("6462e7d8024396b14d7651e2ec11e2bbf07a05c4~99"));
 		assertNull(db.resolve("42e4e7c5e507e113ebbb7801b16b52cf867b7ce1~~"));
+		assertNull(db.resolve("42e4e7c5e507e113ebbb7801b16b52cf867b7ce1^^"));
 		assertNull(db.resolve("42e4e7c5e507e113ebbb7801b16b52cf867b7ce1~2"));
 		assertNull(db.resolve("42e4e7c5e507e113ebbb7801b16b52cf867b7ce1~99"));
 		assertEquals("42e4e7c5e507e113ebbb7801b16b52cf867b7ce1",db.resolve("master~6").name());
@@ -289,6 +295,53 @@ public void resolveUpstream() throws Exception {
 		assertEquals("refs/remotes/origin/main", db.simplify("@{upstream}"));
 	}
 
+	@Test
+	public void invalidNames() throws AmbiguousObjectException, IOException {
+		assertTrue(Repository.isValidRefName("x/a"));
+		assertTrue(Repository.isValidRefName("x/a.b"));
+		assertTrue(Repository.isValidRefName("x/a@b"));
+		assertTrue(Repository.isValidRefName("x/a@b{x}"));
+		assertTrue(Repository.isValidRefName("x/a/b"));
+		assertTrue(Repository.isValidRefName("x/a]b")); // odd, yes..
+		assertTrue(Repository.isValidRefName("x/\u00a0")); // unicode is fine,
+															// even hard space
+		assertFalse(Repository.isValidRefName("x/.a"));
+		assertFalse(Repository.isValidRefName("x/a."));
+		assertFalse(Repository.isValidRefName("x/a..b"));
+		assertFalse(Repository.isValidRefName("x//a"));
+		assertFalse(Repository.isValidRefName("x/a/"));
+		assertFalse(Repository.isValidRefName("x/a//b"));
+		assertFalse(Repository.isValidRefName("x/a[b"));
+		assertFalse(Repository.isValidRefName("x/a^b"));
+		assertFalse(Repository.isValidRefName("x/a*b"));
+		assertFalse(Repository.isValidRefName("x/a?b"));
+		assertFalse(Repository.isValidRefName("x/a~1"));
+		assertFalse(Repository.isValidRefName("x/a\\b"));
+		assertFalse(Repository.isValidRefName("x/a\u0000"));
+
+		assertUnparseable(".");
+		assertUnparseable("x@{3");
+		assertUnparseable("x[b");
+		assertUnparseable("x y");
+		assertUnparseable("x.");
+		assertUnparseable(".x");
+		assertUnparseable("a..b");
+		assertUnparseable("x\\b");
+		assertUnparseable("a~b");
+		assertUnparseable("a^b");
+		assertUnparseable("a\u0000");
+	}
+
+	private void assertUnparseable(String s) throws AmbiguousObjectException,
+			IOException {
+		try {
+			db.resolve(s);
+			fail("'" + s + "' should be unparseable");
+		} catch (RevisionSyntaxException e) {
+			// good
+		}
+	}
+
 	private static ObjectId id(String name) {
 		return ObjectId.fromString(name);
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/FileBasedConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/FileBasedConfigTest.java
new file mode 100644
index 0000000..075852a
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/storage/file/FileBasedConfigTest.java
@@ -0,0 +1,162 @@
+/*
+ * Copyright (C) 2012, Marc Strapetz
+ * and other copyright owners as documented in the project's IP log.
+ *
+ * This program and the accompanying materials are made available
+ * under the terms of the Eclipse Distribution License v1.0 which
+ * accompanies this distribution, is reproduced below, and is
+ * available at http://www.eclipse.org/org/documents/edl-v10.php
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ *   copyright notice, this list of conditions and the following
+ *   disclaimer in the documentation and/or other materials provided
+ *   with the distribution.
+ *
+ * - Neither the name of the Eclipse Foundation, Inc. nor the
+ *   names of its contributors may be used to endorse or promote
+ *   products derived from this software without specific prior
+ *   written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package org.eclipse.jgit.storage.file;
+
+import static org.junit.Assert.*;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+import org.eclipse.jgit.errors.ConfigInvalidException;
+import org.eclipse.jgit.util.FS;
+import org.eclipse.jgit.util.FileUtils;
+import org.eclipse.jgit.util.IO;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+public class FileBasedConfigTest {
+
+	private static final String USER = "user";
+
+	private static final String NAME = "name";
+
+	private static final String ALICE = "Alice";
+
+	private static final String BOB = "Bob";
+
+	private static final String CONTENT1 = "[" + USER + "]\n\t" + NAME + " = "
+			+ ALICE + "\n";
+
+	private static final String CONTENT2 = "[" + USER + "]\n\t" + NAME + " = "
+			+ BOB + "\n";
+
+	private final File trash = new File(new File("target"), "trash");
+
+	@After
+	public void tearDown() throws Exception {
+		FileUtils.delete(trash, FileUtils.RECURSIVE | FileUtils.SKIP_MISSING);
+	}
+
+	@Test
+	public void testSystemEncoding() throws IOException, ConfigInvalidException {
+		final File file = createFile(CONTENT1.getBytes());
+		final FileBasedConfig config = new FileBasedConfig(file, FS.DETECTED);
+		config.load();
+		assertEquals(ALICE, config.getString(USER, null, NAME));
+
+		config.setString(USER, null, NAME, BOB);
+		config.save();
+		assertArrayEquals(CONTENT2.getBytes(), IO.readFully(file));
+	}
+
+	@Test
+	public void testUTF8withoutBOM() throws IOException, ConfigInvalidException {
+		final File file = createFile(CONTENT1.getBytes("UTF-8"));
+		final FileBasedConfig config = new FileBasedConfig(file, FS.DETECTED);
+		config.load();
+		assertEquals(ALICE, config.getString(USER, null, NAME));
+
+		config.setString(USER, null, NAME, BOB);
+		config.save();
+		assertArrayEquals(CONTENT2.getBytes(), IO.readFully(file));
+	}
+
+	@Test
+	public void testUTF8withBOM() throws IOException, ConfigInvalidException {
+		final ByteArrayOutputStream bos1 = new ByteArrayOutputStream();
+		bos1.write(0xEF);
+		bos1.write(0xBB);
+		bos1.write(0xBF);
+		bos1.write(CONTENT1.getBytes("UTF-8"));
+
+		final File file = createFile(bos1.toByteArray());
+		final FileBasedConfig config = new FileBasedConfig(file, FS.DETECTED);
+		config.load();
+		assertEquals(ALICE, config.getString(USER, null, NAME));
+
+		config.setString(USER, null, NAME, BOB);
+		config.save();
+
+		final ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
+		bos2.write(0xEF);
+		bos2.write(0xBB);
+		bos2.write(0xBF);
+		bos2.write(CONTENT2.getBytes("UTF-8"));
+		assertArrayEquals(bos2.toByteArray(), IO.readFully(file));
+	}
+
+	@Test
+	public void testLeadingWhitespaces() throws IOException, ConfigInvalidException {
+		final ByteArrayOutputStream bos1 = new ByteArrayOutputStream();
+		bos1.write(" \n\t".getBytes());
+		bos1.write(CONTENT1.getBytes());
+
+		final File file = createFile(bos1.toByteArray());
+		final FileBasedConfig config = new FileBasedConfig(file, FS.DETECTED);
+		config.load();
+		assertEquals(ALICE, config.getString(USER, null, NAME));
+
+		config.setString(USER, null, NAME, BOB);
+		config.save();
+
+		final ByteArrayOutputStream bos2 = new ByteArrayOutputStream();
+		bos2.write(" \n\t".getBytes());
+		bos2.write(CONTENT2.getBytes());
+		assertArrayEquals(bos2.toByteArray(), IO.readFully(file));
+	}
+
+	private File createFile(byte[] content) throws IOException {
+		trash.mkdirs();
+		File f = File.createTempFile(getClass().getName(), null, trash);
+		FileOutputStream os = new FileOutputStream(f, true);
+		try {
+			os.write(content);
+		} finally {
+			os.close();
+		}
+		return f;
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
index d8efbe7..57f47a4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
@@ -64,6 +64,7 @@
 import org.eclipse.jgit.dircache.DirCacheEntry;
 import org.eclipse.jgit.dircache.DirCacheIterator;
 import org.eclipse.jgit.errors.AmbiguousObjectException;
+import org.eclipse.jgit.errors.UnmergedPathException;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Constants;
@@ -284,7 +285,8 @@ protected CheckoutCommand checkoutPaths() throws IOException,
 			startWalk.setRecursive(true);
 			if (!checkoutAllPaths)
 				startWalk.setFilter(PathFilterGroup.createFromStrings(paths));
-			boolean checkoutIndex = startCommit == null && startPoint == null;
+			final boolean checkoutIndex = startCommit == null
+					&& startPoint == null;
 			if (!checkoutIndex)
 				startWalk.addTree(revWalk.parseCommit(getStartPoint())
 						.getTree());
@@ -299,6 +301,11 @@ protected CheckoutCommand checkoutPaths() throws IOException,
 					final FileMode mode = startWalk.getFileMode(0);
 					editor.add(new PathEdit(startWalk.getPathString()) {
 						public void apply(DirCacheEntry ent) {
+							if (checkoutIndex
+									&& ent.getStage() > DirCacheEntry.STAGE_0) {
+								UnmergedPathException e = new UnmergedPathException(ent);
+								throw new JGitInternalException(e.getMessage(), e);
+							}
 							ent.setObjectId(blobId);
 							ent.setFileMode(mode);
 							File file = new File(workTree, ent.getPathString());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java
index 49dc914..9d2babd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/AnyObjectId.java
@@ -510,8 +510,8 @@ public final String getName() {
 
 	/**
 	 * Return an abbreviation (prefix) of this object SHA-1.
-	 *
-	 * This implementation does not guaranteeing uniqueness. Callers should
+	 * <p>
+	 * This implementation does not guarantee uniqueness. Callers should
 	 * instead use {@link ObjectReader#abbreviate(AnyObjectId, int)} to obtain a
 	 * unique abbreviation within the scope of a particular object database.
 	 *
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
index 16f8cdf..76f5378 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
@@ -429,7 +429,12 @@ private Object resolve(final RevWalk rw, final String revstr)
 			case '^':
 				if (rev == null) {
 					if (name == null)
-						name = new String(revChars, done, i);
+						if (done == 0)
+							name = new String(revChars, done, i);
+						else {
+							done = i + 1;
+							break;
+						}
 					rev = parseSimple(rw, name);
 					name = null;
 					if (rev == null)
@@ -471,7 +476,7 @@ private Object resolve(final RevWalk rw, final String revstr)
 								rev = commit.getParent(pnum - 1);
 						}
 						i = j - 1;
-						done = i;
+						done = j;
 						break;
 					case '{':
 						int k;
@@ -512,7 +517,6 @@ private Object resolve(final RevWalk rw, final String revstr)
 						} else
 							throw new IncorrectObjectTypeException(rev,
 									Constants.TYPE_COMMIT);
-
 					}
 				} else {
 					rev = rw.peel(rev);
@@ -526,11 +530,17 @@ private Object resolve(final RevWalk rw, final String revstr)
 						throw new IncorrectObjectTypeException(rev,
 								Constants.TYPE_COMMIT);
 				}
+				done = i + 1;
 				break;
 			case '~':
 				if (rev == null) {
 					if (name == null)
-						name = new String(revChars, done, i);
+						if (done == 0)
+							name = new String(revChars, done, i);
+						else {
+							done = i + 1;
+							break;
+						}
 					rev = parseSimple(rw, name);
 					name = null;
 					if (rev == null)
@@ -568,10 +578,13 @@ private Object resolve(final RevWalk rw, final String revstr)
 					--dist;
 				}
 				i = l - 1;
+				done = l;
 				break;
 			case '@':
 				if (rev != null)
 					throw new RevisionSyntaxException(revstr);
+				if (i + 1 < revChars.length && revChars[i + 1] != '{')
+					continue;
 				int m;
 				String time = null;
 				for (m = i + 2; m < revChars.length; ++m) {
@@ -588,6 +601,8 @@ private Object resolve(final RevWalk rw, final String revstr)
 							// Currently checked out branch, HEAD if
 							// detached
 							name = Constants.HEAD;
+						if (!Repository.isValidRefName("x/" + name))
+							throw new RevisionSyntaxException(revstr);
 						Ref ref = getRef(name);
 						name = null;
 						if (ref == null)
@@ -636,6 +651,8 @@ private Object resolve(final RevWalk rw, final String revstr)
 							name = new String(revChars, done, i);
 						if (name.equals(""))
 							name = Constants.HEAD;
+						if (!Repository.isValidRefName("x/" + name))
+							throw new RevisionSyntaxException(revstr);
 						Ref ref = getRef(name);
 						name = null;
 						if (ref == null)
@@ -680,7 +697,11 @@ private Object resolve(final RevWalk rw, final String revstr)
 			return rev.copy();
 		if (name != null)
 			return name;
+		if (rev == null && done == revstr.length())
+			return null;
 		name = revstr.substring(done);
+		if (!Repository.isValidRefName("x/" + name))
+			throw new RevisionSyntaxException(revstr);
 		if (getRef(name) != null)
 			return name;
 		return resolveSimple(name);
@@ -709,9 +730,11 @@ private ObjectId resolveSimple(final String revstr) throws IOException {
 		if (ObjectId.isId(revstr))
 			return ObjectId.fromString(revstr);
 
-		Ref r = getRefDatabase().getRef(revstr);
-		if (r != null)
-			return r.getObjectId();
+		if (Repository.isValidRefName("x/" + revstr)) {
+			Ref r = getRefDatabase().getRef(revstr);
+			if (r != null)
+				return r.getObjectId();
+		}
 
 		if (AbbreviatedObjectId.isId(revstr))
 			return resolveAbbreviation(revstr);
@@ -1132,6 +1155,8 @@ public static boolean isValidRefName(final String refName) {
 			case '/':
 				if (i == 0 || i == len - 1)
 					return false;
+				if (p == '/')
+					return false;
 				components++;
 				break;
 			case '{':
@@ -1141,6 +1166,7 @@ public static boolean isValidRefName(final String refName) {
 			case '~': case '^': case ':':
 			case '?': case '[': case '*':
 			case '\\':
+			case '\u007F':
 				return false;
 			}
 			p = c;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
index f302536..7ae491b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/file/FileBasedConfig.java
@@ -49,6 +49,7 @@
 
 package org.eclipse.jgit.storage.file;
 
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
@@ -70,8 +71,13 @@
  */
 public class FileBasedConfig extends StoredConfig {
 	private final File configFile;
+
 	private final FS fs;
+
+	private boolean utf8Bom;
+
 	private volatile FileSnapshot snapshot;
+
 	private volatile ObjectId hash;
 
 	/**
@@ -141,7 +147,16 @@ public void load() throws IOException, ConfigInvalidException {
 				else
 					snapshot = newSnapshot;
 			} else {
-				fromText(RawParseUtils.decode(in));
+				final String decoded;
+				if (in.length >= 3 && in[0] == (byte) 0xEF
+						&& in[1] == (byte) 0xBB && in[2] == (byte) 0xBF) {
+					decoded = RawParseUtils.decode(RawParseUtils.UTF8_CHARSET,
+							in, 3, in.length);
+					utf8Bom = true;
+				} else {
+					decoded = RawParseUtils.decode(in);
+				}
+				fromText(decoded);
 				snapshot = newSnapshot;
 				hash = newHash;
 			}
@@ -170,7 +185,19 @@ public void load() throws IOException, ConfigInvalidException {
 	 *             the file could not be written.
 	 */
 	public void save() throws IOException {
-		final byte[] out = Constants.encode(toText());
+		final byte[] out;
+		final String text = toText();
+		if (utf8Bom) {
+			final ByteArrayOutputStream bos = new ByteArrayOutputStream();
+			bos.write(0xEF);
+			bos.write(0xBB);
+			bos.write(0xBF);
+			bos.write(text.getBytes(RawParseUtils.UTF8_CHARSET));
+			out = bos.toByteArray();
+		} else {
+			out = Constants.encode(text);
+		}
+
 		final LockFile lf = new LockFile(getFile(), fs);
 		if (!lf.lock())
 			throw new LockFailedException(getFile());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TrackingRefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TrackingRefUpdate.java
index 3344c3f..d6dcb32 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TrackingRefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TrackingRefUpdate.java
@@ -193,4 +193,21 @@ private RefUpdate.Result decode(ReceiveCommand.Result status) {
 			}
 		}
 	}
+
+	@Override
+	public String toString() {
+		StringBuilder sb = new StringBuilder();
+		sb.append("TrackingRefUpdate[");
+		sb.append(remoteName);
+		sb.append(" -> ");
+		sb.append(localName);
+		if (forceUpdate)
+			sb.append(" (forced)");
+		sb.append(" ");
+		sb.append(oldObjectId == null ? "" : oldObjectId.abbreviate(7).name());
+		sb.append("..");
+		sb.append(newObjectId == null ? "" : newObjectId.abbreviate(7).name());
+		sb.append("]");
+		return sb.toString();
+	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
index 91184ba..89fbeed 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/RawParseUtils.java
@@ -65,6 +65,11 @@
 
 /** Handy utility functions to parse raw object contents. */
 public final class RawParseUtils {
+	/**
+	 * UTF-8 charset constant.
+	 */
+	public static final Charset UTF8_CHARSET = Charset.forName("UTF-8");
+
 	private static final byte[] digits10;
 
 	private static final byte[] digits16;