Merge branch 'master' into stable-4.4

* master:
  Fix javadoc errors and unused imports introduced by ddd0fe25
  RepoCommand: record manifest shallow recommendation in .gitmodules
  RepoCommand: record manifest groups as submodule labels
  Remove the deprecated TestRepository.getClock() method
  Replace use of deprecated method Repository.getRef()
  [findBugs] Prevent potential NPE in
    FileLfsRepository.getOutputStream()
  Better report on client side if push failed due to too large object
  [findBugs] Prevent potential NPE in CloneCommand.init()
  RepoCommand: remove --record-remote-branches
  RepoCommandTest: Improve assertion message for remote branch recording

Change-Id: I4fbce4f84925a933fcc9a48058ed6793f5821b97
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
index 86b87b4..c282df0 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/RepositoryTestCase.java
@@ -406,7 +406,7 @@ protected RevCommit commitFile(String filename, String contents, String branch)
 			String originalBranch = repo.getFullBranch();
 			boolean empty = repo.resolve(Constants.HEAD) == null;
 			if (!empty) {
-				if (repo.getRef(branch) == null)
+				if (repo.findRef(branch) == null)
 					git.branchCreate().setName(branch).call();
 				git.checkout().setName(branch).call();
 			}
diff --git a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
index 07df56d..0a2345f 100644
--- a/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
+++ b/org.eclipse.jgit.junit/src/org/eclipse/jgit/junit/TestRepository.java
@@ -211,17 +211,6 @@ public Date getDate() {
 		return new Date(mockSystemReader.getCurrentTime());
 	}
 
-	/**
-	 * @return current date.
-	 *
-	 * @deprecated Use {@link #getDate()} instead.
-	 */
-	@Deprecated
-	public Date getClock() {
-		// Remove once Gitiles and Gerrit are using the updated JGit.
-		return getDate();
-	}
-
 	/** @return timezone used for default identities. */
 	public TimeZone getTimeZone() {
 		return mockSystemReader.getTimeZone();
@@ -501,7 +490,7 @@ public RevCommit update(String ref, CommitBuilder to) throws Exception {
 	 */
 	public CommitBuilder amendRef(String ref) throws Exception {
 		String name = normalizeRef(ref);
-		Ref r = db.getRef(name);
+		Ref r = db.exactRef(name);
 		if (r == null)
 			throw new IOException("Not a ref: " + ref);
 		return amend(pool.parseCommit(r.getObjectId()), branch(name).commit());
@@ -703,7 +692,7 @@ public RevCommit cherryPick(AnyObjectId id) throws Exception {
 		RevCommit parent = commit.getParent(0);
 		pool.parseHeaders(parent);
 
-		Ref headRef = db.getRef(Constants.HEAD);
+		Ref headRef = db.exactRef(Constants.HEAD);
 		if (headRef == null)
 			throw new IOException("Missing HEAD");
 		RevCommit head = pool.parseCommit(headRef.getObjectId());
@@ -1025,7 +1014,7 @@ public class CommitBuilder {
 		CommitBuilder(BranchBuilder b) throws Exception {
 			branch = b;
 
-			Ref ref = db.getRef(branch.ref);
+			Ref ref = db.exactRef(branch.ref);
 			if (ref != null && ref.getObjectId() != null)
 				parent(pool.parseCommit(ref.getObjectId()));
 		}
diff --git a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsRepository.java b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsRepository.java
index 2e71c04..dd70a36 100644
--- a/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsRepository.java
+++ b/org.eclipse.jgit.lfs.server/src/org/eclipse/jgit/lfs/server/fs/FileLfsRepository.java
@@ -147,7 +147,10 @@ ReadableByteChannel getReadChannel(AnyLongObjectId id)
 	AtomicObjectOutputStream getOutputStream(AnyLongObjectId id)
 			throws IOException {
 		Path path = getPath(id);
-		Files.createDirectories(path.getParent());
+		Path parent = path.getParent();
+		if (parent != null) {
+			Files.createDirectories(parent);
+		}
 		return new AtomicObjectOutputStream(path, id);
 	}
 
diff --git a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
index fc412ba..abe04b8 100644
--- a/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
+++ b/org.eclipse.jgit.pgm/resources/org/eclipse/jgit/pgm/internal/CLIText.properties
@@ -211,7 +211,6 @@
 updating=Updating {0}..{1}
 usage_Aggressive=This option will cause gc to more aggressively optimize the repository at the expense of taking much more time
 usage_bareClone=Make a bare Git repository. That is, instead of creating [DIRECTORY] and placing the administrative files in [DIRECTORY]/.git, make the [DIRECTORY] itself the $GIT_DIR.
-usage_branches=Set branch field in .gitmodules
 usage_Blame=Show what revision and author last modified each line
 usage_CommandLineClientForamazonsS3Service=Command line client for Amazon's S3 service
 usage_CommitAll=commit all modified and deleted files
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java
index bf6ee3a..5f3740c 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Branch.java
@@ -169,7 +169,7 @@ protected void run() throws Exception {
 			if (rename) {
 				String src, dst;
 				if (otherBranch == null) {
-					final Ref head = db.getRef(Constants.HEAD);
+					final Ref head = db.exactRef(Constants.HEAD);
 					if (head != null && head.isSymbolic()) {
 						src = head.getLeaf().getName();
 					} else {
@@ -178,7 +178,7 @@ protected void run() throws Exception {
 					dst = branch;
 				} else {
 					src = branch;
-					final Ref old = db.getRef(src);
+					final Ref old = db.findRef(src);
 					if (old == null)
 						throw die(MessageFormat.format(CLIText.get().doesNotExist, src));
 					if (!old.getName().startsWith(Constants.R_HEADS))
@@ -204,7 +204,7 @@ protected void run() throws Exception {
 				} else {
 					startBranch = Constants.HEAD;
 				}
-				Ref startRef = db.getRef(startBranch);
+				Ref startRef = db.findRef(startBranch);
 				ObjectId startAt = db.resolve(startBranch + "^0"); //$NON-NLS-1$
 				if (startRef != null) {
 					startBranch = startRef.getName();
@@ -243,7 +243,7 @@ protected void run() throws Exception {
 	}
 
 	private void list() throws Exception {
-		Ref head = db.getRef(Constants.HEAD);
+		Ref head = db.exactRef(Constants.HEAD);
 		// This can happen if HEAD is stillborn
 		if (head != null) {
 			String current = head.getLeaf().getName();
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
index 38d8d70..2cfbd86 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Commit.java
@@ -95,7 +95,7 @@ protected void run() throws NoHeadException, NoMessageException,
 					commitCmd.setOnly(p);
 			commitCmd.setAmend(amend);
 			commitCmd.setAll(all);
-			Ref head = db.getRef(Constants.HEAD);
+			Ref head = db.exactRef(Constants.HEAD);
 			if (head == null) {
 				throw die(CLIText.get().onBranchToBeBorn);
 			}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java
index 6947cdd..62e7728 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Log.java
@@ -228,7 +228,7 @@ protected void run() throws Exception {
 	}
 
 	private void addNoteMap(String notesRef) throws IOException {
-		Ref notes = db.getRef(notesRef);
+		Ref notes = db.exactRef(notesRef);
 		if (notes == null)
 			return;
 		RevCommit notesCommit = argWalk.parseCommit(notes.getObjectId());
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 e739b58..485efc5 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
@@ -114,7 +114,7 @@ protected void run() throws Exception {
 		}
 
 		// determine the other revision we want to merge with HEAD
-		final Ref srcRef = db.getRef(ref);
+		final Ref srcRef = db.findRef(ref);
 		final ObjectId src = db.resolve(ref + "^{commit}"); //$NON-NLS-1$
 		if (src == null)
 			throw die(MessageFormat.format(
@@ -209,7 +209,7 @@ protected void run() throws Exception {
 	}
 
 	private Ref getOldHead() throws IOException {
-		Ref oldHead = db.getRef(Constants.HEAD);
+		Ref oldHead = db.exactRef(Constants.HEAD);
 		if (oldHead == null) {
 			throw die(CLIText.get().onBranchToBeBorn);
 		}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java
index ea59527..bec5003 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Repo.java
@@ -58,16 +58,12 @@ class Repo extends TextBuiltin {
 	@Argument(required = true, metaVar = "metaVar_path", usage = "usage_pathToXml")
 	private String path;
 
-	@Option(name = "--record-remote-branch", usage = "usage_branches")
-	private boolean branches;
-
 	@Override
 	protected void run() throws Exception {
 		new RepoCommand(db)
 			.setURI(uri)
 			.setPath(path)
 			.setGroups(groups)
-			.setRecordRemoteBranch(branches)
 			.call();
 	}
 }
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 6a63221..de3df80 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
@@ -204,7 +204,7 @@ private void printPorcelainLine(char x, char y, String path)
 	private void printLongStatus(org.eclipse.jgit.api.Status status)
 			throws IOException {
 		// Print current branch name
-		final Ref head = db.getRef(Constants.HEAD);
+		final Ref head = db.exactRef(Constants.HEAD);
 		if (head != null && head.isSymbolic()) {
 			String branch = Repository.shortenRefName(head.getLeaf().getName());
 			outw.println(CLIText.formatLine(MessageFormat.format(
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
index 725ebc0..a4a699e 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ResetCommandTest.java
@@ -596,7 +596,7 @@ private boolean inIndex(String path) throws IOException {
 	 * @throws IOException
 	 */
 	private void assertSameAsHead(Ref ref) throws IOException {
-		Ref headRef = db.getRef(Constants.HEAD);
+		Ref headRef = db.exactRef(Constants.HEAD);
 		assertEquals(headRef.getName(), ref.getName());
 		assertEquals(headRef.getObjectId(), ref.getObjectId());
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
index 2cec34b..ccd15d0 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/RepoCommandTest.java
@@ -44,6 +44,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
 import java.io.BufferedReader;
@@ -743,14 +744,107 @@ public void testRecordRemoteBranch() throws Exception {
 				FileBasedConfig c = new FileBasedConfig(gitmodules,
 						FS.DETECTED);
 				c.load();
-				assertEquals("standard branches work", "master",
+				assertEquals("Recording remote branches should work for short branch descriptions", "master",
 						c.getString("submodule", "with-branch", "branch"));
-				assertEquals("long branches work", "refs/heads/master",
+				assertEquals("Recording remote branches should work for full ref specs", "refs/heads/master",
 						c.getString("submodule", "with-long-branch", "branch"));
 			}
 		}
 	}
 
+
+	@Test
+	public void testRecordSubmoduleLabels() throws Exception {
+		try (
+				Repository remoteDb = createBareRepository();
+				Repository tempDb = createWorkRepository()) {
+			StringBuilder xmlContent = new StringBuilder();
+			xmlContent
+				.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
+				.append("<manifest>")
+				.append("<remote name=\"remote1\" fetch=\".\" />")
+				.append("<default revision=\"master\" remote=\"remote1\" />")
+				.append("<project path=\"test\" ")
+					.append("revision=\"master\" ")
+					.append("name=\"").append(notDefaultUri).append("\" ")
+					.append("groups=\"a1,a2\" />")
+				.append("</manifest>");
+			JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
+				xmlContent.toString());
+
+			RepoCommand command = new RepoCommand(remoteDb);
+			command.setPath(tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
+				.setURI(rootUri)
+				.setRecordSubmoduleLabels(true)
+				.call();
+			// Clone it
+			File directory = createTempDirectory("testBareRepo");
+			try (Repository localDb = Git.cloneRepository()
+					.setDirectory(directory)
+					.setURI(remoteDb.getDirectory().toURI().toString()).call()
+					.getRepository();) {
+				// The .gitattributes file should exist
+				File gitattributes = new File(localDb.getWorkTree(),
+					".gitattributes");
+				assertTrue("The .gitattributes file should exist",
+						gitattributes.exists());
+				try (BufferedReader reader = new BufferedReader(
+						new FileReader(gitattributes));) {
+					String content = reader.readLine();
+					assertEquals(".gitattributes content should be as expected",
+						"/test a1 a2", content);
+				}
+			}
+		}
+	}
+
+	@Test
+	public void testRecordShallowRecommendation() throws Exception {
+		try (
+				Repository remoteDb = createBareRepository();
+				Repository tempDb = createWorkRepository()) {
+			StringBuilder xmlContent = new StringBuilder();
+			xmlContent
+				.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n")
+				.append("<manifest>")
+				.append("<remote name=\"remote1\" fetch=\".\" />")
+				.append("<default revision=\"master\" remote=\"remote1\" />")
+				.append("<project path=\"shallow-please\" ")
+					.append("name=\"").append(defaultUri).append("\" ")
+					.append("clone-depth=\"1\" />")
+				.append("<project path=\"non-shallow\" ")
+					.append("name=\"").append(defaultUri).append("\" />")
+				.append("</manifest>");
+			JGitTestUtil.writeTrashFile(tempDb, "manifest.xml",
+				xmlContent.toString());
+
+			RepoCommand command = new RepoCommand(remoteDb);
+			command.setPath(tempDb.getWorkTree().getAbsolutePath() + "/manifest.xml")
+				.setURI(rootUri)
+				.setRecommendShallow(true)
+				.call();
+			// Clone it
+			File directory = createTempDirectory("testBareRepo");
+			try (Repository localDb = Git.cloneRepository()
+					.setDirectory(directory)
+					.setURI(remoteDb.getDirectory().toURI().toString()).call()
+					.getRepository();) {
+				// The .gitmodules file should exist
+				File gitmodules = new File(localDb.getWorkTree(),
+						".gitmodules");
+				assertTrue("The .gitmodules file should exist",
+						gitmodules.exists());
+				FileBasedConfig c = new FileBasedConfig(gitmodules,
+						FS.DETECTED);
+				c.load();
+				assertEquals("Recording shallow configuration should work", "true",
+						c.getString("submodule", "shallow-please", "shallow"));
+				assertNull("Recording non shallow configuration should work",
+						c.getString("submodule", "non-shallow", "shallow"));
+			}
+		}
+	}
+
 	@Test
 	public void testRemoteRevision() throws Exception {
 		StringBuilder xmlContent = new StringBuilder();
diff --git a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
index f7d9374..b71e48b 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -314,6 +314,8 @@
 indexSignatureIsInvalid=Index signature is invalid: {0}
 indexWriteException=Modified index could not be written
 initFailedBareRepoDifferentDirs=When initializing a bare repo with directory {0} and separate git-dir {1} specified both folders must point to the same location
+initFailedDirIsNoDirectory=Cannot set directory to ''{0}'' which is not a directory
+initFailedGitDirIsNoDirectory=Cannot set git-dir to ''{0}'' which is not a directory
 initFailedNonBareRepoSameDirs=When initializing a non-bare repo with directory {0} and separate git-dir {1} specified both folders should not point to the same location
 inMemoryBufferLimitExceeded=In-memory buffer limit exceeded
 inputDidntMatchLength=Input did not match supplied length. {0} bytes are missing.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddNoteCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddNoteCommand.java
index 9cf8881..4235e37 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/AddNoteCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/AddNoteCommand.java
@@ -87,7 +87,7 @@ public Note call() throws GitAPIException {
 		RevCommit notesCommit = null;
 		try (RevWalk walk = new RevWalk(repo);
 				ObjectInserter inserter = repo.newObjectInserter()) {
-			Ref ref = repo.getRef(notesRef);
+			Ref ref = repo.findRef(notesRef);
 			// if we have a notes ref, use it
 			if (ref != null) {
 				notesCommit = walk.parseCommit(ref.getObjectId());
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 6c80289..65508ef 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CheckoutCommand.java
@@ -223,7 +223,7 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
 				}
 			}
 
-			Ref headRef = repo.getRef(Constants.HEAD);
+			Ref headRef = repo.exactRef(Constants.HEAD);
 			if (headRef == null) {
 				// TODO Git CLI supports checkout from unborn branch, we should
 				// also allow this
@@ -242,7 +242,7 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
 								JGitText.get().checkoutUnexpectedResult,
 								r.name()));
 					this.status = CheckoutResult.NOT_TRIED_RESULT;
-					return repo.getRef(Constants.HEAD);
+					return repo.exactRef(Constants.HEAD);
 				}
 				branch = getStartPointObjectId();
 			} else {
@@ -277,7 +277,7 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
 			} finally {
 				dc.unlock();
 			}
-			Ref ref = repo.getRef(name);
+			Ref ref = repo.findRef(name);
 			if (ref != null && !ref.getName().startsWith(Constants.R_HEADS))
 				ref = null;
 			String toName = Repository.shortenRefName(name);
@@ -289,7 +289,7 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
 				updateResult = refUpdate.link(ref.getName());
 			else if (orphan) {
 				updateResult = refUpdate.link(getBranchName());
-				ref = repo.getRef(Constants.HEAD);
+				ref = repo.exactRef(Constants.HEAD);
 			} else {
 				refUpdate.setNewObjectId(newCommit);
 				updateResult = refUpdate.forceUpdate();
@@ -519,7 +519,7 @@ private void processOptions() throws InvalidRefNameException,
 					.get().branchNameInvalid, name == null ? "<null>" : name)); //$NON-NLS-1$
 
 		if (orphan) {
-			Ref refToCheck = repo.getRef(getBranchName());
+			Ref refToCheck = repo.exactRef(getBranchName());
 			if (refToCheck != null)
 				throw new RefAlreadyExistsException(MessageFormat.format(
 						JGitText.get().refAlreadyExists, name));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
index d6e930a..e82a697 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CherryPickCommand.java
@@ -126,7 +126,7 @@ public CherryPickResult call() throws GitAPIException, NoMessageException,
 		try (RevWalk revWalk = new RevWalk(repo)) {
 
 			// get the head commit
-			Ref headRef = repo.getRef(Constants.HEAD);
+			Ref headRef = repo.exactRef(Constants.HEAD);
 			if (headRef == null)
 				throw new NoHeadException(
 						JGitText.get().commitOnRepoWithoutHEADCurrentlyNotSupported);
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 2ac8729..ff15fd0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CloneCommand.java
@@ -155,6 +155,7 @@ private Repository init(URIish u) throws GitAPIException {
 		command.setBare(bare);
 		if (directory == null && gitDir == null)
 			directory = new File(u.getHumanishName(), Constants.DOT_GIT);
+		validateDirs(directory, gitDir, bare);
 		if (directory != null && directory.exists()
 				&& directory.listFiles().length != 0)
 			throw new JGitInternalException(MessageFormat.format(
@@ -511,6 +512,15 @@ public CloneCommand setNoCheckout(boolean noCheckout) {
 	private static void validateDirs(File directory, File gitDir, boolean bare)
 			throws IllegalStateException {
 		if (directory != null) {
+			if (directory.exists() && !directory.isDirectory()) {
+				throw new IllegalStateException(MessageFormat.format(
+						JGitText.get().initFailedDirIsNoDirectory, directory));
+			}
+			if (gitDir != null && gitDir.exists() && !gitDir.isDirectory()) {
+				throw new IllegalStateException(MessageFormat.format(
+						JGitText.get().initFailedGitDirIsNoDirectory,
+						gitDir));
+			}
 			if (bare) {
 				if (gitDir != null && !gitDir.equals(directory))
 					throw new IllegalStateException(MessageFormat.format(
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
index e54169a..561319c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CommitCommand.java
@@ -195,7 +195,7 @@ public RevCommit call() throws GitAPIException, NoHeadException,
 				}
 			}
 
-			Ref head = repo.getRef(Constants.HEAD);
+			Ref head = repo.exactRef(Constants.HEAD);
 			if (head == null)
 				throw new NoHeadException(
 						JGitText.get().commitOnRepoWithoutHEADCurrentlyNotSupported);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/CreateBranchCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/CreateBranchCommand.java
index a664660..69d82bc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CreateBranchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CreateBranchCommand.java
@@ -125,7 +125,7 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
 		checkCallable();
 		processOptions();
 		try (RevWalk revWalk = new RevWalk(repo)) {
-			Ref refToCheck = repo.getRef(name);
+			Ref refToCheck = repo.findRef(name);
 			boolean exists = refToCheck != null
 					&& refToCheck.getName().startsWith(Constants.R_HEADS);
 			if (!force && exists)
@@ -135,7 +135,7 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
 			ObjectId startAt = getStartPointObjectId();
 			String startPointFullName = null;
 			if (startPoint != null) {
-				Ref baseRef = repo.getRef(startPoint);
+				Ref baseRef = repo.findRef(startPoint);
 				if (baseRef != null)
 					startPointFullName = baseRef.getName();
 			}
@@ -207,7 +207,7 @@ public Ref call() throws GitAPIException, RefAlreadyExistsException,
 						.get().createBranchUnexpectedResult, updateResult
 						.name()));
 
-			Ref result = repo.getRef(name);
+			Ref result = repo.findRef(name);
 			if (result == null)
 				throw new JGitInternalException(
 						JGitText.get().createBranchFailedUnknownReason);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DeleteBranchCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DeleteBranchCommand.java
index 61beb2f..ecc1ce5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DeleteBranchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DeleteBranchCommand.java
@@ -114,7 +114,7 @@ public List<String> call() throws GitAPIException,
 					for (String branchName : branchNames) {
 						if (branchName == null)
 							continue;
-						Ref currentRef = repo.getRef(branchName);
+						Ref currentRef = repo.findRef(branchName);
 						if (currentRef == null)
 							continue;
 
@@ -130,7 +130,7 @@ public List<String> call() throws GitAPIException,
 			for (String branchName : branchNames) {
 				if (branchName == null)
 					continue;
-				Ref currentRef = repo.getRef(branchName);
+				Ref currentRef = repo.findRef(branchName);
 				if (currentRef == null)
 					continue;
 				String fullName = currentRef.getName();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/DeleteTagCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/DeleteTagCommand.java
index ae511c6..3aeec48 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DeleteTagCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DeleteTagCommand.java
@@ -90,7 +90,7 @@ public List<String> call() throws GitAPIException {
 			for (String tagName : tags) {
 				if (tagName == null)
 					continue;
-				Ref currentRef = repo.getRef(tagName);
+				Ref currentRef = repo.findRef(tagName);
 				if (currentRef == null)
 					continue;
 				String fullName = currentRef.getName();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ListBranchCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ListBranchCommand.java
index 904c74f..efcfd16 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ListBranchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ListBranchCommand.java
@@ -108,7 +108,7 @@ public List<Ref> call() throws GitAPIException {
 			Collection<Ref> refs = new ArrayList<Ref>();
 
 			// Also return HEAD if it's detached
-			Ref head = repo.getRef(Constants.HEAD);
+			Ref head = repo.exactRef(Constants.HEAD);
 			if (head != null && head.getLeaf().getName().equals(Constants.HEAD))
 				refs.add(head);
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ListNotesCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ListNotesCommand.java
index 796ac79..ff963ed 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ListNotesCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ListNotesCommand.java
@@ -82,7 +82,7 @@ public List<Note> call() throws GitAPIException {
 		List<Note> notes = new ArrayList<Note>();
 		NoteMap map = NoteMap.newEmptyMap();
 		try (RevWalk walk = new RevWalk(repo)) {
-			Ref ref = repo.getRef(notesRef);
+			Ref ref = repo.findRef(notesRef);
 			// if we have a notes ref, use it
 			if (ref != null) {
 				RevCommit notesCommit = walk.parseCommit(ref.getObjectId());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
index bfe90a3..38b1097 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
@@ -231,7 +231,7 @@ public MergeResult call() throws GitAPIException, NoHeadException,
 		RevWalk revWalk = null;
 		DirCacheCheckout dco = null;
 		try {
-			Ref head = repo.getRef(Constants.HEAD);
+			Ref head = repo.exactRef(Constants.HEAD);
 			if (head == null)
 				throw new NoHeadException(
 						JGitText.get().commitOnRepoWithoutHEADCurrentlyNotSupported);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
index f5b82bd..0a49f78 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PushCommand.java
@@ -55,6 +55,7 @@
 import org.eclipse.jgit.api.errors.InvalidRemoteException;
 import org.eclipse.jgit.api.errors.JGitInternalException;
 import org.eclipse.jgit.errors.NotSupportedException;
+import org.eclipse.jgit.errors.TooLargeObjectInPackException;
 import org.eclipse.jgit.errors.TooLargePackException;
 import org.eclipse.jgit.errors.TransportException;
 import org.eclipse.jgit.internal.JGitText;
@@ -130,7 +131,7 @@ public Iterable<PushResult> call() throws GitAPIException,
 				refSpecs.addAll(config.getPushRefSpecs());
 			}
 			if (refSpecs.isEmpty()) {
-				Ref head = repo.getRef(Constants.HEAD);
+				Ref head = repo.exactRef(Constants.HEAD);
 				if (head != null && head.isSymbolic())
 					refSpecs.add(new RefSpec(head.getLeaf().getName()));
 			}
@@ -160,6 +161,9 @@ public Iterable<PushResult> call() throws GitAPIException,
 				} catch (TooLargePackException e) {
 					throw new org.eclipse.jgit.api.errors.TooLargePackException(
 							e.getMessage(), e);
+				} catch (TooLargeObjectInPackException e) {
+					throw new org.eclipse.jgit.api.errors.TooLargeObjectInPackException(
+							e.getMessage(), e);
 				} catch (TransportException e) {
 					throw new org.eclipse.jgit.api.errors.TransportException(
 							e.getMessage(), e);
@@ -344,7 +348,7 @@ public PushCommand add(String nameOrSpec) {
 		} else {
 			Ref src;
 			try {
-				src = repo.getRef(nameOrSpec);
+				src = repo.findRef(nameOrSpec);
 			} catch (IOException e) {
 				throw new JGitInternalException(
 						JGitText.get().exceptionCaughtDuringExecutionOfPushCommand,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
index 643ec7a..2d6a76b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
@@ -419,7 +419,7 @@ private boolean autoStashApply() throws IOException, GitAPIException {
 
 	private void updateStashRef(ObjectId commitId, PersonIdent refLogIdent,
 			String refLogMessage) throws IOException {
-		Ref currentRef = repo.getRef(Constants.R_STASH);
+		Ref currentRef = repo.exactRef(Constants.R_STASH);
 		RefUpdate refUpdate = repo.updateRef(Constants.R_STASH);
 		refUpdate.setNewObjectId(commitId);
 		refUpdate.setRefLogIdent(refLogIdent);
@@ -750,7 +750,7 @@ private RevCommit doSquashFixup(boolean isSquash, RevCommit commitToPick,
 
 	private void resetSoftToParent() throws IOException,
 			GitAPIException, CheckoutConflictException {
-		Ref ref = repo.getRef(Constants.ORIG_HEAD);
+		Ref ref = repo.exactRef(Constants.ORIG_HEAD);
 		ObjectId orig_head = ref == null ? null : ref.getObjectId();
 		try {
 			// we have already commited the cherry-picked commit.
@@ -1207,7 +1207,7 @@ private static String getHeadName(Ref head) {
 	}
 
 	private Ref getHead() throws IOException, RefNotFoundException {
-		Ref head = repo.getRef(Constants.HEAD);
+		Ref head = repo.exactRef(Constants.HEAD);
 		if (head == null || head.getObjectId() == null)
 			throw new RefNotFoundException(MessageFormat.format(
 					JGitText.get().refNotResolved, Constants.HEAD));
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoveNoteCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoveNoteCommand.java
index a526c27..1c4880c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoveNoteCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoveNoteCommand.java
@@ -85,7 +85,7 @@ public Note call() throws GitAPIException {
 				ObjectInserter inserter = repo.newObjectInserter()) {
 			NoteMap map = NoteMap.newEmptyMap();
 			RevCommit notesCommit = null;
-			Ref ref = repo.getRef(notesRef);
+			Ref ref = repo.exactRef(notesRef);
 			// if we have a notes ref, use it
 			if (ref != null) {
 				notesCommit = walk.parseCommit(ref.getObjectId());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java
index 0731dd4..044a486 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RenameBranchCommand.java
@@ -107,11 +107,11 @@ public Ref call() throws GitAPIException, RefNotFoundException, InvalidRefNameEx
 		try {
 			String fullOldName;
 			String fullNewName;
-			if (repo.getRef(newName) != null)
+			if (repo.findRef(newName) != null)
 				throw new RefAlreadyExistsException(MessageFormat.format(
 						JGitText.get().refAlreadyExists1, newName));
 			if (oldName != null) {
-				Ref ref = repo.getRef(oldName);
+				Ref ref = repo.findRef(oldName);
 				if (ref == null)
 					throw new RefNotFoundException(MessageFormat.format(
 							JGitText.get().refNotResolved, oldName));
@@ -186,7 +186,7 @@ public Ref call() throws GitAPIException, RefNotFoundException, InvalidRefNameEx
 				repoConfig.save();
 			}
 
-			Ref resultRef = repo.getRef(newName);
+			Ref resultRef = repo.findRef(newName);
 			if (resultRef == null)
 				throw new JGitInternalException(
 						JGitText.get().renameBranchFailedUnknownReason);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
index 4c91e6c..e385a5d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
@@ -171,7 +171,7 @@ public Ref call() throws GitAPIException, CheckoutConflictException {
 				// reset [commit] -- paths
 				resetIndexForPaths(commitTree);
 				setCallable(false);
-				return repo.getRef(Constants.HEAD);
+				return repo.exactRef(Constants.HEAD);
 			}
 
 			final Ref result;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java
index 8015773..9d79ed0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java
@@ -129,7 +129,7 @@ public RevCommit call() throws NoMessageException, UnmergedPathsException,
 		try (RevWalk revWalk = new RevWalk(repo)) {
 
 			// get the head commit
-			Ref headRef = repo.getRef(Constants.HEAD);
+			Ref headRef = repo.exactRef(Constants.HEAD);
 			if (headRef == null)
 				throw new NoHeadException(
 						JGitText.get().commitOnRepoWithoutHEADCurrentlyNotSupported);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ShowNoteCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ShowNoteCommand.java
index 82db881..168ea51 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ShowNoteCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ShowNoteCommand.java
@@ -79,7 +79,7 @@ public Note call() throws GitAPIException {
 		NoteMap map = NoteMap.newEmptyMap();
 		RevCommit notesCommit = null;
 		try (RevWalk walk = new RevWalk(repo)) {
-			Ref ref = repo.getRef(notesRef);
+			Ref ref = repo.exactRef(notesRef);
 			// if we have a notes ref, use it
 			if (ref != null) {
 				notesCommit = walk.parseCommit(ref.getObjectId());
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java
index ef32ac9..ee9b7fc 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java
@@ -206,7 +206,7 @@ private void updateStashRef(ObjectId commitId, PersonIdent refLogIdent,
 			String refLogMessage) throws IOException {
 		if (ref == null)
 			return;
-		Ref currentRef = repo.getRef(ref);
+		Ref currentRef = repo.findRef(ref);
 		RefUpdate refUpdate = repo.updateRef(ref);
 		refUpdate.setNewObjectId(commitId);
 		refUpdate.setRefLogIdent(refLogIdent);
@@ -220,7 +220,7 @@ private void updateStashRef(ObjectId commitId, PersonIdent refLogIdent,
 
 	private Ref getHead() throws GitAPIException {
 		try {
-			Ref head = repo.getRef(Constants.HEAD);
+			Ref head = repo.exactRef(Constants.HEAD);
 			if (head == null || head.getObjectId() == null)
 				throw new NoHeadException(JGitText.get().headRequiredToStash);
 			return head;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java
index f6903be..6e1d0f2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java
@@ -118,7 +118,7 @@ public StashDropCommand setAll(final boolean all) {
 
 	private Ref getRef() throws GitAPIException {
 		try {
-			return repo.getRef(R_STASH);
+			return repo.exactRef(R_STASH);
 		} catch (IOException e) {
 			throw new InvalidRefNameException(MessageFormat.format(
 					JGitText.get().cannotRead, R_STASH), e);
@@ -236,7 +236,7 @@ public ObjectId call() throws GitAPIException {
 		updateRef(stashRef, entryId);
 
 		try {
-			Ref newStashRef = repo.getRef(R_STASH);
+			Ref newStashRef = repo.exactRef(R_STASH);
 			return newStashRef != null ? newStashRef.getObjectId() : null;
 		} catch (IOException e) {
 			throw new InvalidRefNameException(MessageFormat.format(
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashListCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashListCommand.java
index 59a83aa..aedc9a6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashListCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashListCommand.java
@@ -81,7 +81,7 @@ public Collection<RevCommit> call() throws GitAPIException,
 		checkCallable();
 
 		try {
-			if (repo.getRef(Constants.R_STASH) == null)
+			if (repo.exactRef(Constants.R_STASH) == null)
 				return Collections.emptyList();
 		} catch (IOException e) {
 			throw new InvalidRefNameException(MessageFormat.format(
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java
index e7fe71a..024f0be 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleSyncCommand.java
@@ -101,7 +101,7 @@ public SubmoduleSyncCommand addPath(final String path) {
 	 * @throws IOException
 	 */
 	protected String getHeadBranch(final Repository subRepo) throws IOException {
-		Ref head = subRepo.getRef(Constants.HEAD);
+		Ref head = subRepo.exactRef(Constants.HEAD);
 		if (head != null && head.isSymbolic())
 			return Repository.shortenRefName(head.getLeaf().getName());
 		else
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java
index ca98ced..39dd42c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java
@@ -184,7 +184,7 @@ private Ref updateTagRef(ObjectId tagId, RevWalk revWalk,
 		switch (updateResult) {
 		case NEW:
 		case FORCED:
-			return repo.getRef(refName);
+			return repo.exactRef(refName);
 		case LOCK_FAILURE:
 			throw new ConcurrentRefUpdateException(
 					JGitText.get().couldNotLockHEAD, tagRef.getRef(),
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TooLargeObjectInPackException.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TooLargeObjectInPackException.java
new file mode 100644
index 0000000..08c25c2
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/errors/TooLargeObjectInPackException.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2016, Matthias Sohn <matthias.sohn@sap.com> 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.api.errors;
+
+/**
+ * Exception thrown when the server rejected a too large pack
+ *
+ * @since 4.4
+ */
+public class TooLargeObjectInPackException extends TransportException {
+	private static final long serialVersionUID = 1L;
+
+	/**
+	 * @param msg
+	 *            message describing the transport failure.
+	 */
+	public TooLargeObjectInPackException(String msg) {
+		super(msg);
+	}
+
+	/**
+	 * @param msg
+	 *            message describing the transport exception.
+	 * @param cause
+	 *            why the transport failed.
+	 */
+	public TooLargeObjectInPackException(String msg, Throwable cause) {
+		super(msg, cause);
+	}
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/errors/TooLargeObjectInPackException.java b/org.eclipse.jgit/src/org/eclipse/jgit/errors/TooLargeObjectInPackException.java
index 79515fc..b5b1af5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/errors/TooLargeObjectInPackException.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/errors/TooLargeObjectInPackException.java
@@ -43,13 +43,13 @@
 
 package org.eclipse.jgit.errors;
 
-import java.io.IOException;
 import java.text.MessageFormat;
 
 import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.transport.URIish;
 
 /** Thrown when PackParser finds an object larger than a predefined limit */
-public class TooLargeObjectInPackException extends IOException {
+public class TooLargeObjectInPackException extends TransportException {
 	private static final long serialVersionUID = 1L;
 
 	/**
@@ -79,4 +79,17 @@ public TooLargeObjectInPackException(long objectSize,
 		super(MessageFormat.format(JGitText.get().receivePackObjectTooLarge2,
 				Long.valueOf(objectSize), Long.valueOf(maxObjectSizeLimit)));
 	}
+
+	/**
+	 * Construct a too large object in pack exception.
+	 *
+	 * @param uri
+	 *            URI used for transport
+	 * @param s
+	 *            message
+	 * @since 4.4
+	 */
+	public TooLargeObjectInPackException(URIish uri, String s) {
+		super(uri.setPass(null) + ": " + s); //$NON-NLS-1$
+	}
 }
\ No newline at end of file
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
index 796b422..2370ae1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
@@ -192,6 +192,8 @@ public void startElement(
 					attributes.getValue("revision"), //$NON-NLS-1$
 					attributes.getValue("remote"), //$NON-NLS-1$
 					attributes.getValue("groups")); //$NON-NLS-1$
+			currentProject.setRecommendShallow(
+				attributes.getValue("clone-depth")); //$NON-NLS-1$
 		} else if ("remote".equals(qName)) { //$NON-NLS-1$
 			String alias = attributes.getValue("alias"); //$NON-NLS-1$
 			String fetch = attributes.getValue("fetch"); //$NON-NLS-1$
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
index ee937f5..ca976a1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
@@ -53,6 +53,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 import org.eclipse.jgit.annotations.Nullable;
 import org.eclipse.jgit.api.Git;
@@ -110,6 +111,8 @@ public class RepoCommand extends GitCommand<RevCommit> {
 	private String branch;
 	private String targetBranch = Constants.HEAD;
 	private boolean recordRemoteBranch = false;
+	private boolean recordSubmoduleLabels = false;
+	private boolean recordShallowSubmodules = false;
 	private PersonIdent author;
 	private RemoteReader callback;
 	private InputStream inputStream;
@@ -345,6 +348,36 @@ public RepoCommand setRecordRemoteBranch(boolean enable) {
 	}
 
 	/**
+	 * Set whether the labels field should be recorded as a label in
+	 * .gitattributes.
+	 * <p>
+	 * Not implemented for non-bare repositories.
+	 *
+	 * @param enable Whether to record the labels in the .gitattributes
+	 * @return this command
+	 * @since 4.4
+	 */
+	public RepoCommand setRecordSubmoduleLabels(boolean enable) {
+		this.recordSubmoduleLabels = enable;
+		return this;
+	}
+
+	/**
+	 * Set whether the clone-depth field should be recorded as a shallow
+	 * recommendation in .gitmodules.
+	 * <p>
+	 * Not implemented for non-bare repositories.
+	 *
+	 * @param enable Whether to record the shallow recommendation.
+	 * @return this command
+	 * @since 4.4
+	 */
+	public RepoCommand setRecommendShallow(boolean enable) {
+		this.recordShallowSubmodules = enable;
+		return this;
+	}
+
+	/**
 	 * The progress monitor associated with the clone operation. By default,
 	 * this is set to <code>NullProgressMonitor</code>
 	 *
@@ -452,7 +485,9 @@ public RevCommit call() throws GitAPIException {
 					addSubmodule(proj.getUrl(),
 							proj.getPath(),
 							proj.getRevision(),
-							proj.getCopyFiles());
+							proj.getCopyFiles(),
+							proj.getGroups(),
+							proj.getRecommendShallow());
 				}
 			} catch (GitAPIException | IOException e) {
 				throw new ManifestErrorException(e);
@@ -472,6 +507,7 @@ public RevCommit call() throws GitAPIException {
 			ObjectInserter inserter = repo.newObjectInserter();
 			try (RevWalk rw = new RevWalk(repo)) {
 				Config cfg = new Config();
+				StringBuilder attributes = new StringBuilder();
 				for (RepoProject proj : bareProjects) {
 					String name = proj.getPath();
 					String nameUri = proj.getName();
@@ -492,6 +528,27 @@ public RevCommit call() throws GitAPIException {
 							cfg.setString("submodule", name, "branch", //$NON-NLS-1$ //$NON-NLS-2$
 									proj.getRevision());
 						}
+
+						if (recordShallowSubmodules && proj.getRecommendShallow() != null) {
+							// The shallow recommendation is losing information.
+							// As the repo manifests stores the recommended
+							// depth in the 'clone-depth' field, while
+							// git core only uses a binary 'shallow = true/false'
+							// hint, we'll map any depth to 'shallow = true'
+							cfg.setBoolean("submodule", name, "shallow", //$NON-NLS-1$ //$NON-NLS-2$
+									true);
+						}
+					}
+					if (recordSubmoduleLabels) {
+						StringBuilder rec = new StringBuilder();
+						rec.append("/"); //$NON-NLS-1$
+						rec.append(name);
+						for (String group : proj.getGroups()) {
+							rec.append(" "); //$NON-NLS-1$
+							rec.append(group);
+						}
+						rec.append("\n"); //$NON-NLS-1$
+						attributes.append(rec.toString());
 					}
 					cfg.setString("submodule", name, "path", name); //$NON-NLS-1$ //$NON-NLS-2$
 					cfg.setString("submodule", name, "url", nameUri); //$NON-NLS-1$ //$NON-NLS-2$
@@ -522,6 +579,16 @@ public RevCommit call() throws GitAPIException {
 				dcEntry.setFileMode(FileMode.REGULAR_FILE);
 				builder.add(dcEntry);
 
+				if (recordSubmoduleLabels) {
+					// create a new DirCacheEntry for .gitattributes file.
+					final DirCacheEntry dcEntryAttr = new DirCacheEntry(Constants.DOT_GIT_ATTRIBUTES);
+					ObjectId attrId = inserter.insert(Constants.OBJ_BLOB,
+							attributes.toString().getBytes(Constants.CHARACTER_ENCODING));
+					dcEntryAttr.setObjectId(attrId);
+					dcEntryAttr.setFileMode(FileMode.REGULAR_FILE);
+					builder.add(dcEntryAttr);
+				}
+
 				builder.finish();
 				ObjectId treeId = index.writeTree(inserter);
 
@@ -575,9 +642,10 @@ public RevCommit call() throws GitAPIException {
 	}
 
 	private void addSubmodule(String url, String name, String revision,
-			List<CopyFile> copyfiles) throws GitAPIException, IOException {
+			List<CopyFile> copyfiles, Set<String> groups, String recommendShallow)
+			throws GitAPIException, IOException {
 		if (repo.isBare()) {
-			RepoProject proj = new RepoProject(url, name, revision, null, null);
+			RepoProject proj = new RepoProject(url, name, revision, null, groups, recommendShallow);
 			proj.addCopyFiles(copyfiles);
 			bareProjects.add(proj);
 		} else {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
index f6d1209..d29f6c0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
@@ -70,6 +70,7 @@ public class RepoProject implements Comparable<RepoProject> {
 	private final String remote;
 	private final Set<String> groups;
 	private final List<CopyFile> copyfiles;
+	private String recommendShallow;
 	private String url;
 	private String defaultRevision;
 
@@ -134,10 +135,14 @@ public void copy() throws IOException {
 	 * @param remote
 	 *            name of the remote definition
 	 * @param groups
-	 *            comma separated group list
+	 *            set of groups
+	 * @param recommendShallow
+	 *            recommendation for shallowness
+	 * @since 4.4
 	 */
 	public RepoProject(String name, String path, String revision,
-			String remote, String groups) {
+			String remote, Set<String> groups,
+			String recommendShallow) {
 		if (name == null) {
 			throw new NullPointerException();
 		}
@@ -148,13 +153,31 @@ public RepoProject(String name, String path, String revision,
 			this.path = name;
 		this.revision = revision;
 		this.remote = remote;
-		this.groups = new HashSet<String>();
-		if (groups != null && groups.length() > 0)
-			this.groups.addAll(Arrays.asList(groups.split(","))); //$NON-NLS-1$
+		this.groups = groups;
+		this.recommendShallow = recommendShallow;
 		copyfiles = new ArrayList<CopyFile>();
 	}
 
 	/**
+	 * @param name
+	 *            the relative path to the {@code remote}
+	 * @param path
+	 *            the relative path to the super project
+	 * @param revision
+	 *            a SHA-1 or branch name or tag name
+	 * @param remote
+	 *            name of the remote definition
+	 * @param groups
+	 *            comma separated group list
+	 */
+	public RepoProject(String name, String path, String revision,
+			String remote, String groups) {
+		this(name, path, revision, remote, new HashSet<String>(), null);
+		if (groups != null && groups.length() > 0)
+			this.setGroups(groups);
+	}
+
+	/**
 	 * Set the url of the sub repo.
 	 *
 	 * @param url
@@ -166,6 +189,20 @@ public RepoProject setUrl(String url) {
 	}
 
 	/**
+	 * Set the url of the sub repo.
+	 *
+	 * @param groups
+	 *            comma separated group list
+	 * @return this for chaining.
+	 * @since 4.4
+	 */
+	public RepoProject setGroups(String groups) {
+		this.groups.clear();
+		this.groups.addAll(Arrays.asList(groups.split(","))); //$NON-NLS-1$
+		return this;
+	}
+
+	/**
 	 * Set the default revision for the sub repo.
 	 *
 	 * @param defaultRevision
@@ -241,6 +278,37 @@ public boolean inGroup(String group) {
 	}
 
 	/**
+	 * Return the set of groups.
+	 *
+	 * @return a Set of groups.
+	 * @since 4.4
+	 */
+	public Set<String> getGroups() {
+		return groups;
+	}
+
+	/**
+	 * Return the recommendation for shallowness.
+	 *
+	 * @return the String of "clone-depth"
+	 * @since 4.4
+	 */
+	public String getRecommendShallow() {
+		return recommendShallow;
+	}
+
+	/**
+	 * Sets the recommendation for shallowness.
+	 *
+	 * @param recommendShallow
+	 *            recommendation for shallowness
+	 * @since 4.4
+	 */
+	public void setRecommendShallow(String recommendShallow) {
+		this.recommendShallow = recommendShallow;
+	}
+
+	/**
 	 * Add a copy file configuration.
 	 *
 	 * @param copyfile
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
index d07c001..7c10178 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -373,6 +373,8 @@ public static JGitText get() {
 	/***/ public String indexSignatureIsInvalid;
 	/***/ public String indexWriteException;
 	/***/ public String initFailedBareRepoDifferentDirs;
+	/***/ public String initFailedDirIsNoDirectory;
+	/***/ public String initFailedGitDirIsNoDirectory;
 	/***/ public String initFailedNonBareRepoSameDirs;
 	/***/ public String inMemoryBufferLimitExceeded;
 	/***/ public String inputDidntMatchLength;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
index b02efed..53fd37e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/FileRepository.java
@@ -491,7 +491,7 @@ public void notifyIndexChanged() {
 	 * @throws IOException the ref could not be accessed.
 	 */
 	public ReflogReader getReflogReader(String refName) throws IOException {
-		Ref ref = getRef(refName);
+		Ref ref = findRef(refName);
 		if (ref != null)
 			return new ReflogReaderImpl(this, ref.getName());
 		return null;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchTrackingStatus.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchTrackingStatus.java
index 1525e5b..d4fccf9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchTrackingStatus.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BranchTrackingStatus.java
@@ -79,11 +79,11 @@ public static BranchTrackingStatus of(Repository repository, String branchName)
 		if (trackingBranch == null)
 			return null;
 
-		Ref tracking = repository.getRef(trackingBranch);
+		Ref tracking = repository.exactRef(trackingBranch);
 		if (tracking == null)
 			return null;
 
-		Ref local = repository.getRef(fullBranchName);
+		Ref local = repository.exactRef(fullBranchName);
 		if (local == null)
 			return null;
 
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 ba0dea3..5703ddd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
@@ -898,7 +898,7 @@ public String toString() {
 	 * This is essentially the same as doing:
 	 *
 	 * <pre>
-	 * return getRef(Constants.HEAD).getTarget().getName()
+	 * return exactRef(Constants.HEAD).getTarget().getName()
 	 * </pre>
 	 *
 	 * Except when HEAD is detached, in which case this method returns the
@@ -912,7 +912,7 @@ public String toString() {
 	 */
 	@Nullable
 	public String getFullBranch() throws IOException {
-		Ref head = getRef(Constants.HEAD);
+		Ref head = exactRef(Constants.HEAD);
 		if (head == null) {
 			return null;
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
index 6263d4b..5b9e8d9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
@@ -264,7 +264,7 @@ public static String getSubmoduleRemoteUrl(final Repository parent,
 
 		String remoteName = null;
 		// Look up remote URL associated wit HEAD ref
-		Ref ref = parent.getRef(Constants.HEAD);
+		Ref ref = parent.exactRef(Constants.HEAD);
 		if (ref != null) {
 			if (ref.isSymbolic())
 				ref = ref.getLeaf();
@@ -704,7 +704,7 @@ public String getHeadRef() throws IOException {
 		if (subRepo == null)
 			return null;
 		try {
-			Ref head = subRepo.getRef(Constants.HEAD);
+			Ref head = subRepo.exactRef(Constants.HEAD);
 			return head != null ? head.getLeaf().getName() : null;
 		} finally {
 			subRepo.close();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
index 963de35..9b8ba80 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BasePackPushConnection.java
@@ -57,6 +57,7 @@
 import org.eclipse.jgit.errors.NoRemoteRepositoryException;
 import org.eclipse.jgit.errors.NotSupportedException;
 import org.eclipse.jgit.errors.PackProtocolException;
+import org.eclipse.jgit.errors.TooLargeObjectInPackException;
 import org.eclipse.jgit.errors.TooLargePackException;
 import org.eclipse.jgit.errors.TransportException;
 import org.eclipse.jgit.internal.JGitText;
@@ -328,12 +329,16 @@ private void readStatusReport(final Map<String, RemoteRefUpdate> refUpdates)
 		if (!unpackLine.startsWith("unpack ")) //$NON-NLS-1$
 			throw new PackProtocolException(uri, MessageFormat.format(JGitText.get().unexpectedReportLine, unpackLine));
 		final String unpackStatus = unpackLine.substring("unpack ".length()); //$NON-NLS-1$
-		if (unpackStatus.startsWith("error Pack exceeds the limit of")) //$NON-NLS-1$
+		if (unpackStatus.startsWith("error Pack exceeds the limit of")) {//$NON-NLS-1$
 			throw new TooLargePackException(uri,
 					unpackStatus.substring("error ".length())); //$NON-NLS-1$
-		if (!unpackStatus.equals("ok")) //$NON-NLS-1$
+		} else if (unpackStatus.startsWith("error Object too large")) {//$NON-NLS-1$
+			throw new TooLargeObjectInPackException(uri,
+					unpackStatus.substring("error ".length())); //$NON-NLS-1$
+		} else if (!unpackStatus.equals("ok")) { //$NON-NLS-1$
 			throw new TransportException(uri, MessageFormat.format(
 					JGitText.get().errorOccurredDuringUnpackingOnTheRemoteEnd, unpackStatus));
+		}
 
 		String refLine;
 		while ((refLine = pckIn.readString()) != PacketLineIn.END) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
index 9e6d1f6..862b3bd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/Transport.java
@@ -629,7 +629,7 @@ public static Collection<RemoteRefUpdate> findRemoteRefUpdatesFor(
 
 		for (final RefSpec spec : procRefs) {
 			String srcSpec = spec.getSource();
-			final Ref srcRef = db.getRef(srcSpec);
+			final Ref srcRef = db.findRef(srcSpec);
 			if (srcRef != null)
 				srcSpec = srcRef.getName();