Merge branch 'master' into stable-4.0

* master:
  Silence non-externalized string warnings in org.eclipse.jgit
  Externalize translatable texts in org.eclipse.jgit
  Don't invalidate pack file on InterruptedIOException
  Update Mars target platforms to use Mars RC2 orbit
  Update build to use eclipse-jarsigner-plugin 1.1.2
  Guard agains null ReflogReader if named ref does not exist
  FS: Allow to manually set the path to the Git system config file
  FS: Fix a minor typo in runInShell() docs
  FS: Improve javadoc of some recently introduced methods
  Cleanup code and Eclipse compile errors in new gitrepo API
  Refactor to expose ManifestParser.
  FS: Remove the gitprefix logic
  SystemReader: Use discoverGitSystemConfig() in openSystemConfig()
  FS: Add a method to discover the system-wide config file
  FS: Extend readPipe() to optionally take additional environment
  FS: Document readpipe()'s encoding parameter
  Split discoverGitPrefix() code out into discoverGitExe()
  Equalize discoverGitPrefix() implementations between POSIX and Win32
  Move resolveGrandparentFile() to the base class for wider use
  Replace deprecated release() methods by close()
  Use AutoClosable to close resources in bundle org.eclipse.jgit
  ReceivePack: support quiet capability
  Fix ObjectReader resources leak

Change-Id: I0cd9f7ad57f26f0a0cbf412845d00ba1efbea346
Signed-off-by: Matthias Sohn <matthias.sohn@sap.com>
diff --git a/README.md b/README.md
index 5a729fd..333fa28 100644
--- a/README.md
+++ b/README.md
@@ -94,9 +94,9 @@
   Git is installed. Make sure Git can be found via the PATH
   environment variable. When installing Git for Windows check the "Run
   Git from the Windows Command Prompt" option. There are other options
-  like the jgit.gitprefix system property or Eclipse settings that can
-  be used for pointing out where C Git is installed. Modifying PATH is
-  the recommended option if C Git is installed.
+  like Eclipse settings that can be used for pointing out where C Git
+  is installed. Modifying PATH is the recommended option if C Git is
+  installed.
 
 - We try to use the same notation of $HOME as C Git does. On Windows
   this is often not the same value as the user.home system property.
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java
index cd066b0c..030287b 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/ReceivePackServlet.java
@@ -117,7 +117,7 @@
 			try {
 				rp.sendAdvertisedRefs(pck);
 			} finally {
-				rp.getRevWalk().release();
+				rp.getRevWalk().close();
 			}
 		}
 	}
diff --git a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java
index 443eebb..44d4b1b 100644
--- a/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java
+++ b/org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java
@@ -117,7 +117,7 @@
 				up.setBiDirectionalPipe(false);
 				up.sendAdvertisedRefs(pck);
 			} finally {
-				up.getRevWalk().release();
+				up.getRevWalk().close();
 			}
 		}
 	}
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 bc225cc..83148d0 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
@@ -307,26 +307,27 @@
 	 */
 	protected void resetIndex(FileTreeIterator treeItr)
 			throws FileNotFoundException, IOException {
-		ObjectInserter inserter = db.newObjectInserter();
-		DirCacheBuilder builder = db.lockDirCache().builder();
-		DirCacheEntry dce;
+		try (ObjectInserter inserter = db.newObjectInserter()) {
+			DirCacheBuilder builder = db.lockDirCache().builder();
+			DirCacheEntry dce;
 
-		while (!treeItr.eof()) {
-			long len = treeItr.getEntryLength();
+			while (!treeItr.eof()) {
+				long len = treeItr.getEntryLength();
 
-			dce = new DirCacheEntry(treeItr.getEntryPathString());
-			dce.setFileMode(treeItr.getEntryFileMode());
-			dce.setLastModified(treeItr.getEntryLastModified());
-			dce.setLength((int) len);
-			FileInputStream in = new FileInputStream(treeItr.getEntryFile());
-			dce.setObjectId(inserter.insert(Constants.OBJ_BLOB, len, in));
-			in.close();
-			builder.add(dce);
-			treeItr.next(1);
+				dce = new DirCacheEntry(treeItr.getEntryPathString());
+				dce.setFileMode(treeItr.getEntryFileMode());
+				dce.setLastModified(treeItr.getEntryLastModified());
+				dce.setLength((int) len);
+				FileInputStream in = new FileInputStream(
+						treeItr.getEntryFile());
+				dce.setObjectId(inserter.insert(Constants.OBJ_BLOB, len, in));
+				in.close();
+				builder.add(dce);
+				treeItr.next(1);
+			}
+			builder.commit();
+			inserter.flush();
 		}
-		builder.commit();
-		inserter.flush();
-		inserter.release();
 	}
 
 	/**
@@ -410,14 +411,15 @@
 
 	protected void checkoutBranch(String branchName)
 			throws IllegalStateException, IOException {
-		RevWalk walk = new RevWalk(db);
-		RevCommit head = walk.parseCommit(db.resolve(Constants.HEAD));
-		RevCommit branch = walk.parseCommit(db.resolve(branchName));
-		DirCacheCheckout dco = new DirCacheCheckout(db, head.getTree().getId(),
-				db.lockDirCache(), branch.getTree().getId());
-		dco.setFailOnConflict(true);
-		dco.checkout();
-		walk.release();
+		try (RevWalk walk = new RevWalk(db)) {
+			RevCommit head = walk.parseCommit(db.resolve(Constants.HEAD));
+			RevCommit branch = walk.parseCommit(db.resolve(branchName));
+			DirCacheCheckout dco = new DirCacheCheckout(db,
+					head.getTree().getId(), db.lockDirCache(),
+					branch.getTree().getId());
+			dco.setFailOnConflict(true);
+			dco.checkout();
+		}
 		// update the HEAD
 		RefUpdate refUpdate = db.updateRef(Constants.HEAD);
 		refUpdate.setRefLogMessage("checkout: moving to " + branchName, false);
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target
index 475fa04..05c6324 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.target
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8" standalone="no"?>
 <?pde?>
 <!-- generated with https://github.com/mbarbero/fr.obeo.releng.targetplatform -->
-<target name="jgit-4.5" sequenceNumber="1431244072">
+<target name="jgit-4.5" sequenceNumber="1432590632">
   <locations>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.jetty.client" version="9.2.10.v20150310"/>
@@ -23,8 +23,8 @@
       <repository id="jetty-9.2.10" location="http://download.eclipse.org/jetty/updates/jetty-bundles-9.x/9.2.10.v20150310/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
-      <unit id="org.apache.ant" version="1.9.4.v201410062020"/>
-      <unit id="org.apache.ant.source" version="1.9.4.v201410062020"/>
+      <unit id="org.apache.ant" version="1.9.4.v201504302020"/>
+      <unit id="org.apache.ant.source" version="1.9.4.v201504302020"/>
       <unit id="org.apache.commons.compress" version="1.6.0.v201310281400"/>
       <unit id="org.apache.commons.compress.source" version="1.6.0.v201310281400"/>
       <unit id="org.apache.commons.logging" version="1.1.1.v201101211721"/>
@@ -41,8 +41,8 @@
       <unit id="org.hamcrest.core.source" version="1.3.0.v201303031735"/>
       <unit id="javaewah" version="0.7.9.v201401101600"/>
       <unit id="javaewah.source" version="0.7.9.v201401101600"/>
-      <unit id="org.objenesis" version="1.0.0.v201105211943"/>
-      <unit id="org.objenesis.source" version="1.0.0.v201105211943"/>
+      <unit id="org.objenesis" version="1.0.0.v201505121915"/>
+      <unit id="org.objenesis.source" version="1.0.0.v201505121915"/>
       <unit id="org.mockito" version="1.8.4.v201303031500"/>
       <unit id="org.mockito.source" version="1.8.4.v201303031500"/>
       <unit id="com.jcraft.jsch" version="0.1.51.v201410302000"/>
@@ -57,7 +57,7 @@
       <unit id="org.slf4j.api.source" version="1.7.2.v20121108-1250"/>
       <unit id="org.slf4j.impl.log4j12" version="1.7.2.v20131105-2200"/>
       <unit id="org.slf4j.impl.log4j12.source" version="1.7.2.v20131105-2200"/>
-      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/S20150202203538/repository/"/>
+      <repository location="http://download.eclipse.org/tools/orbit/downloads/drops/S20150519210750/repository/"/>
     </location>
     <location includeMode="slicer" includeAllPlatforms="false" includeSource="true" includeConfigurePhase="true" type="InstallableUnit">
       <unit id="org.eclipse.osgi" version="0.0.0"/>
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd
index 71c9634..0b80120 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.5.tpd
@@ -1,7 +1,7 @@
 target "jgit-4.5" with source configurePhase
 
 include "projects/jetty-9.2.10.tpd"
-include "orbit/S20150202203538-Mars-M5.tpd"
+include "orbit/S20150519210750-Mars-RC2.tpd"
 
 location "http://download.eclipse.org/releases/mars/" {
 	org.eclipse.osgi lazy
diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20150202203538-Mars-M5.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20150519210750-Mars-RC2.tpd
similarity index 88%
rename from org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20150202203538-Mars-M5.tpd
rename to org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20150519210750-Mars-RC2.tpd
index 94419cb..b4ca87a 100644
--- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20150202203538-Mars-M5.tpd
+++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/S20150519210750-Mars-RC2.tpd
@@ -1,9 +1,9 @@
 target "S20141023165154-Mars-M3" with source configurePhase
 // see http://download.eclipse.org/tools/orbit/downloads/
 
-location "http://download.eclipse.org/tools/orbit/downloads/drops/S20150202203538/repository/" {
-	org.apache.ant [1.9.4.v201410062020,1.9.4.v201410062020]
-	org.apache.ant.source [1.9.4.v201410062020,1.9.4.v201410062020]
+location "http://download.eclipse.org/tools/orbit/downloads/drops/S20150519210750/repository/" {
+	org.apache.ant [1.9.4.v201504302020,1.9.4.v201504302020]
+	org.apache.ant.source [1.9.4.v201504302020,1.9.4.v201504302020]
 	org.apache.commons.compress [1.6.0.v201310281400,1.6.0.v201310281400]
 	org.apache.commons.compress.source [1.6.0.v201310281400,1.6.0.v201310281400]
 	org.apache.commons.logging [1.1.1.v201101211721,1.1.1.v201101211721]
@@ -20,8 +20,8 @@
 	org.hamcrest.core.source [1.3.0.v201303031735,1.3.0.v201303031735]
 	javaewah [0.7.9.v201401101600,0.7.9.v201401101600]
 	javaewah.source [0.7.9.v201401101600,0.7.9.v201401101600]
-	org.objenesis [1.0.0.v201105211943,1.0.0.v201105211943]
-	org.objenesis.source [1.0.0.v201105211943,1.0.0.v201105211943]
+	org.objenesis [1.0.0.v201505121915,1.0.0.v201505121915]
+	org.objenesis.source [1.0.0.v201505121915,1.0.0.v201505121915]
 	org.mockito [1.8.4.v201303031500,1.8.4.v201303031500]
 	org.mockito.source [1.8.4.v201303031500,1.8.4.v201303031500]
 	com.jcraft.jsch [0.1.51.v201410302000,0.1.51.v201410302000]
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml
index 5c6d51a..021032c 100644
--- a/org.eclipse.jgit.packaging/pom.xml
+++ b/org.eclipse.jgit.packaging/pom.xml
@@ -214,7 +214,7 @@
         <plugin>
           <groupId>org.eclipse.cbi.maven.plugins</groupId>
           <artifactId>eclipse-jarsigner-plugin</artifactId>
-          <version>1.1.2-SNAPSHOT</version>
+          <version>1.1.2</version>
         </plugin>
         <plugin>
           <groupId>org.codehaus.mojo</groupId>
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java
index d226df2..fde0a78 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/AbstractFetchCommand.java
@@ -67,8 +67,7 @@
 	private boolean verbose;
 
 	protected void showFetchResult(final FetchResult r) throws IOException {
-		ObjectReader reader = db.newObjectReader();
-		try {
+		try (ObjectReader reader = db.newObjectReader()) {
 			boolean shownURI = false;
 			for (final TrackingRefUpdate u : r.getTrackingRefUpdates()) {
 				if (!verbose && u.getResult() == RefUpdate.Result.NO_CHANGE)
@@ -89,8 +88,6 @@
 						src, dst);
 				outw.println();
 			}
-		} finally {
-			reader.release();
 		}
 		showRemoteMessages(errw, r.getMessages());
 	}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java
index 271e934..0f54171 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Blame.java
@@ -156,10 +156,9 @@
 		else
 			dateFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss ZZZZ"); //$NON-NLS-1$
 
-		BlameGenerator generator = new BlameGenerator(db, file);
-		RevFlag scanned = generator.newFlag("SCANNED"); //$NON-NLS-1$
 		reader = db.newObjectReader();
-		try {
+		try (BlameGenerator generator = new BlameGenerator(db, file)) {
+			RevFlag scanned = generator.newFlag("SCANNED"); //$NON-NLS-1$
 			generator.setTextComparator(comparator);
 
 			if (!reverseRange.isEmpty()) {
@@ -247,8 +246,7 @@
 				} while (++line < end && blame.getSourceCommit(line) == c);
 			}
 		} finally {
-			generator.release();
-			reader.release();
+			reader.close();
 		}
 	}
 
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 7147544..72e3715 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
@@ -204,15 +204,12 @@
 			addRefs(refs, Constants.R_HEADS);
 			addRefs(refs, Constants.R_REMOTES);
 
-			ObjectReader reader = db.newObjectReader();
-			try {
+			try (ObjectReader reader = db.newObjectReader()) {
 				for (final Entry<String, Ref> e : printRefs.entrySet()) {
 					final Ref ref = e.getValue();
 					printHead(reader, e.getKey(),
 							current.equals(ref.getName()), ref);
 				}
-			} finally {
-				reader.release();
 			}
 		}
 	}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java
index fe2df65..61a385d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Diff.java
@@ -184,11 +184,8 @@
 					if (head == null)
 						die(MessageFormat.format(CLIText.get().notATree, HEAD));
 					CanonicalTreeParser p = new CanonicalTreeParser();
-					ObjectReader reader = db.newObjectReader();
-					try {
+					try (ObjectReader reader = db.newObjectReader()) {
 						p.reset(reader, head);
-					} finally {
-						reader.release();
 					}
 					oldTree = p;
 				}
@@ -219,7 +216,7 @@
 				diffFmt.flush();
 			}
 		} finally {
-			diffFmt.release();
+			diffFmt.close();
 		}
 	}
 
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/IndexPack.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/IndexPack.java
index 4afb6d5..22f3be9 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/IndexPack.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/IndexPack.java
@@ -63,8 +63,7 @@
 	@Override
 	protected void run() throws Exception {
 		BufferedInputStream in = new BufferedInputStream(ins);
-		ObjectInserter inserter = db.newObjectInserter();
-		try {
+		try (ObjectInserter inserter = db.newObjectInserter()) {
 			PackParser p = inserter.newPackParser(in);
 			p.setAllowThin(fixThin);
 			if (indexVersion != -1 && p instanceof ObjectDirectoryPackParser) {
@@ -73,8 +72,6 @@
 			}
 			p.parse(new TextProgressMonitor(errw));
 			inserter.flush();
-		} finally {
-			inserter.release();
 		}
 	}
 }
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 688de2c..d43424c 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
@@ -223,7 +223,7 @@
 
 			super.run();
 		} finally {
-			diffFmt.release();
+			diffFmt.close();
 		}
 	}
 
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 1119337..4268f21 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
@@ -125,11 +125,8 @@
 		push.setTimeout(timeout);
 		Iterable<PushResult> results = push.call();
 		for (PushResult result : results) {
-			ObjectReader reader = db.newObjectReader();
-			try {
+			try (ObjectReader reader = db.newObjectReader()) {
 				printPushResult(reader, result.getURI(), result);
-			} finally {
-				reader.release();
 			}
 		}
 	}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java
index a33a2d4..b668139 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/Show.java
@@ -184,8 +184,7 @@
 			else
 				objectId = db.resolve(objectName);
 
-			RevWalk rw = new RevWalk(db);
-			try {
+			try (RevWalk rw = new RevWalk(db)) {
 				RevObject obj = rw.parseAny(objectId);
 				while (obj instanceof RevTag) {
 					show((RevTag) obj);
@@ -216,11 +215,9 @@
 							CLIText.get().cannotReadBecause, obj.name(),
 							obj.getType()));
 				}
-			} finally {
-				rw.release();
 			}
 		} finally {
-			diffFmt.release();
+			diffFmt.close();
 		}
 	}
 
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java
index 91b5917..24d717d 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/DiffAlgorithms.java
@@ -173,8 +173,7 @@
 		int maxN = 0;
 
 		AbbreviatedObjectId startId;
-		ObjectReader or = db.newObjectReader();
-		try {
+		try (ObjectReader or = db.newObjectReader()) {
 			final MutableObjectId id = new MutableObjectId();
 			RevWalk rw = new RevWalk(or);
 			TreeWalk tw = new TreeWalk(or);
@@ -232,8 +231,6 @@
 				if (count > 0 && files > count)
 					break;
 			}
-		} finally {
-			or.release();
 		}
 
 		Collections.sort(all, new Comparator<Test>() {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java
index afa4696..494055a 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/RebuildCommitGraph.java
@@ -134,12 +134,12 @@
 	}
 
 	private void recreateCommitGraph() throws IOException {
-		final RevWalk rw = new RevWalk(db);
 		final Map<ObjectId, ToRewrite> toRewrite = new HashMap<ObjectId, ToRewrite>();
 		List<ToRewrite> queue = new ArrayList<ToRewrite>();
-		final BufferedReader br = new BufferedReader(new InputStreamReader(
-				new FileInputStream(graph), Constants.CHARSET));
-		try {
+		try (RevWalk rw = new RevWalk(db);
+				final BufferedReader br = new BufferedReader(
+						new InputStreamReader(new FileInputStream(graph),
+								Constants.CHARSET))) {
 			String line;
 			while ((line = br.readLine()) != null) {
 				final String[] parts = line.split("[ \t]{1,}"); //$NON-NLS-1$
@@ -162,52 +162,52 @@
 				toRewrite.put(oldId, t);
 				queue.add(t);
 			}
-		} finally {
-			br.close();
 		}
 
 		pm.beginTask("Rewriting commits", queue.size());
-		final ObjectInserter oi = db.newObjectInserter();
-		final ObjectId emptyTree = oi.insert(Constants.OBJ_TREE, new byte[] {});
-		final PersonIdent me = new PersonIdent("jgit rebuild-commitgraph", //$NON-NLS-1$
-				"rebuild-commitgraph@localhost"); //$NON-NLS-1$
-		while (!queue.isEmpty()) {
-			final ListIterator<ToRewrite> itr = queue
-					.listIterator(queue.size());
-			queue = new ArrayList<ToRewrite>();
-			REWRITE: while (itr.hasPrevious()) {
-				final ToRewrite t = itr.previous();
-				final ObjectId[] newParents = new ObjectId[t.oldParents.length];
-				for (int k = 0; k < t.oldParents.length; k++) {
-					final ToRewrite p = toRewrite.get(t.oldParents[k]);
-					if (p != null) {
-						if (p.newId == null) {
-							// Must defer until after the parent is rewritten.
-							queue.add(t);
-							continue REWRITE;
+		try (ObjectInserter oi = db.newObjectInserter()) {
+			final ObjectId emptyTree = oi.insert(Constants.OBJ_TREE,
+					new byte[] {});
+			final PersonIdent me = new PersonIdent("jgit rebuild-commitgraph", //$NON-NLS-1$
+					"rebuild-commitgraph@localhost"); //$NON-NLS-1$
+			while (!queue.isEmpty()) {
+				final ListIterator<ToRewrite> itr = queue
+						.listIterator(queue.size());
+				queue = new ArrayList<ToRewrite>();
+				REWRITE: while (itr.hasPrevious()) {
+					final ToRewrite t = itr.previous();
+					final ObjectId[] newParents = new ObjectId[t.oldParents.length];
+					for (int k = 0; k < t.oldParents.length; k++) {
+						final ToRewrite p = toRewrite.get(t.oldParents[k]);
+						if (p != null) {
+							if (p.newId == null) {
+								// Must defer until after the parent is
+								// rewritten.
+								queue.add(t);
+								continue REWRITE;
+							} else {
+								newParents[k] = p.newId;
+							}
 						} else {
-							newParents[k] = p.newId;
+							// We have the old parent object. Use it.
+							//
+							newParents[k] = t.oldParents[k];
 						}
-					} else {
-						// We have the old parent object. Use it.
-						//
-						newParents[k] = t.oldParents[k];
 					}
-				}
 
-				final CommitBuilder newc = new CommitBuilder();
-				newc.setTreeId(emptyTree);
-				newc.setAuthor(new PersonIdent(me, new Date(t.commitTime)));
-				newc.setCommitter(newc.getAuthor());
-				newc.setParentIds(newParents);
-				newc.setMessage("ORIGINAL " + t.oldId.name() + "\n"); //$NON-NLS-2$
-				t.newId = oi.insert(newc);
-				rewrites.put(t.oldId, t.newId);
-				pm.update(1);
+					final CommitBuilder newc = new CommitBuilder();
+					newc.setTreeId(emptyTree);
+					newc.setAuthor(new PersonIdent(me, new Date(t.commitTime)));
+					newc.setCommitter(newc.getAuthor());
+					newc.setParentIds(newParents);
+					newc.setMessage("ORIGINAL " + t.oldId.name() + "\n"); //$NON-NLS-2$
+					t.newId = oi.insert(newc);
+					rewrites.put(t.oldId, t.newId);
+					pm.update(1);
+				}
 			}
+			oi.flush();
 		}
-		oi.flush();
-		oi.release();
 		pm.endTask();
 	}
 
@@ -275,11 +275,11 @@
 	}
 
 	private Map<String, Ref> computeNewRefs() throws IOException {
-		final RevWalk rw = new RevWalk(db);
 		final Map<String, Ref> refs = new HashMap<String, Ref>();
-		final BufferedReader br = new BufferedReader(new InputStreamReader(
-				new FileInputStream(refList), Constants.CHARSET));
-		try {
+		try (RevWalk rw = new RevWalk(db);
+				BufferedReader br = new BufferedReader(
+						new InputStreamReader(new FileInputStream(refList),
+								Constants.CHARSET))) {
 			String line;
 			while ((line = br.readLine()) != null) {
 				final String[] parts = line.split("[ \t]{1,}"); //$NON-NLS-1$
@@ -302,9 +302,6 @@
 				refs.put(name, new ObjectIdRef.Unpeeled(Ref.Storage.PACKED,
 						name, id));
 			}
-		} finally {
-			rw.release();
-			br.close();
 		}
 		return refs;
 	}
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java
index 4205140..dcfa8cf 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/debug/TextHashFunctions.java
@@ -300,8 +300,7 @@
 
 		long fileCnt = 0;
 		long lineCnt = 0;
-		ObjectReader or = db.newObjectReader();
-		try {
+		try (ObjectReader or = db.newObjectReader()) {
 			final MutableObjectId id = new MutableObjectId();
 			RevWalk rw = new RevWalk(or);
 			TreeWalk tw = new TreeWalk(or);
@@ -340,8 +339,6 @@
 				for (Function fun : all)
 					testOne(fun, txt, lines, cnt);
 			}
-		} finally {
-			or.release();
 		}
 
 		if (db.getDirectory() != null) {
diff --git a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java
index 087dbb0..229fb67 100644
--- a/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java
+++ b/org.eclipse.jgit.pgm/src/org/eclipse/jgit/pgm/opt/AbstractTreeIteratorHandler.java
@@ -125,8 +125,7 @@
 			throw new CmdLineException(MessageFormat.format(CLIText.get().notATree, name));
 
 		final CanonicalTreeParser p = new CanonicalTreeParser();
-		final ObjectReader curs = clp.getRepository().newObjectReader();
-		try {
+		try (ObjectReader curs = clp.getRepository().newObjectReader()) {
 			p.reset(curs, clp.getRevWalk().parseTree(id));
 		} catch (MissingObjectException e) {
 			throw new CmdLineException(MessageFormat.format(CLIText.get().notATree, name));
@@ -134,8 +133,6 @@
 			throw new CmdLineException(MessageFormat.format(CLIText.get().notATree, name));
 		} catch (IOException e) {
 			throw new CmdLineException(MessageFormat.format(CLIText.get().cannotReadBecause, name, e.getMessage()));
-		} finally {
-			curs.release();
 		}
 
 		setter.addValue(p);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
index 275b7ad..2abed3a 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/AddCommandTest.java
@@ -624,7 +624,7 @@
 				return this;
 			}
 
-			protected File discoverGitPrefix() {
+			protected File discoverGitExe() {
 				return null;
 			}
 
@@ -669,7 +669,7 @@
 				return this;
 			}
 
-			protected File discoverGitPrefix() {
+			protected File discoverGitExe() {
 				return null;
 			}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java
index ea07bee..3b2fa6c 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java
@@ -414,17 +414,19 @@
 		assertEquals(commit, pathStatus.getHeadId());
 		assertEquals(commit, pathStatus.getIndexId());
 
-		SubmoduleWalk walk = SubmoduleWalk.forIndex(git2.getRepository());
-		assertTrue(walk.next());
-		Repository clonedSub1 = walk.getRepository();
-		addRepoToClose(clonedSub1);
-		assertNotNull(clonedSub1);
-		assertEquals(
-				new File(git2.getRepository().getWorkTree(), walk.getPath()),
-				clonedSub1.getWorkTree());
-		assertEquals(new File(new File(git2.getRepository().getDirectory(),
-				"modules"), walk.getPath()), clonedSub1.getDirectory());
-		walk.release();
+		try (SubmoduleWalk walk = SubmoduleWalk
+				.forIndex(git2.getRepository())) {
+			assertTrue(walk.next());
+			Repository clonedSub1 = walk.getRepository();
+			addRepoToClose(clonedSub1);
+			assertNotNull(clonedSub1);
+			assertEquals(new File(git2.getRepository().getWorkTree(),
+					walk.getPath()), clonedSub1.getWorkTree());
+			assertEquals(
+					new File(new File(git2.getRepository().getDirectory(),
+							"modules"), walk.getPath()),
+					clonedSub1.getDirectory());
+		}
 	}
 
 	@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
index 1f71402..54fbc66 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CommitCommandTest.java
@@ -108,7 +108,7 @@
 				return this;
 			}
 
-			protected File discoverGitPrefix() {
+			protected File discoverGitExe() {
 				return null;
 			}
 
@@ -153,7 +153,7 @@
 				return this;
 			}
 
-			protected File discoverGitPrefix() {
+			protected File discoverGitExe() {
 				return null;
 			}
 
@@ -509,9 +509,9 @@
 				+ "[unmerged2, mode:100644, stage:3]",
 				indexState(0));
 
-		TreeWalk walk = TreeWalk.forPath(db, "unmerged1", commit.getTree());
-		assertEquals(FileMode.REGULAR_FILE, walk.getFileMode(0));
-		walk.release();
+		try (TreeWalk walk = TreeWalk.forPath(db, "unmerged1", commit.getTree())) {
+			assertEquals(FileMode.REGULAR_FILE, walk.getFileMode(0));
+		}
 	}
 
 	private static void addUnmergedEntry(String file, DirCacheBuilder builder) {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java
index c5608b3..4ad01cf 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/DiffCommandTest.java
@@ -247,12 +247,9 @@
 		if (id == null)
 			throw new IllegalArgumentException(name);
 		final CanonicalTreeParser p = new CanonicalTreeParser();
-		final ObjectReader or = db.newObjectReader();
-		try {
+		try (ObjectReader or = db.newObjectReader()) {
 			p.reset(or, new RevWalk(db).parseTree(id));
 			return p;
-		} finally {
-			or.release();
 		}
 	}
 }
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 eb092ad..db811cd 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
@@ -193,8 +193,8 @@
 	public static void validateIndex(Git git) throws NoWorkTreeException,
 			IOException {
 		DirCache dc = git.getRepository().lockDirCache();
-		ObjectReader r = git.getRepository().getObjectDatabase().newReader();
-		try {
+		try (ObjectReader r = git.getRepository().getObjectDatabase()
+				.newReader()) {
 			for (int i = 0; i < dc.getEntryCount(); ++i) {
 				DirCacheEntry entry = dc.getEntry(i);
 				if (entry.getLength() > 0)
@@ -203,7 +203,6 @@
 			}
 		} finally {
 			dc.unlock();
-			r.release();
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java
index d4805d0..57888e7 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/PullCommandTest.java
@@ -474,34 +474,35 @@
 		}
 		assertFileContentsEqual(sourceFile, "content");
 
-		RevWalk rw = new RevWalk(dbTarget);
-		rw.sort(RevSort.TOPO);
-		rw.markStart(rw.parseCommit(dbTarget.resolve("refs/heads/master")));
+		try (RevWalk rw = new RevWalk(dbTarget)) {
+			rw.sort(RevSort.TOPO);
+			rw.markStart(rw.parseCommit(dbTarget.resolve("refs/heads/master")));
 
-		RevCommit next;
-		if (expectedPullMode == TestPullMode.MERGE) {
-			next = rw.next();
-			assertEquals(2, next.getParentCount());
-			assertEquals(merge, next.getParent(0));
-			assertEquals(sourceCommit, next.getParent(1));
-			// since both parents are known do no further checks here
-		} else {
-			if (expectedPullMode == TestPullMode.REBASE_PREASERVE) {
+			RevCommit next;
+			if (expectedPullMode == TestPullMode.MERGE) {
 				next = rw.next();
 				assertEquals(2, next.getParentCount());
+				assertEquals(merge, next.getParent(0));
+				assertEquals(sourceCommit, next.getParent(1));
+				// since both parents are known do no further checks here
+			} else {
+				if (expectedPullMode == TestPullMode.REBASE_PREASERVE) {
+					next = rw.next();
+					assertEquals(2, next.getParentCount());
+				}
+				next = rw.next();
+				assertEquals(t2.getShortMessage(), next.getShortMessage());
+				next = rw.next();
+				assertEquals(t1.getShortMessage(), next.getShortMessage());
+				next = rw.next();
+				assertEquals(sourceCommit, next);
+				next = rw.next();
+				assertEquals("Initial commit for source",
+						next.getShortMessage());
+				next = rw.next();
+				assertNull(next);
 			}
-			next = rw.next();
-			assertEquals(t2.getShortMessage(), next.getShortMessage());
-			next = rw.next();
-			assertEquals(t1.getShortMessage(), next.getShortMessage());
-			next = rw.next();
-			assertEquals(sourceCommit, next);
-			next = rw.next();
-			assertEquals("Initial commit for source", next.getShortMessage());
-			next = rw.next();
-			assertNull(next);
 		}
-		rw.release();
 	}
 
 	@Override
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
index 6b641c4..8b0ed5f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/RebaseCommandTest.java
@@ -114,13 +114,14 @@
 
 	private void checkoutCommit(RevCommit commit) throws IllegalStateException,
 			IOException {
-		RevWalk walk = new RevWalk(db);
-		RevCommit head = walk.parseCommit(db.resolve(Constants.HEAD));
-		DirCacheCheckout dco = new DirCacheCheckout(db, head.getTree(), db
-				.lockDirCache(), commit.getTree());
-		dco.setFailOnConflict(true);
-		dco.checkout();
-		walk.release();
+		RevCommit head;
+		try (RevWalk walk = new RevWalk(db)) {
+			head = walk.parseCommit(db.resolve(Constants.HEAD));
+			DirCacheCheckout dco = new DirCacheCheckout(db, head.getTree(),
+					db.lockDirCache(), commit.getTree());
+			dco.setFailOnConflict(true);
+			dco.checkout();
+		}
 		// update the HEAD
 		RefUpdate refUpdate = db.updateRef(Constants.HEAD, true);
 		refUpdate.setNewObjectId(commit);
@@ -472,11 +473,12 @@
 	}
 
 	private String readFile(String path, RevCommit commit) throws IOException {
-		TreeWalk walk = TreeWalk.forPath(db, path, commit.getTree());
-		ObjectLoader loader = db.open(walk.getObjectId(0), Constants.OBJ_BLOB);
-		String result = RawParseUtils.decode(loader.getCachedBytes());
-		walk.release();
-		return result;
+		try (TreeWalk walk = TreeWalk.forPath(db, path, commit.getTree())) {
+			ObjectLoader loader = db.open(walk.getObjectId(0),
+					Constants.OBJ_BLOB);
+			String result = RawParseUtils.decode(loader.getCachedBytes());
+			return result;
+		}
 	}
 
 	@Test
@@ -2073,14 +2075,11 @@
 	private List<DiffEntry> diffWorkingAgainstHead(final RevCommit commit,
 			RevWalk revWalk)
 			throws IOException {
-		TreeWalk walk = createTreeWalk();
 		RevCommit parentCommit = revWalk.parseCommit(commit.getParent(0));
-		try {
+		try (TreeWalk walk = createTreeWalk()) {
 			walk.addTree(parentCommit.getTree());
 			walk.addTree(commit.getTree());
 			return DiffEntry.scan(walk);
-		} finally {
-			walk.release();
 		}
 	}
 
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 c48b412..9997c8c 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
@@ -537,16 +537,10 @@
 	 */
 	private boolean inHead(String path) throws IOException {
 		ObjectId headId = db.resolve(Constants.HEAD);
-		RevWalk rw = new RevWalk(db);
-		TreeWalk tw = null;
-		try {
-			tw = TreeWalk.forPath(db, path, rw.parseTree(headId));
+		try (RevWalk rw = new RevWalk(db);
+				TreeWalk tw = TreeWalk.forPath(db, path,
+						rw.parseTree(headId))) {
 			return tw != null;
-		} finally {
-			rw.release();
-			rw.dispose();
-			if (tw != null)
-				tw.release();
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java
index 3871203..c317e3b 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/StashCreateCommandTest.java
@@ -118,12 +118,9 @@
 		assertEquals(parentCount, commit.getParentCount());
 
 		// Load parents
-		RevWalk walk = new RevWalk(db);
-		try {
+		try (RevWalk walk = new RevWalk(db)) {
 			for (RevCommit parent : commit.getParents())
 				walk.parseBody(parent);
-		} finally {
-			walk.release();
 		}
 
 		assertEquals(1, commit.getParent(1).getParentCount());
@@ -144,37 +141,28 @@
 
 	private List<DiffEntry> diffWorkingAgainstHead(final RevCommit commit)
 			throws IOException {
-		TreeWalk walk = createTreeWalk();
-		try {
+		try (TreeWalk walk = createTreeWalk()) {
 			walk.addTree(commit.getParent(0).getTree());
 			walk.addTree(commit.getTree());
 			return DiffEntry.scan(walk);
-		} finally {
-			walk.release();
 		}
 	}
 
 	private List<DiffEntry> diffIndexAgainstHead(final RevCommit commit)
 			throws IOException {
-		TreeWalk walk = createTreeWalk();
-		try {
+		try (TreeWalk walk = createTreeWalk()) {
 			walk.addTree(commit.getParent(0).getTree());
 			walk.addTree(commit.getParent(1).getTree());
 			return DiffEntry.scan(walk);
-		} finally {
-			walk.release();
 		}
 	}
 
 	private List<DiffEntry> diffIndexAgainstWorking(final RevCommit commit)
 			throws IOException {
-		TreeWalk walk = createTreeWalk();
-		try {
+		try (TreeWalk walk = createTreeWalk()) {
 			walk.addTree(commit.getParent(1).getTree());
 			walk.addTree(commit.getTree());
 			return DiffEntry.scan(walk);
-		} finally {
-			walk.release();
 		}
 	}
 
@@ -224,11 +212,12 @@
 		writeTrashFile("file", "content2");
 		RevCommit stashedWorkTree = Git.wrap(db).stashCreate().call();
 		validateStashedCommit(stashedWorkTree);
-		RevWalk walk = new RevWalk(db);
-		RevCommit stashedIndex = stashedWorkTree.getParent(1);
-		walk.parseBody(stashedIndex);
-		walk.parseBody(stashedIndex.getTree());
-		walk.parseBody(stashedIndex.getParent(0));
+		try (RevWalk walk = new RevWalk(db)) {
+			RevCommit stashedIndex = stashedWorkTree.getParent(1);
+			walk.parseBody(stashedIndex);
+			walk.parseBody(stashedIndex.getTree());
+			walk.parseBody(stashedIndex.getParent(0));
+		}
 		List<DiffEntry> workTreeStashAgainstWorkTree = diffWorkingAgainstHead(stashedWorkTree);
 		assertEquals(1, workTreeStashAgainstWorkTree.size());
 		List<DiffEntry> workIndexAgainstWorkTree = diffIndexAgainstHead(stashedWorkTree);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/blame/BlameGeneratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/blame/BlameGeneratorTest.java
index a7bce1e..42909f0 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/blame/BlameGeneratorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/blame/BlameGeneratorTest.java
@@ -70,8 +70,7 @@
 		git.add().addFilepattern("file.txt").call();
 		RevCommit c2 = git.commit().setMessage("create file").call();
 
-		BlameGenerator generator = new BlameGenerator(db, "file.txt");
-		try {
+		try (BlameGenerator generator = new BlameGenerator(db, "file.txt")) {
 			generator.push(null, db.resolve(Constants.HEAD));
 			assertEquals(3, generator.getResultContents().size());
 
@@ -94,8 +93,6 @@
 			assertEquals("file.txt", generator.getSourcePath());
 
 			assertFalse(generator.next());
-		} finally {
-			generator.release();
 		}
 	}
 
@@ -123,8 +120,7 @@
 		git.add().addFilepattern(FILENAME_2).call();
 		RevCommit c2 = git.commit().setMessage("change file2").call();
 
-		BlameGenerator generator = new BlameGenerator(db, FILENAME_2);
-		try {
+		try (BlameGenerator generator = new BlameGenerator(db, FILENAME_2)) {
 			generator.push(null, db.resolve(Constants.HEAD));
 			assertEquals(3, generator.getResultContents().size());
 
@@ -147,13 +143,10 @@
 			assertEquals(FILENAME_1, generator.getSourcePath());
 
 			assertFalse(generator.next());
-		} finally {
-			generator.release();
 		}
 
 		// and test again with other BlameGenerator API:
-		generator = new BlameGenerator(db, FILENAME_2);
-		try {
+		try (BlameGenerator generator = new BlameGenerator(db, FILENAME_2)) {
 			generator.push(null, db.resolve(Constants.HEAD));
 			BlameResult result = generator.computeBlameResult();
 
@@ -167,9 +160,6 @@
 
 			assertEquals(c1, result.getSourceCommit(2));
 			assertEquals(FILENAME_1, result.getSourcePath(2));
-
-		} finally {
-			generator.release();
 		}
 	}
 
@@ -193,8 +183,7 @@
 		git.add().addFilepattern("file.txt").call();
 		RevCommit c3 = git.commit().setMessage("create file").call();
 
-		BlameGenerator generator = new BlameGenerator(db, "file.txt");
-		try {
+		try (BlameGenerator generator = new BlameGenerator(db, "file.txt")) {
 			generator.push(null, db.resolve(Constants.HEAD));
 			assertEquals(3, generator.getResultContents().size());
 
@@ -204,8 +193,6 @@
 			assertEquals(3, generator.getResultEnd());
 
 			assertFalse(generator.next());
-		} finally {
-			generator.release();
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java
index 91498e7..02e485d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/diff/DiffFormatterTest.java
@@ -98,8 +98,9 @@
 	@Override
 	@After
 	public void tearDown() throws Exception {
-		if (df != null)
-			df.release();
+		if (df != null) {
+			df.close();
+		}
 		super.tearDown();
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java
new file mode 100644
index 0000000..1005b39
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/gitrepo/ManifestParserTest.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2015, Google Inc.
+ * 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.gitrepo;
+
+import static org.junit.Assert.assertTrue;
+
+import java.io.StringBufferInputStream;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.junit.Test;
+
+public class ManifestParserTest {
+
+	@Test
+	public void testManifestParser() throws Exception {
+		String baseUrl = "https://git.google.com/";
+		StringBuilder xmlContent = new StringBuilder();
+		Set<String> results = new HashSet<String>();
+		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=\"foo\" name=\"")
+			.append("foo")
+			.append("\" groups=\"a,test\" />")
+			.append("<project path=\"bar\" name=\"")
+			.append("bar")
+			.append("\" groups=\"notdefault\" />")
+			.append("<project path=\"foo/a\" name=\"")
+			.append("a")
+			.append("\" groups=\"a\" />")
+			.append("<project path=\"b\" name=\"")
+			.append("b")
+			.append("\" groups=\"b\" />")
+			.append("</manifest>");
+
+		ManifestParser parser = new ManifestParser(
+				null, null, "master", baseUrl, null, null);
+		parser.read(new StringBufferInputStream(xmlContent.toString()));
+		// Unfiltered projects should have them all.
+		results.clear();
+		results.add("foo");
+		results.add("bar");
+		results.add("foo/a");
+		results.add("b");
+		for (RepoProject proj : parser.getProjects()) {
+			String msg = String.format(
+					"project \"%s\" should be included in unfiltered projects",
+					proj.path);
+			assertTrue(msg, results.contains(proj.path));
+			results.remove(proj.path);
+		}
+		assertTrue(
+				"Unfiltered projects shouldn't contain any unexpected results",
+				results.isEmpty());
+		// Filtered projects should have foo & b
+		results.clear();
+		results.add("foo");
+		results.add("b");
+		for (RepoProject proj : parser.getFilteredProjects()) {
+			String msg = String.format(
+					"project \"%s\" should be included in filtered projects",
+					proj.path);
+			assertTrue(msg, results.contains(proj.path));
+			results.remove(proj.path);
+		}
+		assertTrue(
+				"Filtered projects shouldn't contain any unexpected results",
+				results.isEmpty());
+	}
+}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsInserterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsInserterTest.java
index 693388c..fc8cbaa 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsInserterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/dfs/DfsInserterTest.java
@@ -78,12 +78,11 @@
 
 	@Test
 	public void testInserterDiscardsPack() throws IOException {
-		ObjectInserter ins = db.newObjectInserter();
-		ins.insert(Constants.OBJ_BLOB, Constants.encode("foo"));
-		ins.insert(Constants.OBJ_BLOB, Constants.encode("bar"));
-		assertEquals(0, db.getObjectDatabase().listPacks().size());
-
-		ins.release();
+		try (ObjectInserter ins = db.newObjectInserter()) {
+			ins.insert(Constants.OBJ_BLOB, Constants.encode("foo"));
+			ins.insert(Constants.OBJ_BLOB, Constants.encode("bar"));
+			assertEquals(0, db.getObjectDatabase().listPacks().size());
+		}
 		assertEquals(0, db.getObjectDatabase().listPacks().size());
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AbbreviationTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AbbreviationTest.java
index 3a0b827..9875403 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AbbreviationTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/AbbreviationTest.java
@@ -94,8 +94,9 @@
 
 	@After
 	public void tearDown() throws Exception {
-		if (reader != null)
-			reader.release();
+		if (reader != null) {
+			reader.close();
+		}
 	}
 
 	@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java
index 562cde7..514e00f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/ConcurrentRepackTest.java
@@ -150,11 +150,11 @@
 		// within the pack has been modified.
 		//
 		final RevObject o2 = writeBlob(eden, "o2");
-		final PackWriter pw = new PackWriter(eden);
-		pw.addObject(o2);
-		pw.addObject(o1);
-		write(out1, pw);
-		pw.release();
+		try (PackWriter pw = new PackWriter(eden)) {
+			pw.addObject(o2);
+			pw.addObject(o1);
+			write(out1, pw);
+		}
 
 		// Try the old name, then the new name. The old name should cause the
 		// pack to reload when it opens and the index and pack mismatch.
@@ -216,18 +216,18 @@
 
 	private File[] pack(final Repository src, final RevObject... list)
 			throws IOException {
-		final PackWriter pw = new PackWriter(src);
-		for (final RevObject o : list) {
-			pw.addObject(o);
-		}
+		try (PackWriter pw = new PackWriter(src)) {
+			for (final RevObject o : list) {
+				pw.addObject(o);
+			}
 
-		final ObjectId name = pw.computeName();
-		final File packFile = fullPackFileName(name, ".pack");
-		final File idxFile = fullPackFileName(name, ".idx");
-		final File[] files = new File[] { packFile, idxFile };
-		write(files, pw);
-		pw.release();
-		return files;
+			final ObjectId name = pw.computeName();
+			final File packFile = fullPackFileName(name, ".pack");
+			final File idxFile = fullPackFileName(name, ".idx");
+			final File[] files = new File[] { packFile, idxFile };
+			write(files, pw);
+			return files;
+		}
 	}
 
 	private static void write(final File[] files, final PackWriter pw)
@@ -282,13 +282,10 @@
 			throws IOException {
 		final RevWalk revWalk = new RevWalk(repo);
 		final byte[] bytes = Constants.encode(data);
-		final ObjectInserter inserter = repo.newObjectInserter();
 		final ObjectId id;
-		try {
+		try (ObjectInserter inserter = repo.newObjectInserter()) {
 			id = inserter.insert(Constants.OBJ_BLOB, bytes);
 			inserter.flush();
-		} finally {
-			inserter.release();
 		}
 		try {
 			parse(id);
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java
index 3324627..0505564 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackFileTest.java
@@ -373,8 +373,9 @@
 
 	@After
 	public void release() {
-		if (inserter != null)
-			inserter.release();
+		if (inserter != null) {
+			inserter.close();
+		}
 	}
 
 	private PackParser index(byte[] raw) throws IOException {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
index 873b2cd..bc880a1 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/PackWriterTest.java
@@ -120,11 +120,11 @@
 	@After
 	public void tearDown() throws Exception {
 		if (writer != null) {
-			writer.release();
+			writer.close();
 			writer = null;
 		}
 		if (inserter != null) {
-			inserter.release();
+			inserter.close();
 			inserter = null;
 		}
 		super.tearDown();
@@ -514,26 +514,26 @@
 	private static PackIndex writePack(FileRepository repo,
 			Set<? extends ObjectId> want, Set<ObjectIdSet> excludeObjects)
 			throws IOException {
-		PackWriter pw = new PackWriter(repo);
-		pw.setDeltaBaseAsOffset(true);
-		pw.setReuseDeltaCommits(false);
-		for (ObjectIdSet idx : excludeObjects)
-			pw.excludeObjects(idx);
-		pw.preparePack(NullProgressMonitor.INSTANCE, want,
-				Collections.<ObjectId> emptySet());
-		String id = pw.computeName().getName();
-		File packdir = new File(repo.getObjectsDirectory(), "pack");
-		File packFile = new File(packdir, "pack-" + id + ".pack");
-		FileOutputStream packOS = new FileOutputStream(packFile);
-		pw.writePack(NullProgressMonitor.INSTANCE,
-				NullProgressMonitor.INSTANCE, packOS);
-		packOS.close();
-		File idxFile = new File(packdir, "pack-" + id + ".idx");
-		FileOutputStream idxOS = new FileOutputStream(idxFile);
-		pw.writeIndex(idxOS);
-		idxOS.close();
-		pw.release();
-		return PackIndex.open(idxFile);
+		try (PackWriter pw = new PackWriter(repo)) {
+			pw.setDeltaBaseAsOffset(true);
+			pw.setReuseDeltaCommits(false);
+			for (ObjectIdSet idx : excludeObjects)
+				pw.excludeObjects(idx);
+			pw.preparePack(NullProgressMonitor.INSTANCE, want,
+					Collections.<ObjectId> emptySet());
+			String id = pw.computeName().getName();
+			File packdir = new File(repo.getObjectsDirectory(), "pack");
+			File packFile = new File(packdir, "pack-" + id + ".pack");
+			FileOutputStream packOS = new FileOutputStream(packFile);
+			pw.writePack(NullProgressMonitor.INSTANCE,
+					NullProgressMonitor.INSTANCE, packOS);
+			packOS.close();
+			File idxFile = new File(packdir, "pack-" + id + ".idx");
+			FileOutputStream idxOS = new FileOutputStream(idxFile);
+			pw.writeIndex(idxOS);
+			idxOS.close();
+			return PackIndex.open(idxFile);
+		}
 	}
 
 	// TODO: testWritePackDeltasCycle()
@@ -639,7 +639,7 @@
 		writer.setIgnoreMissingUninteresting(ignoreMissingUninteresting);
 		writer.preparePack(m, interestings, uninterestings);
 		writer.writePack(m, m, os);
-		writer.release();
+		writer.close();
 		verifyOpenPack(thin);
 	}
 
@@ -650,7 +650,7 @@
 		writer.preparePack(objectSource.iterator());
 		assertEquals(objectSource.size(), writer.getObjectCount());
 		writer.writePack(m, m, os);
-		writer.release();
+		writer.close();
 		verifyOpenPack(false);
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
index 0ab013b..5670a96 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/internal/storage/file/T0003_BasicTest.java
@@ -304,11 +304,12 @@
 		// object (as it already exists in the pack).
 		//
 		final Repository newdb = createBareRepository();
-		final ObjectInserter oi = newdb.newObjectInserter();
-		final ObjectId treeId = oi.insert(new TreeFormatter());
-		oi.release();
+		try (final ObjectInserter oi = newdb.newObjectInserter()) {
+			final ObjectId treeId = oi.insert(new TreeFormatter());
+			assertEquals("4b825dc642cb6eb9a060e54bf8d69288fbee4904",
+					treeId.name());
+		}
 
-		assertEquals("4b825dc642cb6eb9a060e54bf8d69288fbee4904", treeId.name());
 		final File o = new File(new File(new File(newdb.getDirectory(),
 				"objects"), "4b"), "825dc642cb6eb9a060e54bf8d69288fbee4904");
 		assertTrue("Exists " + o, o.isFile());
@@ -569,8 +570,7 @@
 	@Test
 	public void test026_CreateCommitMultipleparents() throws IOException {
 		final ObjectId treeId;
-		final ObjectInserter oi = db.newObjectInserter();
-		try {
+		try (final ObjectInserter oi = db.newObjectInserter()) {
 			final ObjectId blobId = oi.insert(Constants.OBJ_BLOB,
 					"and this is the data in me\n".getBytes(Constants.CHARSET
 							.name()));
@@ -578,8 +578,6 @@
 			fmt.append("i-am-a-file", FileMode.REGULAR_FILE, blobId);
 			treeId = oi.insert(fmt);
 			oi.flush();
-		} finally {
-			oi.release();
 		}
 		assertEquals(ObjectId
 				.fromString("00b1f73724f493096d1ffa0b0f1f1482dbb8c936"), treeId);
@@ -741,80 +739,59 @@
 
 	private ObjectId insertEmptyBlob() throws IOException {
 		final ObjectId emptyId;
-		ObjectInserter oi = db.newObjectInserter();
-		try {
+		try (ObjectInserter oi = db.newObjectInserter()) {
 			emptyId = oi.insert(Constants.OBJ_BLOB, new byte[] {});
 			oi.flush();
-		} finally {
-			oi.release();
 		}
 		return emptyId;
 	}
 
 	private ObjectId insertTree(Tree tree) throws IOException {
-		ObjectInserter oi = db.newObjectInserter();
-		try {
+		try (ObjectInserter oi = db.newObjectInserter()) {
 			ObjectId id = oi.insert(Constants.OBJ_TREE, tree.format());
 			oi.flush();
 			return id;
-		} finally {
-			oi.release();
 		}
 	}
 
 	private ObjectId insertTree(TreeFormatter tree) throws IOException {
-		ObjectInserter oi = db.newObjectInserter();
-		try {
+		try (ObjectInserter oi = db.newObjectInserter()) {
 			ObjectId id = oi.insert(tree);
 			oi.flush();
 			return id;
-		} finally {
-			oi.release();
 		}
 	}
 
 	private ObjectId insertCommit(final CommitBuilder builder)
 			throws IOException, UnsupportedEncodingException {
-		ObjectInserter oi = db.newObjectInserter();
-		try {
+		try (ObjectInserter oi = db.newObjectInserter()) {
 			ObjectId id = oi.insert(builder);
 			oi.flush();
 			return id;
-		} finally {
-			oi.release();
 		}
 	}
 
 	private RevCommit parseCommit(AnyObjectId id)
 			throws MissingObjectException, IncorrectObjectTypeException,
 			IOException {
-		RevWalk rw = new RevWalk(db);
-		try {
+		try (RevWalk rw = new RevWalk(db)) {
 			return rw.parseCommit(id);
-		} finally {
-			rw.release();
 		}
 	}
 
 	private ObjectId insertTag(final TagBuilder tag) throws IOException,
 			UnsupportedEncodingException {
-		ObjectInserter oi = db.newObjectInserter();
-		try {
+		try (ObjectInserter oi = db.newObjectInserter()) {
 			ObjectId id = oi.insert(tag);
 			oi.flush();
 			return id;
-		} finally {
-			oi.release();
 		}
 	}
 
 	private RevTag parseTag(AnyObjectId id) throws MissingObjectException,
 			IncorrectObjectTypeException, IOException {
-		RevWalk rw = new RevWalk(db);
-		try {
+		try (RevWalk rw = new RevWalk(db)) {
 			return rw.parseTag(id);
-		} finally {
-			rw.release();
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
index 48debae..7a115e1 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/DirCacheCheckoutTest.java
@@ -356,15 +356,12 @@
 	}
 
 	ObjectId genSha1(String data) {
-		ObjectInserter w = db.newObjectInserter();
-		try {
+		try (ObjectInserter w = db.newObjectInserter()) {
 			ObjectId id = w.insert(Constants.OBJ_BLOB, data.getBytes());
 			w.flush();
 			return id;
 		} catch (IOException e) {
 			fail(e.toString());
-		} finally {
-			w.release();
 		}
 		return null;
 	}
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
index a85198f..a5cd7b5 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/IndexDiffTest.java
@@ -384,13 +384,10 @@
 	}
 
 	private ObjectId insertTree(Tree tree) throws IOException {
-		ObjectInserter oi = db.newObjectInserter();
-		try {
+		try (ObjectInserter oi = db.newObjectInserter()) {
 			ObjectId id = oi.insert(Constants.OBJ_TREE, tree.format());
 			oi.flush();
 			return id;
-		} finally {
-			oi.release();
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogConfigTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogConfigTest.java
index cf8d42f..7b6d7d4 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogConfigTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/ReflogConfigTest.java
@@ -109,14 +109,11 @@
 		commit.setAuthor(author);
 		commit.setCommitter(committer);
 		commit.setMessage(commitMsg);
-		ObjectInserter inserter = db.newObjectInserter();
 		ObjectId id;
-		try {
+		try (ObjectInserter inserter = db.newObjectInserter()) {
 			commit.setTreeId(inserter.insert(new TreeFormatter()));
 			id = inserter.insert(commit);
 			inserter.flush();
-		} finally {
-			inserter.release();
 		}
 
 		int nl = commitMsg.indexOf('\n');
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/DefaultNoteMergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/DefaultNoteMergerTest.java
index 91608ea..d3a6f18 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/DefaultNoteMergerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/DefaultNoteMergerTest.java
@@ -86,8 +86,8 @@
 	@Override
 	@After
 	public void tearDown() throws Exception {
-		reader.release();
-		inserter.release();
+		reader.close();
+		inserter.close();
 		super.tearDown();
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/NoteMapMergerTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/NoteMapMergerTest.java
index 8010fb1..be7bead 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/NoteMapMergerTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/NoteMapMergerTest.java
@@ -127,8 +127,8 @@
 	@Override
 	@After
 	public void tearDown() throws Exception {
-		reader.release();
-		inserter.release();
+		reader.close();
+		inserter.close();
 		super.tearDown();
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/NoteMapTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/NoteMapTest.java
index c2f63d6..4539a01 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/NoteMapTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/notes/NoteMapTest.java
@@ -91,8 +91,8 @@
 	@Override
 	@After
 	public void tearDown() throws Exception {
-		reader.release();
-		inserter.release();
+		reader.close();
+		inserter.close();
 		super.tearDown();
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java
index dfde7fc..2a59f58 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/ObjectWalkTest.java
@@ -229,15 +229,12 @@
 			Tree A_A = A.addTree("A");
 			Tree A_B = A.addTree("B");
 
-			final ObjectInserter inserter = db.newObjectInserter();
-			try {
+			try (final ObjectInserter inserter = db.newObjectInserter()) {
 				A_A.setId(inserter.insert(Constants.OBJ_TREE, A_A.format()));
 				A_B.setId(inserter.insert(Constants.OBJ_TREE, A_B.format()));
 				A.setId(inserter.insert(Constants.OBJ_TREE, A.format()));
 				root.setId(inserter.insert(Constants.OBJ_TREE, root.format()));
 				inserter.flush();
-			} finally {
-				inserter.release();
 			}
 
 			tree_root = rw.parseTree(root.getId());
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkUtilsReachableTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkUtilsReachableTest.java
index 855bb80..10bea0a 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkUtilsReachableTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/revwalk/RevWalkUtilsReachableTest.java
@@ -103,12 +103,9 @@
 		RevCommit a = commit();
 		Ref branchA = branch("a", a);
 
-		RevWalk walk = new RevWalk(db);
-		try {
+		try (RevWalk walk = new RevWalk(db)) {
 			RevCommit parsedCommit = walk.parseCommit(a.getId());
 			assertContains(parsedCommit, asList(branchA));
-		} finally {
-			walk.release();
 		}
 	}
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java
index 6859dd5..c829be9 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/PackParserTest.java
@@ -486,8 +486,9 @@
 
 	@After
 	public void release() {
-		if (inserter != null)
-			inserter.release();
+		if (inserter != null) {
+			inserter.close();
+		}
 	}
 
 	private PackParser index(InputStream in) throws IOException {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java
index 2bd9077..aa5914f 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/transport/ReceivePackAdvertiseRefsHookTest.java
@@ -543,8 +543,9 @@
 
 	@After
 	public void release() {
-		if (inserter != null)
-			inserter.release();
+		if (inserter != null) {
+			inserter.close();
+		}
 	}
 
 	private void openPack(TemporaryBuffer.Heap buf) throws IOException {
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorJava7Test.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorJava7Test.java
index 741396c..8875410 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorJava7Test.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorJava7Test.java
@@ -89,20 +89,19 @@
 		DirCacheEditor dce = dc.editor();
 		final String UNNORMALIZED = "target/";
 		final byte[] UNNORMALIZED_BYTES = Constants.encode(UNNORMALIZED);
-		ObjectInserter oi = db.newObjectInserter();
-		final ObjectId linkid = oi.insert(Constants.OBJ_BLOB,
-				UNNORMALIZED_BYTES, 0,
-				UNNORMALIZED_BYTES.length);
-		oi.release();
-		dce.add(new DirCacheEditor.PathEdit("link") {
-			@Override
-			public void apply(DirCacheEntry ent) {
-				ent.setFileMode(FileMode.SYMLINK);
-				ent.setObjectId(linkid);
-				ent.setLength(UNNORMALIZED_BYTES.length);
-			}
-		});
-		assertTrue(dce.commit());
+		try (ObjectInserter oi = db.newObjectInserter()) {
+			final ObjectId linkid = oi.insert(Constants.OBJ_BLOB,
+					UNNORMALIZED_BYTES, 0, UNNORMALIZED_BYTES.length);
+			dce.add(new DirCacheEditor.PathEdit("link") {
+				@Override
+				public void apply(DirCacheEntry ent) {
+					ent.setFileMode(FileMode.SYMLINK);
+					ent.setObjectId(linkid);
+					ent.setLength(UNNORMALIZED_BYTES.length);
+				}
+			});
+			assertTrue(dce.commit());
+		}
 		new Git(db).commit().setMessage("Adding link").call();
 		new Git(db).reset().setMode(ResetType.HARD).call();
 		DirCacheIterator dci = new DirCacheIterator(db.readDirCache());
@@ -129,19 +128,19 @@
 		DirCacheEditor dce = dc.editor();
 		final String NORMALIZED = "target";
 		final byte[] NORMALIZED_BYTES = Constants.encode(NORMALIZED);
-		ObjectInserter oi = db.newObjectInserter();
-		final ObjectId linkid = oi.insert(Constants.OBJ_BLOB, NORMALIZED_BYTES,
-				0, NORMALIZED_BYTES.length);
-		oi.release();
-		dce.add(new DirCacheEditor.PathEdit("link") {
-			@Override
-			public void apply(DirCacheEntry ent) {
-				ent.setFileMode(FileMode.SYMLINK);
-				ent.setObjectId(linkid);
-				ent.setLength(NORMALIZED_BYTES.length);
-			}
-		});
-		assertTrue(dce.commit());
+		try (ObjectInserter oi = db.newObjectInserter()) {
+			final ObjectId linkid = oi.insert(Constants.OBJ_BLOB,
+					NORMALIZED_BYTES, 0, NORMALIZED_BYTES.length);
+			dce.add(new DirCacheEditor.PathEdit("link") {
+				@Override
+				public void apply(DirCacheEntry ent) {
+					ent.setFileMode(FileMode.SYMLINK);
+					ent.setObjectId(linkid);
+					ent.setLength(NORMALIZED_BYTES.length);
+				}
+			});
+			assertTrue(dce.commit());
+		}
 		new Git(db).commit().setMessage("Adding link").call();
 		new Git(db).reset().setMode(ResetType.HARD).call();
 		DirCacheIterator dci = new DirCacheIterator(db.readDirCache());
@@ -166,21 +165,21 @@
 	public void testSymlinkActuallyModified() throws Exception {
 		final String NORMALIZED = "target";
 		final byte[] NORMALIZED_BYTES = Constants.encode(NORMALIZED);
-		ObjectInserter oi = db.newObjectInserter();
-		final ObjectId linkid = oi.insert(Constants.OBJ_BLOB, NORMALIZED_BYTES,
-				0, NORMALIZED_BYTES.length);
-		oi.release();
-		DirCache dc = db.lockDirCache();
-		DirCacheEditor dce = dc.editor();
-		dce.add(new DirCacheEditor.PathEdit("link") {
-			@Override
-			public void apply(DirCacheEntry ent) {
-				ent.setFileMode(FileMode.SYMLINK);
-				ent.setObjectId(linkid);
-				ent.setLength(NORMALIZED_BYTES.length);
-			}
-		});
-		assertTrue(dce.commit());
+		try (ObjectInserter oi = db.newObjectInserter()) {
+			final ObjectId linkid = oi.insert(Constants.OBJ_BLOB,
+					NORMALIZED_BYTES, 0, NORMALIZED_BYTES.length);
+			DirCache dc = db.lockDirCache();
+			DirCacheEditor dce = dc.editor();
+			dce.add(new DirCacheEditor.PathEdit("link") {
+				@Override
+				public void apply(DirCacheEntry ent) {
+					ent.setFileMode(FileMode.SYMLINK);
+					ent.setObjectId(linkid);
+					ent.setLength(NORMALIZED_BYTES.length);
+				}
+			});
+			assertTrue(dce.commit());
+		}
 		new Git(db).commit().setMessage("Adding link").call();
 		new Git(db).reset().setMode(ResetType.HARD).call();
 
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
index 7964578..767e13d 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/FileTreeIteratorTest.java
@@ -274,9 +274,9 @@
 		ObjectId fromRaw = ObjectId.fromRaw(fti.idBuffer(), fti.idOffset());
 		assertEquals("6b584e8ece562ebffc15d38808cd6b98fc3d97ea",
 				fromRaw.getName());
-		ObjectReader objectReader = db.newObjectReader();
-		assertFalse(fti.isModified(dce, false, objectReader));
-		objectReader.release();
+		try (ObjectReader objectReader = db.newObjectReader()) {
+			assertFalse(fti.isModified(dce, false, objectReader));
+		}
 	}
 
 	@Test
@@ -291,15 +291,15 @@
 		// Modify previously committed DirCacheEntry and write it back to disk
 		DirCacheEntry dce = db.readDirCache().getEntry("symlink");
 		dce.setFileMode(FileMode.SYMLINK);
-		ObjectReader objectReader = db.newObjectReader();
-		DirCacheCheckout.checkoutEntry(db, dce, objectReader);
+		try (ObjectReader objectReader = db.newObjectReader()) {
+			DirCacheCheckout.checkoutEntry(db, dce, objectReader);
 
-		FileTreeIterator fti = new FileTreeIterator(trash, db.getFS(), db
-				.getConfig().get(WorkingTreeOptions.KEY));
-		while (!fti.getEntryPathString().equals("symlink"))
-			fti.next(1);
-		assertFalse(fti.isModified(dce, false, objectReader));
-		objectReader.release();
+			FileTreeIterator fti = new FileTreeIterator(trash, db.getFS(),
+					db.getConfig().get(WorkingTreeOptions.KEY));
+			while (!fti.getEntryPathString().equals("symlink"))
+				fti.next(1);
+			assertFalse(fti.isModified(dce, false, objectReader));
+		}
 	}
 
 	@Test
@@ -327,9 +327,9 @@
 		// If the rounding trick does not work we could skip the compareMetaData
 		// test and hope that we are usually testing the intended code path.
 		assertEquals(MetadataDiff.SMUDGED, fti.compareMetadata(dce));
-		ObjectReader objectReader = db.newObjectReader();
-		assertTrue(fti.isModified(dce, false, objectReader));
-		objectReader.release();
+		try (ObjectReader objectReader = db.newObjectReader()) {
+			assertTrue(fti.isModified(dce, false, objectReader));
+		}
 	}
 
 	@Test
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/ForPathTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/ForPathTest.java
index 59c4a8d..eaee8bb 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/ForPathTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/ForPathTest.java
@@ -68,70 +68,69 @@
 	public void testFindObjects() throws Exception {
 		final DirCache tree0 = DirCache.newInCore();
 		final DirCacheBuilder b0 = tree0.builder();
-		ObjectReader or = db.newObjectReader();
-		ObjectInserter oi = db.newObjectInserter();
+		try (ObjectReader or = db.newObjectReader();
+				ObjectInserter oi = db.newObjectInserter()) {
 
-		DirCacheEntry aDotB = createEntry("a.b", EXECUTABLE_FILE);
-		b0.add(aDotB);
-		DirCacheEntry aSlashB = createEntry("a/b", REGULAR_FILE);
-		b0.add(aSlashB);
-		DirCacheEntry aSlashCSlashD = createEntry("a/c/d", REGULAR_FILE);
-		b0.add(aSlashCSlashD);
-		DirCacheEntry aZeroB = createEntry("a0b", SYMLINK);
-		b0.add(aZeroB);
-		b0.finish();
-		assertEquals(4, tree0.getEntryCount());
-		ObjectId tree = tree0.writeTree(oi);
+			DirCacheEntry aDotB = createEntry("a.b", EXECUTABLE_FILE);
+			b0.add(aDotB);
+			DirCacheEntry aSlashB = createEntry("a/b", REGULAR_FILE);
+			b0.add(aSlashB);
+			DirCacheEntry aSlashCSlashD = createEntry("a/c/d", REGULAR_FILE);
+			b0.add(aSlashCSlashD);
+			DirCacheEntry aZeroB = createEntry("a0b", SYMLINK);
+			b0.add(aZeroB);
+			b0.finish();
+			assertEquals(4, tree0.getEntryCount());
+			ObjectId tree = tree0.writeTree(oi);
 
-		// Find the directories that were implicitly created above.
-		TreeWalk tw = new TreeWalk(or);
-		tw.addTree(tree);
-		ObjectId a = null;
-		ObjectId aSlashC = null;
-		while (tw.next()) {
-			if (tw.getPathString().equals("a")) {
-				a = tw.getObjectId(0);
-				tw.enterSubtree();
-				while (tw.next()) {
-					if (tw.getPathString().equals("a/c")) {
-						aSlashC = tw.getObjectId(0);
-						break;
+			// Find the directories that were implicitly created above.
+			TreeWalk tw = new TreeWalk(or);
+			tw.addTree(tree);
+			ObjectId a = null;
+			ObjectId aSlashC = null;
+			while (tw.next()) {
+				if (tw.getPathString().equals("a")) {
+					a = tw.getObjectId(0);
+					tw.enterSubtree();
+					while (tw.next()) {
+						if (tw.getPathString().equals("a/c")) {
+							aSlashC = tw.getObjectId(0);
+							break;
+						}
 					}
+					break;
 				}
-				break;
 			}
+
+			assertEquals(a, TreeWalk.forPath(or, "a", tree).getObjectId(0));
+			assertEquals(a, TreeWalk.forPath(or, "a/", tree).getObjectId(0));
+			assertEquals(null, TreeWalk.forPath(or, "/a", tree));
+			assertEquals(null, TreeWalk.forPath(or, "/a/", tree));
+
+			assertEquals(aDotB.getObjectId(),
+					TreeWalk.forPath(or, "a.b", tree).getObjectId(0));
+			assertEquals(null, TreeWalk.forPath(or, "/a.b", tree));
+			assertEquals(null, TreeWalk.forPath(or, "/a.b/", tree));
+			assertEquals(aDotB.getObjectId(),
+					TreeWalk.forPath(or, "a.b/", tree).getObjectId(0));
+
+			assertEquals(aZeroB.getObjectId(),
+					TreeWalk.forPath(or, "a0b", tree).getObjectId(0));
+
+			assertEquals(aSlashB.getObjectId(),
+					TreeWalk.forPath(or, "a/b", tree).getObjectId(0));
+			assertEquals(aSlashB.getObjectId(),
+					TreeWalk.forPath(or, "b", a).getObjectId(0));
+
+			assertEquals(aSlashC,
+					TreeWalk.forPath(or, "a/c", tree).getObjectId(0));
+			assertEquals(aSlashC, TreeWalk.forPath(or, "c", a).getObjectId(0));
+
+			assertEquals(aSlashCSlashD.getObjectId(),
+					TreeWalk.forPath(or, "a/c/d", tree).getObjectId(0));
+			assertEquals(aSlashCSlashD.getObjectId(),
+					TreeWalk.forPath(or, "c/d", a).getObjectId(0));
 		}
-
-		assertEquals(a, TreeWalk.forPath(or, "a", tree).getObjectId(0));
-		assertEquals(a, TreeWalk.forPath(or, "a/", tree).getObjectId(0));
-		assertEquals(null, TreeWalk.forPath(or, "/a", tree));
-		assertEquals(null, TreeWalk.forPath(or, "/a/", tree));
-
-		assertEquals(aDotB.getObjectId(), TreeWalk.forPath(or, "a.b", tree)
-				.getObjectId(0));
-		assertEquals(null, TreeWalk.forPath(or, "/a.b", tree));
-		assertEquals(null, TreeWalk.forPath(or, "/a.b/", tree));
-		assertEquals(aDotB.getObjectId(), TreeWalk.forPath(or, "a.b/", tree)
-				.getObjectId(0));
-
-		assertEquals(aZeroB.getObjectId(), TreeWalk.forPath(or, "a0b", tree)
-				.getObjectId(0));
-
-		assertEquals(aSlashB.getObjectId(), TreeWalk.forPath(or, "a/b", tree)
-				.getObjectId(0));
-		assertEquals(aSlashB.getObjectId(), TreeWalk.forPath(or, "b", a)
-				.getObjectId(0));
-
-		assertEquals(aSlashC, TreeWalk.forPath(or, "a/c", tree).getObjectId(0));
-		assertEquals(aSlashC, TreeWalk.forPath(or, "c", a).getObjectId(0));
-
-		assertEquals(aSlashCSlashD.getObjectId(),
-				TreeWalk.forPath(or, "a/c/d", tree).getObjectId(0));
-		assertEquals(aSlashCSlashD.getObjectId(), TreeWalk
-				.forPath(or, "c/d", a).getObjectId(0));
-
-		or.release();
-		oi.release();
 	}
 
 }
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkBasicDiffTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkBasicDiffTest.java
index b52a727..aca7c80 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkBasicDiffTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/treewalk/TreeWalkBasicDiffTest.java
@@ -63,52 +63,51 @@
 	@Test
 	public void testMissingSubtree_DetectFileAdded_FileModified()
 			throws Exception {
-		final ObjectInserter inserter = db.newObjectInserter();
-		final ObjectId aFileId = inserter.insert(OBJ_BLOB, encode("a"));
-		final ObjectId bFileId = inserter.insert(OBJ_BLOB, encode("b"));
-		final ObjectId cFileId1 = inserter.insert(OBJ_BLOB, encode("c-1"));
-		final ObjectId cFileId2 = inserter.insert(OBJ_BLOB, encode("c-2"));
+		final ObjectId oldTree, newTree, bFileId, cFileId1, cFileId2;
+		try (ObjectInserter inserter = db.newObjectInserter()) {
+			final ObjectId aFileId = inserter.insert(OBJ_BLOB, encode("a"));
+			bFileId = inserter.insert(OBJ_BLOB, encode("b"));
+			cFileId1 = inserter.insert(OBJ_BLOB, encode("c-1"));
+			cFileId2 = inserter.insert(OBJ_BLOB, encode("c-2"));
 
-		// Create sub-a/empty, sub-c/empty = hello.
-		final ObjectId oldTree;
-		{
-			final Tree root = new Tree(db);
+			// Create sub-a/empty, sub-c/empty = hello.
 			{
-				final Tree subA = root.addTree("sub-a");
-				subA.addFile("empty").setId(aFileId);
-				subA.setId(inserter.insert(OBJ_TREE, subA.format()));
+				final Tree root = new Tree(db);
+				{
+					final Tree subA = root.addTree("sub-a");
+					subA.addFile("empty").setId(aFileId);
+					subA.setId(inserter.insert(OBJ_TREE, subA.format()));
+				}
+				{
+					final Tree subC = root.addTree("sub-c");
+					subC.addFile("empty").setId(cFileId1);
+					subC.setId(inserter.insert(OBJ_TREE, subC.format()));
+				}
+				oldTree = inserter.insert(OBJ_TREE, root.format());
 			}
-			{
-				final Tree subC = root.addTree("sub-c");
-				subC.addFile("empty").setId(cFileId1);
-				subC.setId(inserter.insert(OBJ_TREE, subC.format()));
-			}
-			oldTree = inserter.insert(OBJ_TREE, root.format());
-		}
 
-		// Create sub-a/empty, sub-b/empty, sub-c/empty.
-		final ObjectId newTree;
-		{
-			final Tree root = new Tree(db);
+			// Create sub-a/empty, sub-b/empty, sub-c/empty.
 			{
-				final Tree subA = root.addTree("sub-a");
-				subA.addFile("empty").setId(aFileId);
-				subA.setId(inserter.insert(OBJ_TREE, subA.format()));
+				final Tree root = new Tree(db);
+				{
+					final Tree subA = root.addTree("sub-a");
+					subA.addFile("empty").setId(aFileId);
+					subA.setId(inserter.insert(OBJ_TREE, subA.format()));
+				}
+				{
+					final Tree subB = root.addTree("sub-b");
+					subB.addFile("empty").setId(bFileId);
+					subB.setId(inserter.insert(OBJ_TREE, subB.format()));
+				}
+				{
+					final Tree subC = root.addTree("sub-c");
+					subC.addFile("empty").setId(cFileId2);
+					subC.setId(inserter.insert(OBJ_TREE, subC.format()));
+				}
+				newTree = inserter.insert(OBJ_TREE, root.format());
 			}
-			{
-				final Tree subB = root.addTree("sub-b");
-				subB.addFile("empty").setId(bFileId);
-				subB.setId(inserter.insert(OBJ_TREE, subB.format()));
-			}
-			{
-				final Tree subC = root.addTree("sub-c");
-				subC.addFile("empty").setId(cFileId2);
-				subC.setId(inserter.insert(OBJ_TREE, subC.format()));
-			}
-			newTree = inserter.insert(OBJ_TREE, root.format());
+			inserter.flush();
 		}
-		inserter.flush();
-		inserter.release();
 
 		final TreeWalk tw = new TreeWalk(db);
 		tw.reset(oldTree, newTree);
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 6028618..f591edd 100644
--- a/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
+++ b/org.eclipse.jgit/resources/org/eclipse/jgit/internal/JGitText.properties
@@ -27,6 +27,7 @@
 badEscape=Bad escape: {0}
 badGroupHeader=Bad group header
 badObjectType=Bad object type: {0}
+badRef=Bad ref: {0}: {1}
 badSectionEntry=Bad section entry: {0}
 bareRepositoryNoWorkdirAndIndex=Bare Repository has neither a working tree, nor an index
 base64InputNotProperlyPadded=Base64 input not properly padded.
@@ -58,16 +59,23 @@
 cannotCreateTempDir=Cannot create a temp dir
 cannotDeleteCheckedOutBranch=Branch {0} is checked out and can not be deleted
 cannotDeleteFile=Cannot delete file: {0}
+cannotDeleteObjectsPath="Can't delete {0}/{1}: {2}
 cannotDeleteStaleTrackingRef=Cannot delete stale tracking ref {0}
 cannotDeleteStaleTrackingRef2=Cannot delete stale tracking ref {0}: {1}
 cannotDetermineProxyFor=Cannot determine proxy for {0}
 cannotDownload=Cannot download {0}
+cannotEnterObjectsPath=Can't enter {0}/objects: {1}
+cannotEnterPathFromParent=Can't enter {0} from {1}: {2}
 cannotExecute=cannot execute: {0}
 cannotGet=Cannot get {0}
+cannotGetObjectsPath=Can't get {0}/{1}: {2}
+cannotListObjectsPath=Can't ls {0}/{1}: {2}
+cannotListPackPath=Can't ls {0}/pack: {1}
 cannotListRefs=cannot list refs
 cannotLock=Cannot lock {0}
 cannotLockPackIn=Cannot lock pack in {0}
 cannotMatchOnEmptyString=Cannot match on empty string.
+cannotMkdirObjectPath=Can't mkdir {0}/{1}: {2}
 cannotMoveIndexTo=Cannot move index to {0}
 cannotMovePackTo=Cannot move pack to {0}
 cannotOpenService=cannot open {0}
@@ -80,13 +88,16 @@
 cannotReadFile=Cannot read file {0}
 cannotReadHEAD=cannot read HEAD: {0} {1}
 cannotReadObject=Cannot read object
+cannotReadObjectsPath=Cannot read {0}/{1}: {2}
 cannotReadTree=Cannot read tree {0}
 cannotRebaseWithoutCurrentHead=Can not rebase without a current HEAD
 cannotResolveLocalTrackingRefForUpdating=Cannot resolve local tracking ref {0} for updating.
 cannotSquashFixupWithoutPreviousCommit=Cannot {0} without previous commit.
 cannotStoreObjects=cannot store objects
+cannotResolveUniquelyAbbrevObjectId=Could not resolve uniquely the abbreviated object ID
 cannotUnloadAModifiedTree=Cannot unload a modified tree.
 cannotWorkWithOtherStagesThanZeroRightNow=Cannot work with other stages than zero right now. Won't write corrupt index.
+cannotWriteObjectsPath="Can't write {0}/{1}: {2}
 canOnlyCherryPickCommitsWithOneParent=Cannot cherry-pick commit ''{0}'' because it has {1} parents, only commits with exactly one parent are supported.
 canOnlyRevertCommitsWithOneParent=Cannot revert commit ''{0}'' because it has {1} parents, only commits with exactly one parent are supported
 commitDoesNotHaveGivenParent=The commit ''{0}'' does not have a parent number {1}.
@@ -113,26 +124,60 @@
 corruptionDetectedReReadingAt=Corruption detected re-reading at {0}
 corruptObjectBadStream=bad stream
 corruptObjectBadStreamCorruptHeader=bad stream, corrupt header
+corruptObjectDuplicateEntryNames=duplicate entry names
 corruptObjectGarbageAfterSize=garbage after size
 corruptObjectIncorrectLength=incorrect length
+corruptObjectIncorrectSorting=incorrectly sorted
+corruptObjectInvalidAuthor=invalid author
+corruptObjectInvalidCommitter=invalid committer
 corruptObjectInvalidEntryMode=invalid entry mode
 corruptObjectInvalidMode=invalid mode
-corruptObjectInvalidMode2=invalid mode {0}
+corruptObjectInvalidModeChar=invalid mode character
+corruptObjectInvalidModeStartsZero=mode starts with '0'
+corruptObjectInvalidMode2=invalid mode {0,number,#}
 corruptObjectInvalidMode3=invalid mode {0} for {1} ''{2}'' in {3}.
+corruptObjectInvalidName=invalid name '%s'
+corruptObjectInvalidNameAux=invalid name 'AUX'
+corruptObjectInvalidNameCon=invalid name 'CON'
+corruptObjectInvalidNameCom=invalid name 'COM%c'
+corruptObjectInvalidNameEnd=invalid name ends with '%c'
+corruptObjectInvalidNameIgnorableUnicode=invalid name '%s' contains ignorable Unicode characters
+corruptObjectInvalidNameInvalidUtf8=invalid name contains byte sequence ''{0}'' which is not a valid UTF-8 character
+corruptObjectInvalidNameLpt=invalid name 'LPT%c'
+corruptObjectInvalidNameNul=invalid name 'NUL'
+corruptObjectInvalidNamePrn=invalid name 'PRN'
+corruptObjectInvalidObject=invalid object
+corruptObjectInvalidParent=invalid parent
+corruptObjectInvalidTagger=invalid tagger
+corruptObjectInvalidTree=invalid tree
 corruptObjectInvalidType=invalid type
 corruptObjectInvalidType2=invalid type {0}
 corruptObjectMalformedHeader=malformed header: {0}
+corruptObjectNameContainsByte=name contains byte 0x%x
+corruptObjectNameContainsChar=name contains '%c'
+corruptObjectNameContainsNullByte=name contains byte 0x00
+corruptObjectNameContainsSlash=name contains '/'
+corruptObjectNameDot=invalid name '.'
+corruptObjectNameDotDot=invalid name '..'
+corruptObjectNameZeroLength=zero length name
 corruptObjectNegativeSize=negative size
 corruptObjectNoAuthor=no author
 corruptObjectNoCommitter=no committer
 corruptObjectNoHeader=no header
 corruptObjectNoObject=no object
+corruptObjectNoObjectHeader=no object header
 corruptObjectNoTaggerBadHeader=no tagger/bad header
 corruptObjectNoTaggerHeader=no tagger header
+corruptObjectNoTagHeader=no tag header
 corruptObjectNoTagName=no tag name
 corruptObjectNotree=no tree
+corruptObjectNotreeHeader=no tree header
 corruptObjectNoType=no type
+corruptObjectNoTypeHeader=no type header
 corruptObjectPackfileChecksumIncorrect=Packfile checksum incorrect.
+corruptObjectTruncatedInMode=truncated in mode
+corruptObjectTruncatedInName=truncated in name
+corruptObjectTruncatedInObjectId=truncated in object id
 couldNotCheckOutBecauseOfConflicts=Could not check out because of conflicts
 couldNotDeleteLockFileShouldNotHappen=Could not delete lock file. Should not happen
 couldNotDeleteTemporaryIndexFileShouldNotHappen=Could not delete temporary index file. Should not happen
@@ -144,6 +189,7 @@
 couldNotRenameDeleteOldIndex=Could not rename delete old index
 couldNotRenameTemporaryFile=Could not rename temporary file {0} to new location {1}
 couldNotRenameTemporaryIndexFileToIndex=Could not rename temporary index file to index
+couldNotRewindToUpstreamCommit=Could not rewind to upstream commit
 couldNotURLEncodeToUTF8=Could not URL encode to UTF-8
 couldNotWriteFile=Could not write file {0}
 countingObjects=Counting objects
@@ -180,6 +226,7 @@
 eitherGitDirOrWorkTreeRequired=One of setGitDir or setWorkTree must be called.
 emptyCommit=No changes
 emptyPathNotPermitted=Empty path not permitted.
+emptyRef=Empty ref: {0}
 encryptionError=Encryption error: {0}
 endOfFileInEscape=End of file in escape
 entryNotFoundByPath=Entry not found by path: {0}
@@ -240,6 +287,7 @@
 gcFailed=Garbage collection failed.
 gitmodulesNotFound=.gitmodules not found in tree.
 headRequiredToStash=HEAD required to stash local changes
+hiddenFilesStartWithDot=Hiding only allowed for names that start with a period
 hoursAgo={0} hours ago
 hugeIndexesAreNotSupportedByJgitYet=Huge indexes are not supported by jgit, yet
 hunkBelongsToAnotherFile=Hunk belongs to another file
@@ -276,8 +324,9 @@
 invalidEncryption=Invalid encryption
 invalidGitdirRef = Invalid .git reference in file ''{0}''
 invalidGitType=invalid git type: {0}
-invalidId=Invalid id {0}
+invalidId=Invalid id: {0}
 invalidIdLength=Invalid id length {0}; should be {1}
+invalidIgnoreParamSubmodule=Found invalid ignore param for submodule {0}.
 invalidIntegerValue=Invalid integer value: {0}.{1}={2}
 invalidKey=Invalid key: {0}
 invalidLineInConfigFile=Invalid line in config file
@@ -310,8 +359,10 @@
 largeObjectOutOfMemory=Out of memory loading {0}
 lengthExceedsMaximumArraySize=Length exceeds maximum array size
 listingAlternates=Listing alternates
+listingPacks=Listing packs
 localObjectsIncomplete=Local objects incomplete.
 localRefIsMissingObjects=Local ref {0} is missing object(s).
+localRepository=local repository
 lockCountMustBeGreaterOrEqual1=lockCount must be >= 1
 lockError=lock error: {0}
 lockOnNotClosed=Lock on {0} not closed.
@@ -410,6 +461,8 @@
 pathNotConfigured=Submodule path is not configured
 peeledLineBeforeRef=Peeled line before ref.
 peerDidNotSupplyACompleteObjectGraph=peer did not supply a complete object graph
+personIdentEmailNonNull=E-mail address of PersonIdent must not be null.
+personIdentNameNonNull=Name of PersonIdent must not be null.
 prefixRemote=remote: 
 problemWithResolvingPushRefSpecsLocally=Problem with resolving push ref specs locally: {0}
 progressMonUploading=Uploading {0}
@@ -453,6 +506,7 @@
 repositoryIsRequired=Repository is required.
 repositoryNotFound=repository not found: {0}
 repositoryState_applyMailbox=Apply mailbox
+repositoryState_bare=Bare
 repositoryState_bisecting=Bisecting
 repositoryState_conflicts=Conflicts
 repositoryState_merged=Merged
@@ -466,6 +520,9 @@
 resolvingDeltas=Resolving deltas
 resultLengthIncorrect=result length incorrect
 rewinding=Rewinding to commit {0}
+s3ActionDeletion=Deletion
+s3ActionReading=Reading
+s3ActionWriting=Writing
 searchForReuse=Finding sources
 searchForSizes=Getting sizes
 secondsAgo={0} seconds ago
@@ -547,6 +604,7 @@
 unencodeableFile=Unencodable file: {0}
 unexpectedCompareResult=Unexpected metadata comparison result: {0}
 unexpectedEndOfConfigFile=Unexpected end of config file
+unexpectedEndOfInput=Unexpected end of input
 unexpectedHunkTrailer=Unexpected hunk trailer
 unexpectedOddResult=odd: {0} + {1} - {2}
 unexpectedRefReport={0}: unexpected ref report: {1}
@@ -558,6 +616,7 @@
 unknownIndexVersionOrCorruptIndex=Unknown index version (or corrupt index): {0}
 unknownObject=unknown object
 unknownObjectType=Unknown object type {0}.
+unknownObjectType2=unknown
 unknownRepositoryFormat=Unknown repository format
 unknownRepositoryFormat2=Unknown repository format "{0}"; expected "0".
 unknownZlibError=Unknown zlib error.
@@ -566,16 +625,21 @@
 unpackException=Exception while parsing pack stream
 unreadablePackIndex=Unreadable pack index: {0}
 unrecognizedRef=Unrecognized ref: {0}
+unsetMark=Mark not set
+unsupportedAlternates=Alternates not supported
 unsupportedArchiveFormat=Unknown archive format ''{0}''
 unsupportedCommand0=unsupported command 0
 unsupportedEncryptionAlgorithm=Unsupported encryption algorithm: {0}
 unsupportedEncryptionVersion=Unsupported encryption version: {0}
 unsupportedGC=Unsupported garbage collector for repository type: {0}
+unsupportedMark=Mark not supported
 unsupportedOperationNotAddAtEnd=Not add-at-end: {0}
 unsupportedPackIndexVersion=Unsupported pack index version {0}
 unsupportedPackVersion=Unsupported pack version {0}.
+updatingHeadFailed=Updating HEAD failed
 updatingReferences=Updating references
 updatingRefFailed=Updating the ref {0} to {1} failed. ReturnCode from RefUpdate.update() was {2}
+upstreamBranchName=branch ''{0}'' of {1}
 uriNotConfigured=Submodule URI not configured
 uriNotFound={0} not found
 URINotSupported=URI not supported: {0}
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 a4ad2c9..a664660 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/CreateBranchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/CreateBranchCommand.java
@@ -124,8 +124,7 @@
 			RefNotFoundException, InvalidRefNameException {
 		checkCallable();
 		processOptions();
-		RevWalk revWalk = new RevWalk(repo);
-		try {
+		try (RevWalk revWalk = new RevWalk(repo)) {
 			Ref refToCheck = repo.getRef(name);
 			boolean exists = refToCheck != null
 					&& refToCheck.getName().startsWith(Constants.R_HEADS);
@@ -270,8 +269,6 @@
 			return result;
 		} catch (IOException ioe) {
 			throw new JGitInternalException(ioe.getMessage(), ioe);
-		} finally {
-			revWalk.release();
 		}
 	}
 
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 30b27f2..61beb2f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/DeleteBranchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/DeleteBranchCommand.java
@@ -108,18 +108,21 @@
 			if (!force) {
 				// check if the branches to be deleted
 				// are all merged into the current branch
-				RevWalk walk = new RevWalk(repo);
-				RevCommit tip = walk.parseCommit(repo.resolve(Constants.HEAD));
-				for (String branchName : branchNames) {
-					if (branchName == null)
-						continue;
-					Ref currentRef = repo.getRef(branchName);
-					if (currentRef == null)
-						continue;
+				try (RevWalk walk = new RevWalk(repo)) {
+					RevCommit tip = walk
+							.parseCommit(repo.resolve(Constants.HEAD));
+					for (String branchName : branchNames) {
+						if (branchName == null)
+							continue;
+						Ref currentRef = repo.getRef(branchName);
+						if (currentRef == null)
+							continue;
 
-					RevCommit base = walk.parseCommit(repo.resolve(branchName));
-					if (!walk.isMergedInto(base, tip)) {
-						throw new NotMergedException();
+						RevCommit base = walk
+								.parseCommit(repo.resolve(branchName));
+						if (!walk.isMergedInto(base, tip)) {
+							throw new NotMergedException();
+						}
 					}
 				}
 			}
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 10f33de..904c74f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ListBranchCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ListBranchCommand.java
@@ -139,8 +139,7 @@
 		if (containsCommitish == null)
 			return refs;
 
-		RevWalk walk = new RevWalk(repo);
-		try {
+		try (RevWalk walk = new RevWalk(repo)) {
 			ObjectId resolved = repo.resolve(containsCommitish);
 			if (resolved == null)
 				throw new RefNotFoundException(MessageFormat.format(
@@ -149,8 +148,6 @@
 			RevCommit containsCommit = walk.parseCommit(resolved);
 			return RevWalkUtils.findBranchesReachableFrom(containsCommit, walk,
 					refs);
-		} finally {
-			walk.release();
 		}
 	}
 
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 84fa355..796ac79 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ListNotesCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ListNotesCommand.java
@@ -80,9 +80,8 @@
 	public List<Note> call() throws GitAPIException {
 		checkCallable();
 		List<Note> notes = new ArrayList<Note>();
-		RevWalk walk = new RevWalk(repo);
 		NoteMap map = NoteMap.newEmptyMap();
-		try {
+		try (RevWalk walk = new RevWalk(repo)) {
 			Ref ref = repo.getRef(notesRef);
 			// if we have a notes ref, use it
 			if (ref != null) {
@@ -95,8 +94,6 @@
 				notes.add(i.next());
 		} catch (IOException e) {
 			throw new JGitInternalException(e.getMessage(), e);
-		} finally {
-			walk.release();
 		}
 
 		return notes;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/ListTagCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/ListTagCommand.java
index a0a5d95..a3b701b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ListTagCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ListTagCommand.java
@@ -78,16 +78,13 @@
 		checkCallable();
 		Map<String, Ref> refList;
 		List<Ref> tags = new ArrayList<Ref>();
-		RevWalk revWalk = new RevWalk(repo);
-		try {
+		try (RevWalk revWalk = new RevWalk(repo)) {
 			refList = repo.getRefDatabase().getRefs(Constants.R_TAGS);
 			for (Ref ref : refList.values()) {
 				tags.add(ref);
 			}
 		} catch (IOException e) {
 			throw new JGitInternalException(e.getMessage(), e);
-		} finally {
-			revWalk.release();
 		}
 		Collections.sort(tags, new Comparator<Ref>() {
 			public int compare(Ref o1, Ref o2) {
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 83026a0..d2075a7 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeCommand.java
@@ -369,9 +369,11 @@
 						mergeStatus = MergeStatus.MERGED_NOT_COMMITTED;
 					}
 					if (commit && !squash) {
-						newHeadId = new Git(getRepository()).commit()
-								.setReflogComment(refLogMessage.toString())
-								.call().getId();
+						try (Git git = new Git(getRepository())) {
+							newHeadId = git.commit()
+									.setReflogComment(refLogMessage.toString())
+									.call().getId();
+						}
 						mergeStatus = MergeStatus.MERGED;
 					}
 					if (commit && squash) {
@@ -416,7 +418,7 @@
 							e), e);
 		} finally {
 			if (revWalk != null)
-				revWalk.release();
+				revWalk.close();
 		}
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeResult.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeResult.java
index 9dc33b5..6141e0c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeResult.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/MergeResult.java
@@ -69,7 +69,7 @@
 		FAST_FORWARD {
 			@Override
 			public String toString() {
-				return "Fast-forward";
+				return "Fast-forward"; //$NON-NLS-1$
 			}
 
 			@Override
@@ -83,7 +83,7 @@
 		FAST_FORWARD_SQUASHED {
 			@Override
 			public String toString() {
-				return "Fast-forward-squashed";
+				return "Fast-forward-squashed"; //$NON-NLS-1$
 			}
 
 			@Override
@@ -95,7 +95,7 @@
 		ALREADY_UP_TO_DATE {
 			@Override
 			public String toString() {
-				return "Already-up-to-date";
+				return "Already-up-to-date"; //$NON-NLS-1$
 			}
 
 			@Override
@@ -107,7 +107,7 @@
 		FAILED {
 			@Override
 			public String toString() {
-				return "Failed";
+				return "Failed"; //$NON-NLS-1$
 			}
 
 			@Override
@@ -119,7 +119,7 @@
 		MERGED {
 			@Override
 			public String toString() {
-				return "Merged";
+				return "Merged"; //$NON-NLS-1$
 			}
 
 			@Override
@@ -133,7 +133,7 @@
 		MERGED_SQUASHED {
 			@Override
 			public String toString() {
-				return "Merged-squashed";
+				return "Merged-squashed"; //$NON-NLS-1$
 			}
 
 			@Override
@@ -147,7 +147,7 @@
 		MERGED_SQUASHED_NOT_COMMITTED {
 			@Override
 			public String toString() {
-				return "Merged-squashed-not-committed";
+				return "Merged-squashed-not-committed"; //$NON-NLS-1$
 			}
 
 			@Override
@@ -159,7 +159,7 @@
 		CONFLICTING {
 			@Override
 			public String toString() {
-				return "Conflicting";
+				return "Conflicting"; //$NON-NLS-1$
 			}
 
 			@Override
@@ -173,7 +173,7 @@
 		ABORTED {
 			@Override
 			public String toString() {
-				return "Aborted";
+				return "Aborted"; //$NON-NLS-1$
 			}
 
 			@Override
@@ -186,7 +186,7 @@
 		 **/
 		MERGED_NOT_COMMITTED {
 			public String toString() {
-				return "Merged-not-committed";
+				return "Merged-not-committed"; //$NON-NLS-1$
 			}
 
 			@Override
@@ -198,7 +198,7 @@
 		NOT_SUPPORTED {
 			@Override
 			public String toString() {
-				return "Not-yet-supported";
+				return "Not-yet-supported"; //$NON-NLS-1$
 			}
 
 			@Override
@@ -213,7 +213,7 @@
 		 */
 		CHECKOUT_CONFLICT {
 			public String toString() {
-				return "Checkout Conflict";
+				return "Checkout Conflict"; //$NON-NLS-1$
 			}
 
 			@Override
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
index cdaf3ec..ac050dd 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/PullCommand.java
@@ -261,7 +261,7 @@
 			fetchRes = fetch.call();
 		} else {
 			// we can skip the fetch altogether
-			remoteUri = "local repository";
+			remoteUri = JGitText.get().localRepository;
 			fetchRes = null;
 		}
 
@@ -302,9 +302,9 @@
 			}
 		}
 
-		String upstreamName = "branch \'"
-				+ Repository.shortenRefName(remoteBranchName) + "\' of "
-				+ remoteUri;
+		String upstreamName = MessageFormat.format(
+				JGitText.get().upstreamBranchName,
+				Repository.shortenRefName(remoteBranchName), remoteUri);
 
 		PullResult result;
 		if (pullRebaseMode.rebase) {
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 82444ba..7196a2f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RebaseCommand.java
@@ -405,11 +405,12 @@
 						.call();
 			} catch (StashApplyFailureException e) {
 				conflicts = true;
-				RevWalk rw = new RevWalk(repo);
-				ObjectId stashId = repo.resolve(stash);
-				RevCommit commit = rw.parseCommit(stashId);
-				updateStashRef(commit, commit.getAuthorIdent(),
-						commit.getShortMessage());
+				try (RevWalk rw = new RevWalk(repo)) {
+					ObjectId stashId = repo.resolve(stash);
+					RevCommit commit = rw.parseCommit(stashId);
+					updateStashRef(commit, commit.getAuthorIdent(),
+							commit.getShortMessage());
+				}
 			}
 		}
 		return conflicts;
@@ -444,7 +445,7 @@
 		Collection<ObjectId> ids = or.resolve(step.getCommit());
 		if (ids.size() != 1)
 			throw new JGitInternalException(
-					"Could not resolve uniquely the abbreviated object ID");
+					JGitText.get().cannotResolveUniquelyAbbrevObjectId);
 		RevCommit commitToPick = walk.parseCommit(ids.iterator().next());
 		if (shouldPick) {
 			if (monitor.isCancelled())
@@ -518,21 +519,23 @@
 			// here we should skip this step in order to avoid
 			// confusing pseudo-changed
 			String ourCommitName = getOurCommitName();
-			CherryPickResult cherryPickResult = new Git(repo).cherryPick()
+			try (Git git = new Git(repo)) {
+				CherryPickResult cherryPickResult = git.cherryPick()
 					.include(commitToPick).setOurCommitName(ourCommitName)
 					.setReflogPrefix(REFLOG_PREFIX).setStrategy(strategy)
 					.call();
-			switch (cherryPickResult.getStatus()) {
-			case FAILED:
-				if (operation == Operation.BEGIN)
-					return abort(RebaseResult.failed(cherryPickResult
-							.getFailingPaths()));
-				else
+				switch (cherryPickResult.getStatus()) {
+				case FAILED:
+					if (operation == Operation.BEGIN)
+						return abort(RebaseResult
+								.failed(cherryPickResult.getFailingPaths()));
+					else
+						return stop(commitToPick, Status.STOPPED);
+				case CONFLICTING:
 					return stop(commitToPick, Status.STOPPED);
-			case CONFLICTING:
-				return stop(commitToPick, Status.STOPPED);
-			case OK:
-				newHead = cherryPickResult.getNewHead();
+				case OK:
+					newHead = cherryPickResult.getNewHead();
+				}
 			}
 		}
 		return null;
@@ -563,62 +566,67 @@
 			// Use the cherry-pick strategy if all non-first parents did not
 			// change. This is different from C Git, which always uses the merge
 			// strategy (see below).
-			if (otherParentsUnchanged) {
-				boolean isMerge = commitToPick.getParentCount() > 1;
-				String ourCommitName = getOurCommitName();
-				CherryPickCommand pickCommand = new Git(repo).cherryPick()
-						.include(commitToPick).setOurCommitName(ourCommitName)
-						.setReflogPrefix(REFLOG_PREFIX).setStrategy(strategy);
-				if (isMerge) {
-					pickCommand.setMainlineParentNumber(1);
-					// We write a MERGE_HEAD and later commit explicitly
-					pickCommand.setNoCommit(true);
-					writeMergeInfo(commitToPick, newParents);
-				}
-				CherryPickResult cherryPickResult = pickCommand.call();
-				switch (cherryPickResult.getStatus()) {
-				case FAILED:
-					if (operation == Operation.BEGIN)
-						return abort(RebaseResult.failed(cherryPickResult
-								.getFailingPaths()));
-					else
-						return stop(commitToPick, Status.STOPPED);
-				case CONFLICTING:
-					return stop(commitToPick, Status.STOPPED);
-				case OK:
+			try (Git git = new Git(repo)) {
+				if (otherParentsUnchanged) {
+					boolean isMerge = commitToPick.getParentCount() > 1;
+					String ourCommitName = getOurCommitName();
+					CherryPickCommand pickCommand = git.cherryPick()
+							.include(commitToPick)
+							.setOurCommitName(ourCommitName)
+							.setReflogPrefix(REFLOG_PREFIX)
+							.setStrategy(strategy);
 					if (isMerge) {
-						// Commit the merge (setup above using writeMergeInfo())
-						CommitCommand commit = new Git(repo).commit();
+						pickCommand.setMainlineParentNumber(1);
+						// We write a MERGE_HEAD and later commit explicitly
+						pickCommand.setNoCommit(true);
+						writeMergeInfo(commitToPick, newParents);
+					}
+					CherryPickResult cherryPickResult = pickCommand.call();
+					switch (cherryPickResult.getStatus()) {
+					case FAILED:
+						if (operation == Operation.BEGIN)
+							return abort(RebaseResult.failed(
+									cherryPickResult.getFailingPaths()));
+						else
+							return stop(commitToPick, Status.STOPPED);
+					case CONFLICTING:
+						return stop(commitToPick, Status.STOPPED);
+					case OK:
+						if (isMerge) {
+							// Commit the merge (setup above using
+							// writeMergeInfo())
+							CommitCommand commit = git.commit();
+							commit.setAuthor(commitToPick.getAuthorIdent());
+							commit.setReflogComment(REFLOG_PREFIX + " " //$NON-NLS-1$
+									+ commitToPick.getShortMessage());
+							newHead = commit.call();
+						} else
+							newHead = cherryPickResult.getNewHead();
+						break;
+					}
+				} else {
+					// Use the merge strategy to redo merges, which had some of
+					// their non-first parents rewritten
+					MergeCommand merge = git.merge()
+							.setFastForward(MergeCommand.FastForwardMode.NO_FF)
+							.setCommit(false);
+					for (int i = 1; i < commitToPick.getParentCount(); i++)
+						merge.include(newParents.get(i));
+					MergeResult mergeResult = merge.call();
+					if (mergeResult.getMergeStatus().isSuccessful()) {
+						CommitCommand commit = git.commit();
 						commit.setAuthor(commitToPick.getAuthorIdent());
+						commit.setMessage(commitToPick.getFullMessage());
 						commit.setReflogComment(REFLOG_PREFIX + " " //$NON-NLS-1$
 								+ commitToPick.getShortMessage());
 						newHead = commit.call();
-					} else
-						newHead = cherryPickResult.getNewHead();
-					break;
-				}
-			} else {
-				// Use the merge strategy to redo merges, which had some of
-				// their non-first parents rewritten
-				MergeCommand merge = new Git(repo).merge()
-						.setFastForward(MergeCommand.FastForwardMode.NO_FF)
-						.setCommit(false);
-				for (int i = 1; i < commitToPick.getParentCount(); i++)
-					merge.include(newParents.get(i));
-				MergeResult mergeResult = merge.call();
-				if (mergeResult.getMergeStatus().isSuccessful()) {
-					CommitCommand commit = new Git(repo).commit();
-					commit.setAuthor(commitToPick.getAuthorIdent());
-					commit.setMessage(commitToPick.getFullMessage());
-					commit.setReflogComment(REFLOG_PREFIX + " " //$NON-NLS-1$
-							+ commitToPick.getShortMessage());
-					newHead = commit.call();
-				} else {
-					if (operation == Operation.BEGIN
-							&& mergeResult.getMergeStatus() == MergeResult.MergeStatus.FAILED)
-						return abort(RebaseResult.failed(mergeResult
-								.getFailingPaths()));
-					return stop(commitToPick, Status.STOPPED);
+					} else {
+						if (operation == Operation.BEGIN && mergeResult
+								.getMergeStatus() == MergeResult.MergeStatus.FAILED)
+							return abort(RebaseResult
+									.failed(mergeResult.getFailingPaths()));
+						return stop(commitToPick, Status.STOPPED);
+					}
 				}
 			}
 		}
@@ -758,24 +766,25 @@
 		String commitMessage = rebaseState
 				.readFile(MESSAGE_SQUASH);
 
-		if (nextStep == null
-				|| ((nextStep.getAction() != Action.FIXUP) && (nextStep
-						.getAction() != Action.SQUASH))) {
-			// this is the last step in this sequence
-			if (sequenceContainsSquash) {
-				commitMessage = interactiveHandler
-						.modifyCommitMessage(commitMessage);
-			}
-			retNewHead = new Git(repo).commit()
-					.setMessage(stripCommentLines(commitMessage))
-					.setAmend(true).setNoVerify(true).call();
-			rebaseState.getFile(MESSAGE_SQUASH).delete();
-			rebaseState.getFile(MESSAGE_FIXUP).delete();
+		try (Git git = new Git(repo)) {
+			if (nextStep == null || ((nextStep.getAction() != Action.FIXUP)
+					&& (nextStep.getAction() != Action.SQUASH))) {
+				// this is the last step in this sequence
+				if (sequenceContainsSquash) {
+					commitMessage = interactiveHandler
+							.modifyCommitMessage(commitMessage);
+				}
+				retNewHead = git.commit()
+						.setMessage(stripCommentLines(commitMessage))
+						.setAmend(true).setNoVerify(true).call();
+				rebaseState.getFile(MESSAGE_SQUASH).delete();
+				rebaseState.getFile(MESSAGE_FIXUP).delete();
 
-		} else {
-			// Next step is either Squash or Fixup
-			retNewHead = new Git(repo).commit().setMessage(commitMessage)
-					.setAmend(true).setNoVerify(true).call();
+			} else {
+				// Next step is either Squash or Fixup
+				retNewHead = git.commit().setMessage(commitMessage)
+						.setAmend(true).setNoVerify(true).call();
+			}
 		}
 		return retNewHead;
 	}
@@ -878,7 +887,8 @@
 			case NO_CHANGE:
 				break;
 			default:
-				throw new JGitInternalException("Updating HEAD failed");
+				throw new JGitInternalException(
+						JGitText.get().updatingHeadFailed);
 			}
 			rup = repo.updateRef(Constants.HEAD);
 			rup.setRefLogMessage("rebase finished: returning to " + headName, //$NON-NLS-1$
@@ -890,7 +900,8 @@
 			case NO_CHANGE:
 				break;
 			default:
-				throw new JGitInternalException("Updating HEAD failed");
+				throw new JGitInternalException(
+						JGitText.get().updatingHeadFailed);
 			}
 		}
 	}
@@ -917,10 +928,10 @@
 		} finally {
 			dc.unlock();
 		}
-		RevWalk rw = new RevWalk(repo);
-		RevCommit commit = rw.parseCommit(repo.resolve(Constants.HEAD));
-		rw.release();
-		return commit;
+		try (RevWalk rw = new RevWalk(repo)) {
+			RevCommit commit = rw.parseCommit(repo.resolve(Constants.HEAD));
+			return commit;
+		}
 	}
 
 	/**
@@ -936,27 +947,29 @@
 			throw new UnmergedPathsException();
 
 		// determine whether we need to commit
-		TreeWalk treeWalk = new TreeWalk(repo);
-		treeWalk.reset();
-		treeWalk.setRecursive(true);
-		treeWalk.addTree(new DirCacheIterator(dc));
-		ObjectId id = repo.resolve(Constants.HEAD + "^{tree}"); //$NON-NLS-1$
-		if (id == null)
-			throw new NoHeadException(
-					JGitText.get().cannotRebaseWithoutCurrentHead);
+		boolean needsCommit;
+		try (TreeWalk treeWalk = new TreeWalk(repo)) {
+			treeWalk.reset();
+			treeWalk.setRecursive(true);
+			treeWalk.addTree(new DirCacheIterator(dc));
+			ObjectId id = repo.resolve(Constants.HEAD + "^{tree}"); //$NON-NLS-1$
+			if (id == null)
+				throw new NoHeadException(
+						JGitText.get().cannotRebaseWithoutCurrentHead);
 
-		treeWalk.addTree(id);
+			treeWalk.addTree(id);
 
-		treeWalk.setFilter(TreeFilter.ANY_DIFF);
+			treeWalk.setFilter(TreeFilter.ANY_DIFF);
 
-		boolean needsCommit = treeWalk.next();
-		treeWalk.release();
-
+			needsCommit = treeWalk.next();
+		}
 		if (needsCommit) {
-			CommitCommand commit = new Git(repo).commit();
-			commit.setMessage(rebaseState.readFile(MESSAGE));
-			commit.setAuthor(parseAuthor());
-			return commit.call();
+			try (Git git = new Git(repo)) {
+				CommitCommand commit = git.commit();
+				commit.setMessage(rebaseState.readFile(MESSAGE));
+				commit.setAuthor(parseAuthor());
+				return commit.call();
+			}
 		}
 		return null;
 	}
@@ -979,9 +992,10 @@
 		rebaseState.createFile(AUTHOR_SCRIPT, authorScript);
 		rebaseState.createFile(MESSAGE, commitToPick.getFullMessage());
 		ByteArrayOutputStream bos = new ByteArrayOutputStream();
-		DiffFormatter df = new DiffFormatter(bos);
-		df.setRepository(repo);
-		df.format(commitToPick.getParent(0), commitToPick);
+		try (DiffFormatter df = new DiffFormatter(bos)) {
+			df.setRepository(repo);
+			df.format(commitToPick.getParent(0), commitToPick);
+		}
 		rebaseState.createFile(PATCH, new String(bos.toByteArray(),
 				Constants.CHARACTER_ENCODING));
 		rebaseState.createFile(STOPPED_SHA,
@@ -1124,9 +1138,11 @@
 
 	private List<RevCommit> calculatePickList(RevCommit headCommit)
 			throws GitAPIException, NoHeadException, IOException {
-		LogCommand cmd = new Git(repo).log().addRange(upstreamCommit,
-				headCommit);
-		Iterable<RevCommit> commitsToUse = cmd.call();
+		Iterable<RevCommit> commitsToUse;
+		try (Git git = new Git(repo)) {
+			LogCommand cmd = git.log().addRange(upstreamCommit, headCommit);
+			commitsToUse = cmd.call();
+		}
 		List<RevCommit> cherryPickList = new ArrayList<RevCommit>();
 		for (RevCommit commit : commitsToUse) {
 			if (preserveMerges || commit.getParentCount() == 1)
@@ -1277,7 +1293,7 @@
 				if (this.upstreamCommit == null)
 					throw new JGitInternalException(MessageFormat
 							.format(JGitText.get().missingRequiredParameter,
-									"upstream"));
+									"upstream")); //$NON-NLS-1$
 				return;
 			default:
 				throw new WrongRepositoryStateException(MessageFormat.format(
@@ -1312,7 +1328,7 @@
 			}
 			dco.setFailOnConflict(false);
 			dco.checkout();
-			walk.release();
+			walk.close();
 		} finally {
 			monitor.endTask();
 		}
@@ -1384,10 +1400,11 @@
 			case FORCED:
 				break;
 			default:
-				throw new IOException("Could not rewind to upstream commit");
+				throw new IOException(
+						JGitText.get().couldNotRewindToUpstreamCommit);
 			}
 		} finally {
-			walk.release();
+			walk.close();
 			monitor.endTask();
 		}
 		return true;
@@ -1454,7 +1471,7 @@
 	public RebaseCommand setUpstreamName(String upstreamName) {
 		if (upstreamCommit == null) {
 			throw new IllegalStateException(
-					"setUpstreamName must be called after setUpstream.");
+					"setUpstreamName must be called after setUpstream."); //$NON-NLS-1$
 		}
 		this.upstreamCommitName = upstreamName;
 		return this;
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 d1e2770..a526c27 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoveNoteCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RemoveNoteCommand.java
@@ -81,11 +81,10 @@
 
 	public Note call() throws GitAPIException {
 		checkCallable();
-		RevWalk walk = new RevWalk(repo);
-		ObjectInserter inserter = repo.newObjectInserter();
-		NoteMap map = NoteMap.newEmptyMap();
-		RevCommit notesCommit = null;
-		try {
+		try (RevWalk walk = new RevWalk(repo);
+				ObjectInserter inserter = repo.newObjectInserter()) {
+			NoteMap map = NoteMap.newEmptyMap();
+			RevCommit notesCommit = null;
 			Ref ref = repo.getRef(notesRef);
 			// if we have a notes ref, use it
 			if (ref != null) {
@@ -94,13 +93,10 @@
 			}
 			map.set(id, null, inserter);
 			commitNoteMap(walk, map, notesCommit, inserter,
-					"Notes removed by 'git notes remove'");
+					"Notes removed by 'git notes remove'"); //$NON-NLS-1$
 			return map.getNote(id);
 		} catch (IOException e) {
 			throw new JGitInternalException(e.getMessage(), e);
-		} finally {
-			inserter.release();
-			walk.release();
 		}
 	}
 
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 ac67037..8f4bc4f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ResetCommand.java
@@ -157,8 +157,8 @@
 			if (ref != null && commitId == null) {
 				// @TODO throw an InvalidRefNameException. We can't do that
 				// now because this would break the API
-				throw new JGitInternalException("Invalid ref " + ref
-						+ " specified");
+				throw new JGitInternalException(MessageFormat
+						.format(JGitText.get().invalidRefName, ref));
 			}
 
 			final ObjectId commitTree;
@@ -234,17 +234,12 @@
 	}
 
 	private RevCommit parseCommit(final ObjectId commitId) {
-		RevCommit commit;
-		RevWalk rw = new RevWalk(repo);
-		try {
-			commit = rw.parseCommit(commitId);
+		try (RevWalk rw = new RevWalk(repo)) {
+			return rw.parseCommit(commitId);
 		} catch (IOException e) {
 			throw new JGitInternalException(MessageFormat.format(
 					JGitText.get().cannotReadCommit, commitId.toString()), e);
-		} finally {
-			rw.release();
 		}
-		return commit;
 	}
 
 	private ObjectId resolveRefToCommitId() {
@@ -276,7 +271,7 @@
 		if (!filepaths.isEmpty())
 			throw new JGitInternalException(MessageFormat.format(
 					JGitText.get().illegalCombinationOfArguments,
-					"[--mixed | --soft | --hard]", "<paths>...")); //$NON-NLS-1$
+					"[--mixed | --soft | --hard]", "<paths>...")); //$NON-NLS-1$ //$NON-NLS-2$
 		this.mode = mode;
 		return this;
 	}
@@ -290,7 +285,7 @@
 	public ResetCommand addPath(String path) {
 		if (mode != null)
 			throw new JGitInternalException(MessageFormat.format(
-					JGitText.get().illegalCombinationOfArguments, "<paths>...",
+					JGitText.get().illegalCombinationOfArguments, "<paths>...", //$NON-NLS-1$
 					"[--mixed | --soft | --hard]")); //$NON-NLS-1$
 		filepaths.add(path);
 		return this;
@@ -305,11 +300,10 @@
 
 	private void resetIndexForPaths(ObjectId commitTree) {
 		DirCache dc = null;
-		try {
+		try (final TreeWalk tw = new TreeWalk(repo)) {
 			dc = repo.lockDirCache();
 			DirCacheBuilder builder = dc.builder();
 
-			final TreeWalk tw = new TreeWalk(repo);
 			tw.addTree(new DirCacheBuildIterator(builder));
 			if (commitTree != null)
 				tw.addTree(commitTree);
@@ -342,11 +336,9 @@
 
 	private void resetIndex(ObjectId commitTree) throws IOException {
 		DirCache dc = repo.lockDirCache();
-		TreeWalk walk = null;
-		try {
+		try (TreeWalk walk = new TreeWalk(repo)) {
 			DirCacheBuilder builder = dc.builder();
 
-			walk = new TreeWalk(repo);
 			if (commitTree != null)
 				walk.addTree(commitTree);
 			else
@@ -380,8 +372,6 @@
 			builder.commit();
 		} finally {
 			dc.unlock();
-			if (walk != null)
-				walk.release();
 		}
 	}
 
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 470d823..8015773 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RevertCommand.java
@@ -126,8 +126,7 @@
 		RevCommit newHead = null;
 		checkCallable();
 
-		RevWalk revWalk = new RevWalk(repo);
-		try {
+		try (RevWalk revWalk = new RevWalk(repo)) {
 
 			// get the head commit
 			Ref headRef = repo.getRef(Constants.HEAD);
@@ -182,9 +181,11 @@
 							merger.getResultTreeId());
 					dco.setFailOnConflict(true);
 					dco.checkout();
-					newHead = new Git(getRepository()).commit()
-							.setMessage(newMessage)
-							.setReflogComment("revert: " + shortMessage).call(); //$NON-NLS-1$
+					try (Git git = new Git(getRepository())) {
+						newHead = git.commit().setMessage(newMessage)
+								.setReflogComment("revert: " + shortMessage) //$NON-NLS-1$
+								.call();
+					}
 					revertedRefs.add(src);
 					headCommit = newHead;
 				} else {
@@ -220,8 +221,6 @@
 					MessageFormat.format(
 									JGitText.get().exceptionCaughtDuringExecutionOfRevertCommand,
 							e), e);
-		} finally {
-			revWalk.release();
 		}
 		return newHead;
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/RmCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/RmCommand.java
index c70b4ae..fd2cbe0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/RmCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/RmCommand.java
@@ -144,10 +144,9 @@
 		checkCallable();
 		DirCache dc = null;
 
-		try {
+		try (final TreeWalk tw = new TreeWalk(repo)) {
 			dc = repo.lockDirCache();
 			DirCacheBuilder builder = dc.builder();
-			final TreeWalk tw = new TreeWalk(repo);
 			tw.reset(); // drop the first empty tree, which we do not need here
 			tw.setRecursive(true);
 			tw.setFilter(PathFilterGroup.createFromStrings(filepatterns));
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 7d411c3..82db881 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/ShowNoteCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/ShowNoteCommand.java
@@ -76,10 +76,9 @@
 
 	public Note call() throws GitAPIException {
 		checkCallable();
-		RevWalk walk = new RevWalk(repo);
 		NoteMap map = NoteMap.newEmptyMap();
 		RevCommit notesCommit = null;
-		try {
+		try (RevWalk walk = new RevWalk(repo)) {
 			Ref ref = repo.getRef(notesRef);
 			// if we have a notes ref, use it
 			if (ref != null) {
@@ -89,8 +88,6 @@
 			return map.getNote(id);
 		} catch (IOException e) {
 			throw new JGitInternalException(e.getMessage(), e);
-		} finally {
-			walk.release();
 		}
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
index 356723d..6de25a0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashApplyCommand.java
@@ -166,9 +166,8 @@
 					JGitText.get().stashApplyOnUnsafeRepository,
 					repo.getRepositoryState()));
 
-		ObjectReader reader = repo.newObjectReader();
-		try {
-			RevWalk revWalk = new RevWalk(reader);
+		try (ObjectReader reader = repo.newObjectReader();
+				RevWalk revWalk = new RevWalk(reader)) {
 
 			ObjectId headCommit = repo.resolve(Constants.HEAD);
 			if (headCommit == null)
@@ -192,8 +191,8 @@
 				untrackedCommit = revWalk.parseCommit(stashCommit.getParent(2));
 
 			ResolveMerger merger = (ResolveMerger) strategy.newMerger(repo);
-			merger.setCommitNames(new String[] { "stashed HEAD", "HEAD",
-					"stash" });
+			merger.setCommitNames(new String[] { "stashed HEAD", "HEAD", //$NON-NLS-1$ //$NON-NLS-2$
+					"stash" }); //$NON-NLS-1$
 			merger.setBase(stashHeadCommit);
 			merger.setWorkingTreeIterator(new FileTreeIterator(repo));
 			if (merger.merge(headCommit, stashCommit)) {
@@ -205,8 +204,8 @@
 				if (applyIndex) {
 					ResolveMerger ixMerger = (ResolveMerger) strategy
 							.newMerger(repo, true);
-					ixMerger.setCommitNames(new String[] { "stashed HEAD",
-							"HEAD", "stashed index" });
+					ixMerger.setCommitNames(new String[] { "stashed HEAD", //$NON-NLS-1$
+							"HEAD", "stashed index" }); //$NON-NLS-1$//$NON-NLS-2$
 					ixMerger.setBase(stashHeadCommit);
 					boolean ok = ixMerger.merge(headCommit, stashIndexCommit);
 					if (ok) {
@@ -250,8 +249,6 @@
 			throw e;
 		} catch (IOException e) {
 			throw new JGitInternalException(JGitText.get().stashApplyFailed, e);
-		} finally {
-			reader.release();
 		}
 	}
 
@@ -286,11 +283,9 @@
 
 	private void resetIndex(RevTree tree) throws IOException {
 		DirCache dc = repo.lockDirCache();
-		TreeWalk walk = null;
-		try {
+		try (TreeWalk walk = new TreeWalk(repo)) {
 			DirCacheBuilder builder = dc.builder();
 
-			walk = new TreeWalk(repo);
 			walk.addTree(tree);
 			walk.addTree(new DirCacheIterator(dc));
 			walk.setRecursive(true);
@@ -321,15 +316,13 @@
 			builder.commit();
 		} finally {
 			dc.unlock();
-			if (walk != null)
-				walk.release();
 		}
 	}
 
 	private void resetUntracked(RevTree tree) throws CheckoutConflictException,
 			IOException {
-		TreeWalk walk = new TreeWalk(repo); // maybe NameConflictTreeWalk;
-		try {
+		// TODO maybe NameConflictTreeWalk ?
+		try (TreeWalk walk = new TreeWalk(repo)) {
 			walk.addTree(tree);
 			walk.addTree(new FileTreeIterator(repo));
 			walk.setRecursive(true);
@@ -359,8 +352,6 @@
 
 				checkoutPath(entry, reader);
 			}
-		} finally {
-			walk.release();
 		}
 	}
 
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 f4d443d..2cdaf24 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashCreateCommand.java
@@ -94,11 +94,11 @@
  */
 public class StashCreateCommand extends GitCommand<RevCommit> {
 
-	private static final String MSG_INDEX = "index on {0}: {1} {2}";
+	private static final String MSG_INDEX = "index on {0}: {1} {2}"; //$NON-NLS-1$
 
-	private static final String MSG_UNTRACKED = "untracked files on {0}: {1} {2}";
+	private static final String MSG_UNTRACKED = "untracked files on {0}: {1} {2}"; //$NON-NLS-1$
 
-	private static final String MSG_WORKING_DIR = "WIP on {0}: {1} {2}";
+	private static final String MSG_WORKING_DIR = "WIP on {0}: {1} {2}"; //$NON-NLS-1$
 
 	private String indexMessage = MSG_INDEX;
 
@@ -187,8 +187,9 @@
 
 	private RevCommit parseCommit(final ObjectReader reader,
 			final ObjectId headId) throws IOException {
-		final RevWalk walk = new RevWalk(reader);
-		return walk.parseCommit(headId);
+		try (final RevWalk walk = new RevWalk(reader)) {
+			return walk.parseCommit(headId);
+		}
 	}
 
 	private CommitBuilder createBuilder() {
@@ -239,14 +240,13 @@
 		checkCallable();
 
 		Ref head = getHead();
-		ObjectReader reader = repo.newObjectReader();
-		try {
+		try (ObjectReader reader = repo.newObjectReader()) {
 			RevCommit headCommit = parseCommit(reader, head.getObjectId());
 			DirCache cache = repo.lockDirCache();
-			ObjectInserter inserter = repo.newObjectInserter();
 			ObjectId commitId;
-			try {
-				TreeWalk treeWalk = new TreeWalk(reader);
+			try (ObjectInserter inserter = repo.newObjectInserter();
+					TreeWalk treeWalk = new TreeWalk(reader)) {
+
 				treeWalk.setRecursive(true);
 				treeWalk.addTree(headCommit.getTree());
 				treeWalk.addTree(new DirCacheIterator(cache));
@@ -380,7 +380,6 @@
 				}
 
 			} finally {
-				inserter.release();
 				cache.unlock();
 			}
 
@@ -391,8 +390,6 @@
 			return parseCommit(reader, commitId);
 		} catch (IOException e) {
 			throw new JGitInternalException(JGitText.get().stashFailed, e);
-		} finally {
-			reader.release();
 		}
 	}
 }
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 6cbcd06..7923fd4 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/StashDropCommand.java
@@ -52,6 +52,7 @@
 import org.eclipse.jgit.api.errors.GitAPIException;
 import org.eclipse.jgit.api.errors.InvalidRefNameException;
 import org.eclipse.jgit.api.errors.JGitInternalException;
+import org.eclipse.jgit.api.errors.RefNotFoundException;
 import org.eclipse.jgit.errors.LockFailedException;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.internal.storage.file.ReflogWriter;
@@ -184,6 +185,10 @@
 		List<ReflogEntry> entries;
 		try {
 			ReflogReader reader = repo.getReflogReader(R_STASH);
+			if (reader == null) {
+				throw new RefNotFoundException(MessageFormat
+						.format(JGitText.get().refNotResolved, stashRef));
+			}
 			entries = reader.getReverseEntries();
 		} catch (IOException e) {
 			throw new JGitInternalException(JGitText.get().stashDropFailed, e);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
index 81a3015..e288d77 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/SubmoduleUpdateCommand.java
@@ -143,8 +143,7 @@
 			RefNotFoundException, GitAPIException {
 		checkCallable();
 
-		try {
-			SubmoduleWalk generator = SubmoduleWalk.forIndex(repo);
+		try (SubmoduleWalk generator = SubmoduleWalk.forIndex(repo)) {
 			if (!paths.isEmpty())
 				generator.setFilter(PathFilterGroup.createFromStrings(paths));
 			List<String> updated = new ArrayList<String>();
@@ -171,8 +170,7 @@
 					submoduleRepo = clone.call().getRepository();
 				}
 
-				try {
-					RevWalk walk = new RevWalk(submoduleRepo);
+				try (RevWalk walk = new RevWalk(submoduleRepo)) {
 					RevCommit commit = walk
 							.parseCommit(generator.getObjectId());
 
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 8570baa..ca98ced 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/api/TagCommand.java
@@ -128,8 +128,7 @@
 		RepositoryState state = repo.getRepositoryState();
 		processOptions(state);
 
-		RevWalk revWalk = new RevWalk(repo);
-		try {
+		try (RevWalk revWalk = new RevWalk(repo)) {
 			// if no id is set, we should attempt to use HEAD
 			if (id == null) {
 				ObjectId objectId = repo.resolve(Constants.HEAD + "^{commit}"); //$NON-NLS-1$
@@ -157,24 +156,19 @@
 			newTag.setObjectId(id);
 
 			// write the tag object
-			ObjectInserter inserter = repo.newObjectInserter();
-			try {
+			try (ObjectInserter inserter = repo.newObjectInserter()) {
 				ObjectId tagId = inserter.insert(newTag);
 				inserter.flush();
 
 				String tag = newTag.getTag();
 				return updateTagRef(tagId, revWalk, tag, newTag.toString());
 
-			} finally {
-				inserter.release();
 			}
 
 		} catch (IOException e) {
 			throw new JGitInternalException(
 					JGitText.get().exceptionCaughtDuringExecutionOfTagCommand,
 					e);
-		} finally {
-			revWalk.release();
 		}
 	}
 
@@ -222,8 +216,9 @@
 		if (tagger == null && annotated)
 			tagger = new PersonIdent(repo);
 		if (name == null || !Repository.isValidRefName(Constants.R_TAGS + name))
-			throw new InvalidTagNameException(MessageFormat.format(JGitText
-					.get().tagNameInvalid, name == null ? "<null>" : name));
+			throw new InvalidTagNameException(
+					MessageFormat.format(JGitText.get().tagNameInvalid,
+							name == null ? "<null>" : name)); //$NON-NLS-1$
 		if (signed)
 			throw new UnsupportedOperationException(
 					JGitText.get().signingNotSupportedOnTag);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java
index ae713e2..fa6fe75 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/blame/BlameGenerator.java
@@ -172,7 +172,7 @@
 			throw new IllegalStateException();
 
 		if (revPool != null)
-			revPool.release();
+			revPool.close();
 
 		if (reverse)
 			revPool = new ReverseWalk(getRepository());
@@ -450,7 +450,7 @@
 				r.computeAll();
 			return r;
 		} finally {
-			release();
+			close();
 		}
 	}
 
@@ -513,7 +513,7 @@
 	}
 
 	private boolean done() {
-		release();
+		close();
 		return false;
 	}
 
@@ -937,14 +937,6 @@
 	}
 
 	/**
-	 * Release the current blame session. Use {@link #close()} instead.
-	 */
-	@Deprecated
-	public void release() {
-		close();
-	}
-
-	/**
 	 * Release the current blame session.
 	 *
 	 * @since 4.0
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
index b71e990..bcc30c3 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/DiffFormatter.java
@@ -381,14 +381,6 @@
 	}
 
 	/**
-	 * Release the internal ObjectReader state. Use {@link #close()} instead.
-	 */
-	@Deprecated
-	public void release() {
-		close();
-	}
-
-	/**
 	 * Release the internal ObjectReader state.
 	 *
 	 * @since 4.0
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RenameDetector.java b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RenameDetector.java
index b819ad0..8865b62 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/diff/RenameDetector.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/diff/RenameDetector.java
@@ -323,7 +323,7 @@
 			try {
 				return compute(objectReader, pm);
 			} finally {
-				objectReader.release();
+				objectReader.close();
 			}
 		}
 		return Collections.unmodifiableList(entries);
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
index f124165..f316ea9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/dircache/DirCacheCheckout.java
@@ -403,8 +403,7 @@
 			MissingObjectException, IncorrectObjectTypeException,
 			CheckoutConflictException, IndexWriteException {
 		toBeDeleted.clear();
-		ObjectReader objectReader = repo.getObjectDatabase().newReader();
-		try {
+		try (ObjectReader objectReader = repo.getObjectDatabase().newReader()) {
 			if (headCommitTree != null)
 				preScanTwoTrees();
 			else
@@ -454,8 +453,6 @@
 			// commit the index builder - a new index is persisted
 			if (!builder.commit())
 				throw new IndexWriteException();
-		} finally {
-			objectReader.release();
 		}
 		return toBeDeleted.size() == 0;
 	}
@@ -1056,8 +1053,7 @@
 	 */
 	private boolean isModifiedSubtree_IndexWorkingtree(String path)
 			throws CorruptObjectException, IOException {
-		NameConflictTreeWalk tw = new NameConflictTreeWalk(repo);
-		try {
+		try (NameConflictTreeWalk tw = new NameConflictTreeWalk(repo)) {
 			tw.addTree(new DirCacheIterator(dc));
 			tw.addTree(new FileTreeIterator(repo));
 			tw.setRecursive(true);
@@ -1075,8 +1071,6 @@
 				}
 			}
 			return false;
-		} finally {
-			tw.release();
 		}
 	}
 
@@ -1105,8 +1099,7 @@
 	 */
 	private boolean isModifiedSubtree_IndexTree(String path, ObjectId tree)
 			throws CorruptObjectException, IOException {
-		NameConflictTreeWalk tw = new NameConflictTreeWalk(repo);
-		try {
+		try (NameConflictTreeWalk tw = new NameConflictTreeWalk(repo)) {
 			tw.addTree(new DirCacheIterator(dc));
 			tw.addTree(tree);
 			tw.setRecursive(true);
@@ -1124,8 +1117,6 @@
 					return true;
 			}
 			return false;
-		} finally {
-			tw.release();
 		}
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
new file mode 100644
index 0000000..ec9fdfa
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/ManifestParser.java
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2015, Google Inc.
+ * 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.gitrepo;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import org.eclipse.jgit.api.errors.GitAPIException;
+import org.eclipse.jgit.gitrepo.RepoProject.CopyFile;
+import org.eclipse.jgit.gitrepo.internal.RepoText;
+import org.eclipse.jgit.internal.JGitText;
+import org.eclipse.jgit.lib.Repository;
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ * Repo XML manifest parser.
+ *
+ * @see <a href="https://code.google.com/p/git-repo/">git-repo project page</a>
+ * @since 4.0
+ */
+public class ManifestParser extends DefaultHandler {
+	private final String filename;
+	private final String baseUrl;
+	private final String defaultBranch;
+	private final Repository rootRepo;
+	private final Map<String, String> remotes;
+	private final Set<String> plusGroups;
+	private final Set<String> minusGroups;
+	private final List<RepoProject> projects;
+	private final List<RepoProject> filteredProjects;
+	private final IncludedFileReader includedReader;
+
+	private String defaultRemote;
+	private String defaultRevision;
+	private int xmlInRead;
+	private RepoProject currentProject;
+
+	/**
+	 * A callback to read included xml files.
+	 */
+	public interface IncludedFileReader {
+		/**
+		 * Read a file from the same base dir of the manifest xml file.
+		 *
+		 * @param path
+		 *            The relative path to the file to read
+		 * @return the {@code InputStream} of the file.
+		 * @throws GitAPIException
+		 * @throws IOException
+		 */
+		public InputStream readIncludeFile(String path)
+				throws GitAPIException, IOException;
+	}
+
+	/**
+	 * @param includedReader
+	 * @param filename
+	 * @param defaultBranch
+	 * @param baseUrl
+	 * @param groups
+	 * @param rootRepo
+	 */
+	public ManifestParser(IncludedFileReader includedReader, String filename,
+			String defaultBranch, String baseUrl, String groups,
+			Repository rootRepo) {
+		this.includedReader = includedReader;
+		this.filename = filename;
+		this.defaultBranch = defaultBranch;
+		this.rootRepo = rootRepo;
+
+		// Strip trailing /s to match repo behavior.
+		int lastIndex = baseUrl.length() - 1;
+		while (lastIndex >= 0 && baseUrl.charAt(lastIndex) == '/')
+			lastIndex--;
+		this.baseUrl = baseUrl.substring(0, lastIndex + 1);
+
+		plusGroups = new HashSet<String>();
+		minusGroups = new HashSet<String>();
+		if (groups == null || groups.length() == 0
+				|| groups.equals("default")) { //$NON-NLS-1$
+			// default means "all,-notdefault"
+			minusGroups.add("notdefault"); //$NON-NLS-1$
+		} else {
+			for (String group : groups.split(",")) { //$NON-NLS-1$
+				if (group.startsWith("-")) //$NON-NLS-1$
+					minusGroups.add(group.substring(1));
+				else
+					plusGroups.add(group);
+			}
+		}
+
+		remotes = new HashMap<String, String>();
+		projects = new ArrayList<RepoProject>();
+		filteredProjects = new ArrayList<RepoProject>();
+	}
+
+	/**
+	 * Read the xml file.
+	 *
+	 * @param inputStream
+	 * @throws IOException
+	 */
+	public void read(InputStream inputStream) throws IOException {
+		xmlInRead++;
+		final XMLReader xr;
+		try {
+			xr = XMLReaderFactory.createXMLReader();
+		} catch (SAXException e) {
+			throw new IOException(JGitText.get().noXMLParserAvailable);
+		}
+		xr.setContentHandler(this);
+		try {
+			xr.parse(new InputSource(inputStream));
+		} catch (SAXException e) {
+			IOException error = new IOException(
+						RepoText.get().errorParsingManifestFile);
+			error.initCause(e);
+			throw error;
+		}
+	}
+
+	@Override
+	public void startElement(
+			String uri,
+			String localName,
+			String qName,
+			Attributes attributes) throws SAXException {
+		if ("project".equals(qName)) { //$NON-NLS-1$
+			currentProject = new RepoProject(
+					attributes.getValue("name"), //$NON-NLS-1$
+					attributes.getValue("path"), //$NON-NLS-1$
+					attributes.getValue("revision"), //$NON-NLS-1$
+					attributes.getValue("remote"), //$NON-NLS-1$
+					attributes.getValue("groups")); //$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$
+			remotes.put(attributes.getValue("name"), fetch); //$NON-NLS-1$
+			if (alias != null)
+				remotes.put(alias, fetch);
+		} else if ("default".equals(qName)) { //$NON-NLS-1$
+			defaultRemote = attributes.getValue("remote"); //$NON-NLS-1$
+			defaultRevision = attributes.getValue("revision"); //$NON-NLS-1$
+			if (defaultRevision == null)
+				defaultRevision = defaultBranch;
+		} else if ("copyfile".equals(qName)) { //$NON-NLS-1$
+			if (currentProject == null)
+				throw new SAXException(RepoText.get().invalidManifest);
+			currentProject.addCopyFile(new CopyFile(
+						rootRepo,
+						currentProject.path,
+						attributes.getValue("src"), //$NON-NLS-1$
+						attributes.getValue("dest"))); //$NON-NLS-1$
+		} else if ("include".equals(qName)) { //$NON-NLS-1$
+			String name = attributes.getValue("name"); //$NON-NLS-1$
+			InputStream is = null;
+			if (includedReader != null) {
+				try {
+					is = includedReader.readIncludeFile(name);
+				} catch (Exception e) {
+					throw new SAXException(MessageFormat.format(
+							RepoText.get().errorIncludeFile, name), e);
+				}
+			} else if (filename != null) {
+				int index = filename.lastIndexOf('/');
+				String path = filename.substring(0, index + 1) + name;
+				try {
+					is = new FileInputStream(path);
+				} catch (IOException e) {
+					throw new SAXException(MessageFormat.format(
+							RepoText.get().errorIncludeFile, path), e);
+				}
+			}
+			if (is == null) {
+				throw new SAXException(
+						RepoText.get().errorIncludeNotImplemented);
+			}
+			try {
+				read(is);
+			} catch (IOException e) {
+				throw new SAXException(e);
+			}
+		}
+	}
+
+	@Override
+	public void endElement(
+			String uri,
+			String localName,
+			String qName) throws SAXException {
+		if ("project".equals(qName)) { //$NON-NLS-1$
+			projects.add(currentProject);
+			currentProject = null;
+		}
+	}
+
+	@Override
+	public void endDocument() throws SAXException {
+		xmlInRead--;
+		if (xmlInRead != 0)
+			return;
+
+		// Only do the following after we finished reading everything.
+		Map<String, String> remoteUrls = new HashMap<String, String>();
+		URI baseUri;
+		try {
+			baseUri = new URI(baseUrl);
+		} catch (URISyntaxException e) {
+			throw new SAXException(e);
+		}
+		for (RepoProject proj : projects) {
+			String remote = proj.remote;
+			if (remote == null) {
+				if (defaultRemote == null) {
+					if (filename != null)
+						throw new SAXException(MessageFormat.format(
+								RepoText.get().errorNoDefaultFilename,
+								filename));
+					else
+						throw new SAXException(
+								RepoText.get().errorNoDefault);
+				}
+				remote = defaultRemote;
+			}
+			String remoteUrl = remoteUrls.get(remote);
+			if (remoteUrl == null) {
+				remoteUrl = baseUri.resolve(remotes.get(remote)).toString();
+				if (!remoteUrl.endsWith("/")) //$NON-NLS-1$
+					remoteUrl = remoteUrl + "/"; //$NON-NLS-1$
+				remoteUrls.put(remote, remoteUrl);
+			}
+			proj.setUrl(remoteUrl + proj.name)
+					.setDefaultRevision(defaultRevision);
+		}
+
+		filteredProjects.addAll(projects);
+		removeNotInGroup();
+		removeOverlaps();
+	}
+
+	/**
+	 * Getter for projects.
+	 *
+	 * @return projects list reference, never null
+	 */
+	public List<RepoProject> getProjects() {
+		return projects;
+	}
+
+	/**
+	 * Getter for filterdProjects.
+	 *
+	 * @return filtered projects list reference, never null
+	 */
+	public List<RepoProject> getFilteredProjects() {
+		return filteredProjects;
+	}
+
+	/** Remove projects that are not in our desired groups. */
+	void removeNotInGroup() {
+		Iterator<RepoProject> iter = filteredProjects.iterator();
+		while (iter.hasNext())
+			if (!inGroups(iter.next()))
+				iter.remove();
+	}
+
+	/** Remove projects that sits in a subdirectory of any other project. */
+	void removeOverlaps() {
+		Collections.sort(filteredProjects);
+		Iterator<RepoProject> iter = filteredProjects.iterator();
+		if (!iter.hasNext())
+			return;
+		RepoProject last = iter.next();
+		while (iter.hasNext()) {
+			RepoProject p = iter.next();
+			if (last.isAncestorOf(p))
+				iter.remove();
+			else
+				last = p;
+		}
+	}
+
+	boolean inGroups(RepoProject proj) {
+		for (String group : minusGroups) {
+			if (proj.groups.contains(group)) {
+				// minus groups have highest priority.
+				return false;
+			}
+		}
+		if (plusGroups.isEmpty() || plusGroups.contains("all")) { //$NON-NLS-1$
+			// empty plus groups means "all"
+			return true;
+		}
+		for (String group : plusGroups) {
+			if (proj.groups.contains(group))
+				return true;
+		}
+		return false;
+	}
+}
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 a4b444e..d258250 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoCommand.java
@@ -44,22 +44,12 @@
 
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
-import java.net.URI;
-import java.net.URISyntaxException;
-import java.nio.channels.FileChannel;
 import java.text.MessageFormat;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
-import java.util.Set;
 
 import org.eclipse.jgit.api.Git;
 import org.eclipse.jgit.api.GitCommand;
@@ -70,6 +60,8 @@
 import org.eclipse.jgit.dircache.DirCache;
 import org.eclipse.jgit.dircache.DirCacheBuilder;
 import org.eclipse.jgit.dircache.DirCacheEntry;
+import org.eclipse.jgit.gitrepo.ManifestParser.IncludedFileReader;
+import org.eclipse.jgit.gitrepo.RepoProject.CopyFile;
 import org.eclipse.jgit.gitrepo.internal.RepoText;
 import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.CommitBuilder;
@@ -89,12 +81,6 @@
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.util.FileUtils;
-import org.xml.sax.Attributes;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.XMLReader;
-import org.xml.sax.helpers.DefaultHandler;
-import org.xml.sax.helpers.XMLReaderFactory;
 
 /**
  * A class used to execute a repo command.
@@ -124,7 +110,7 @@
 	private InputStream inputStream;
 	private IncludedFileReader includedReader;
 
-	private List<Project> bareProjects;
+	private List<RepoProject> bareProjects;
 	private Git git;
 	private ProgressMonitor monitor;
 
@@ -214,350 +200,10 @@
 		 */
 		protected byte[] readFileFromRepo(Repository repo,
 				String ref, String path) throws GitAPIException, IOException {
-			ObjectReader reader = repo.newObjectReader();
-			byte[] result;
-			try {
+			try (ObjectReader reader = repo.newObjectReader()) {
 				ObjectId oid = repo.resolve(ref + ":" + path); //$NON-NLS-1$
-				result = reader.open(oid).getBytes(Integer.MAX_VALUE);
-			} finally {
-				reader.release();
+				return reader.open(oid).getBytes(Integer.MAX_VALUE);
 			}
-			return result;
-		}
-	}
-
-	/**
-	 * A callback to read included xml files.
-	 *
-	 * @since 3.5
-	 */
-	public interface IncludedFileReader {
-		/**
-		 * Read a file from the same base dir of the manifest xml file.
-		 *
-		 * @param path
-		 *            The relative path to the file to read
-		 * @return the {@code InputStream} of the file.
-		 * @throws GitAPIException
-		 * @throws IOException
-		 */
-		public InputStream readIncludeFile(String path)
-				throws GitAPIException, IOException;
-	}
-
-	private static class CopyFile {
-		final Repository repo;
-		final String path;
-		final String src;
-		final String dest;
-
-		CopyFile(Repository repo, String path, String src, String dest) {
-			this.repo = repo;
-			this.path = path;
-			this.src = src;
-			this.dest = dest;
-		}
-
-		void copy() throws IOException {
-			File srcFile = new File(repo.getWorkTree(),
-					path + "/" + src); //$NON-NLS-1$
-			File destFile = new File(repo.getWorkTree(), dest);
-			FileInputStream input = new FileInputStream(srcFile);
-			try {
-				FileOutputStream output = new FileOutputStream(destFile);
-				try {
-					FileChannel channel = input.getChannel();
-					output.getChannel().transferFrom(channel, 0, channel.size());
-				} finally {
-					output.close();
-				}
-			} finally {
-				input.close();
-			}
-		}
-	}
-
-	private static class Project implements Comparable<Project> {
-		final String name;
-		final String path;
-		final String revision;
-		final String remote;
-		final Set<String> groups;
-		final List<CopyFile> copyfiles;
-
-		Project(String name, String path, String revision,
-				String remote, String groups) {
-			this.name = name;
-			if (path != null)
-				this.path = path;
-			else
-				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$
-			copyfiles = new ArrayList<CopyFile>();
-		}
-
-		void addCopyFile(CopyFile copyfile) {
-			copyfiles.add(copyfile);
-		}
-
-		String getPathWithSlash() {
-			if (path.endsWith("/")) //$NON-NLS-1$
-				return path;
-			else
-				return path + "/"; //$NON-NLS-1$
-		}
-
-		boolean isAncestorOf(Project that) {
-			return that.getPathWithSlash().startsWith(this.getPathWithSlash());
-		}
-
-		@Override
-		public boolean equals(Object o) {
-			if (o instanceof Project) {
-				Project that = (Project) o;
-				return this.getPathWithSlash().equals(that.getPathWithSlash());
-			}
-			return false;
-		}
-
-		@Override
-		public int hashCode() {
-			return this.getPathWithSlash().hashCode();
-		}
-
-		public int compareTo(Project that) {
-			return this.getPathWithSlash().compareTo(that.getPathWithSlash());
-		}
-	}
-
-	private static class XmlManifest extends DefaultHandler {
-		private final RepoCommand command;
-		private final String filename;
-		private final String baseUrl;
-		private final Map<String, String> remotes;
-		private final Set<String> plusGroups;
-		private final Set<String> minusGroups;
-		private List<Project> projects;
-		private String defaultRemote;
-		private String defaultRevision;
-		private IncludedFileReader includedReader;
-		private int xmlInRead;
-		private Project currentProject;
-
-		XmlManifest(RepoCommand command, IncludedFileReader includedReader,
-				String filename, String baseUrl, String groups) {
-			this.command = command;
-			this.includedReader = includedReader;
-			this.filename = filename;
-
-			// Strip trailing /s to match repo behavior.
-			int lastIndex = baseUrl.length() - 1;
-			while (lastIndex >= 0 && baseUrl.charAt(lastIndex) == '/')
-				lastIndex--;
-			this.baseUrl = baseUrl.substring(0, lastIndex + 1);
-
-			remotes = new HashMap<String, String>();
-			projects = new ArrayList<Project>();
-			plusGroups = new HashSet<String>();
-			minusGroups = new HashSet<String>();
-			if (groups == null || groups.length() == 0 || groups.equals("default")) { //$NON-NLS-1$
-				// default means "all,-notdefault"
-				minusGroups.add("notdefault"); //$NON-NLS-1$
-			} else {
-				for (String group : groups.split(",")) { //$NON-NLS-1$
-					if (group.startsWith("-")) //$NON-NLS-1$
-						minusGroups.add(group.substring(1));
-					else
-						plusGroups.add(group);
-				}
-			}
-		}
-
-		void read(InputStream inputStream) throws IOException {
-			xmlInRead++;
-			final XMLReader xr;
-			try {
-				xr = XMLReaderFactory.createXMLReader();
-			} catch (SAXException e) {
-				throw new IOException(JGitText.get().noXMLParserAvailable);
-			}
-			xr.setContentHandler(this);
-			try {
-				xr.parse(new InputSource(inputStream));
-			} catch (SAXException e) {
-				IOException error = new IOException(
-							RepoText.get().errorParsingManifestFile);
-				error.initCause(e);
-				throw error;
-			}
-		}
-
-		@Override
-		public void startElement(
-				String uri,
-				String localName,
-				String qName,
-				Attributes attributes) throws SAXException {
-			if ("project".equals(qName)) { //$NON-NLS-1$
-				currentProject = new Project(
-						attributes.getValue("name"), //$NON-NLS-1$
-						attributes.getValue("path"), //$NON-NLS-1$
-						attributes.getValue("revision"), //$NON-NLS-1$
-						attributes.getValue("remote"), //$NON-NLS-1$
-						attributes.getValue("groups")); //$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$
-				remotes.put(attributes.getValue("name"), fetch); //$NON-NLS-1$
-				if (alias != null)
-					remotes.put(alias, fetch);
-			} else if ("default".equals(qName)) { //$NON-NLS-1$
-				defaultRemote = attributes.getValue("remote"); //$NON-NLS-1$
-				defaultRevision = attributes.getValue("revision"); //$NON-NLS-1$
-				if (defaultRevision == null)
-					defaultRevision = command.branch;
-			} else if ("copyfile".equals(qName)) { //$NON-NLS-1$
-				if (currentProject == null)
-					throw new SAXException(RepoText.get().invalidManifest);
-				currentProject.addCopyFile(new CopyFile(
-							command.repo,
-							currentProject.path,
-							attributes.getValue("src"), //$NON-NLS-1$
-							attributes.getValue("dest"))); //$NON-NLS-1$
-			} else if ("include".equals(qName)) { //$NON-NLS-1$
-				String name = attributes.getValue("name"); //$NON-NLS-1$
-				InputStream is = null;
-				if (includedReader != null) {
-					try {
-						is = includedReader.readIncludeFile(name);
-					} catch (Exception e) {
-						throw new SAXException(MessageFormat.format(
-								RepoText.get().errorIncludeFile, name), e);
-					}
-				} else if (filename != null) {
-					int index = filename.lastIndexOf('/');
-					String path = filename.substring(0, index + 1) + name;
-					try {
-						is = new FileInputStream(path);
-					} catch (IOException e) {
-						throw new SAXException(MessageFormat.format(
-								RepoText.get().errorIncludeFile, path), e);
-					}
-				}
-				if (is == null) {
-					throw new SAXException(
-							RepoText.get().errorIncludeNotImplemented);
-				}
-				try {
-					read(is);
-				} catch (IOException e) {
-					throw new SAXException(e);
-				}
-			}
-		}
-
-		@Override
-		public void endElement(
-				String uri,
-				String localName,
-				String qName) throws SAXException {
-			if ("project".equals(qName)) { //$NON-NLS-1$
-				projects.add(currentProject);
-				currentProject = null;
-			}
-		}
-
-		@Override
-		public void endDocument() throws SAXException {
-			xmlInRead--;
-			if (xmlInRead != 0)
-				return;
-
-			// Only do the following after we finished reading everything.
-			removeNotInGroup();
-			removeOverlaps();
-
-			Map<String, String> remoteUrls = new HashMap<String, String>();
-			URI baseUri;
-			try {
-				baseUri = new URI(baseUrl);
-			} catch (URISyntaxException e) {
-				throw new SAXException(e);
-			}
-			for (Project proj : projects) {
-				String remote = proj.remote;
-				if (remote == null) {
-					if (defaultRemote == null) {
-						if (filename != null)
-							throw new SAXException(MessageFormat.format(
-									RepoText.get().errorNoDefaultFilename,
-									filename));
-						else
-							throw new SAXException(
-									RepoText.get().errorNoDefault);
-					}
-					remote = defaultRemote;
-				}
-				String remoteUrl = remoteUrls.get(remote);
-				if (remoteUrl == null) {
-					remoteUrl = baseUri.resolve(remotes.get(remote)).toString();
-					if (!remoteUrl.endsWith("/")) //$NON-NLS-1$
-						remoteUrl = remoteUrl + "/"; //$NON-NLS-1$
-					remoteUrls.put(remote, remoteUrl);
-				}
-
-				command.addSubmodule(remoteUrl + proj.name,
-						proj.path,
-						proj.revision == null
-								? defaultRevision : proj.revision,
-						proj.copyfiles);
-			}
-		}
-
-		/** Remove projects that are not in our desired groups. */
-		void removeNotInGroup() {
-			Iterator<Project> iter = projects.iterator();
-			while (iter.hasNext())
-				if (!inGroups(iter.next()))
-					iter.remove();
-		}
-
-		/** Remove projects that sits in a subdirectory of any other project. */
-		void removeOverlaps() {
-			Collections.sort(projects);
-			Iterator<Project> iter = projects.iterator();
-			if (!iter.hasNext())
-				return;
-			Project last = iter.next();
-			while (iter.hasNext()) {
-				Project p = iter.next();
-				if (last.isAncestorOf(p))
-					iter.remove();
-				else
-					last = p;
-			}
-		}
-
-		boolean inGroups(Project proj) {
-			for (String group : minusGroups) {
-				if (proj.groups.contains(group)) {
-					// minus groups have highest priority.
-					return false;
-				}
-			}
-			if (plusGroups.isEmpty() || plusGroups.contains("all")) { //$NON-NLS-1$
-				// empty plus groups means "all"
-				return true;
-			}
-			for (String group : plusGroups) {
-				if (proj.groups.contains(group))
-					return true;
-			}
-			return false;
 		}
 	}
 
@@ -693,7 +339,7 @@
 	 *
 	 * @param reader
 	 * @return this command
-	 * @since 3.5
+	 * @since 4.0
 	 */
 	public RepoCommand setIncludedFileReader(IncludedFileReader reader) {
 		this.includedReader = reader;
@@ -720,7 +366,7 @@
 			}
 
 			if (repo.isBare()) {
-				bareProjects = new ArrayList<Project>();
+				bareProjects = new ArrayList<RepoProject>();
 				if (author == null)
 					author = new PersonIdent(repo);
 				if (callback == null)
@@ -728,11 +374,17 @@
 			} else
 				git = new Git(repo);
 
-			XmlManifest manifest = new XmlManifest(
-					this, includedReader, path, uri, groups);
+			ManifestParser parser = new ManifestParser(
+					includedReader, path, branch, uri, groups, repo);
 			try {
-				manifest.read(inputStream);
-			} catch (IOException e) {
+				parser.read(inputStream);
+				for (RepoProject proj : parser.getFilteredProjects()) {
+					addSubmodule(proj.url,
+							proj.path,
+							proj.getRevision(),
+							proj.copyfiles);
+				}
+			} catch (GitAPIException | IOException e) {
 				throw new ManifestErrorException(e);
 			}
 		} finally {
@@ -748,10 +400,9 @@
 			DirCache index = DirCache.newInCore();
 			DirCacheBuilder builder = index.builder();
 			ObjectInserter inserter = repo.newObjectInserter();
-			RevWalk rw = new RevWalk(repo);
-			try {
+			try (RevWalk rw = new RevWalk(repo)) {
 				Config cfg = new Config();
-				for (Project proj : bareProjects) {
+				for (RepoProject proj : bareProjects) {
 					String name = proj.path;
 					String nameUri = proj.name;
 					cfg.setString("submodule", name, "path", name); //$NON-NLS-1$ //$NON-NLS-2$
@@ -831,8 +482,6 @@
 				return rw.parseCommit(commitId);
 			} catch (IOException e) {
 				throw new ManifestErrorException(e);
-			} finally {
-				rw.release();
 			}
 		} else {
 			return git
@@ -843,9 +492,9 @@
 	}
 
 	private void addSubmodule(String url, String name, String revision,
-			List<CopyFile> copyfiles) throws SAXException {
+			List<CopyFile> copyfiles) throws GitAPIException, IOException {
 		if (repo.isBare()) {
-			Project proj = new Project(url, name, revision, null, null);
+			RepoProject proj = new RepoProject(url, name, revision, null, null);
 			proj.copyfiles.addAll(copyfiles);
 			bareProjects.add(proj);
 		} else {
@@ -856,22 +505,18 @@
 			if (monitor != null)
 				add.setProgressMonitor(monitor);
 
-			try {
-				Repository subRepo = add.call();
-				if (revision != null) {
-					Git sub = new Git(subRepo);
-					sub.checkout().setName(findRef(revision, subRepo)).call();
-					subRepo.close();
-					git.add().addFilepattern(name).call();
+			Repository subRepo = add.call();
+			if (revision != null) {
+				try (Git sub = new Git(subRepo)) {
+					sub.checkout().setName(findRef(revision, subRepo))
+							.call();
 				}
-				for (CopyFile copyfile : copyfiles) {
-					copyfile.copy();
-					git.add().addFilepattern(copyfile.dest).call();
-				}
-			} catch (GitAPIException e) {
-				throw new SAXException(e);
-			} catch (IOException e) {
-				throw new SAXException(e);
+				subRepo.close();
+				git.add().addFilepattern(name).call();
+			}
+			for (CopyFile copyfile : copyfiles) {
+				copyfile.copy();
+				git.add().addFilepattern(copyfile.dest).call();
 			}
 		}
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
new file mode 100644
index 0000000..dfd4f1b
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/gitrepo/RepoProject.java
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2015, Google Inc.
+ * 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.gitrepo;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.jgit.lib.Repository;
+
+/**
+ * The representation of a repo sub project.
+ *
+ * @see <a href="https://code.google.com/p/git-repo/">git-repo project page</a>
+ * @since 4.0
+ */
+public class RepoProject implements Comparable<RepoProject> {
+	final String name;
+	final String path;
+	final String revision;
+	final String remote;
+	final Set<String> groups;
+	final List<CopyFile> copyfiles;
+	String url;
+	String defaultRevision;
+
+	/**
+	 * The representation of a copy file configuration.
+	 */
+	public static class CopyFile {
+		final Repository repo;
+		final String path;
+		final String src;
+		final String dest;
+
+		/**
+		 * @param repo
+		 * @param path
+		 *            the path of the project containing this copyfile config.
+		 * @param src
+		 * @param dest
+		 */
+		public CopyFile(Repository repo, String path, String src, String dest) {
+			this.repo = repo;
+			this.path = path;
+			this.src = src;
+			this.dest = dest;
+		}
+
+		/**
+		 * Do the copy file action.
+		 *
+		 * @throws IOException
+		 */
+		public void copy() throws IOException {
+			File srcFile = new File(repo.getWorkTree(),
+					path + "/" + src); //$NON-NLS-1$
+			File destFile = new File(repo.getWorkTree(), dest);
+			FileInputStream input = new FileInputStream(srcFile);
+			try {
+				FileOutputStream output = new FileOutputStream(destFile);
+				try {
+					FileChannel channel = input.getChannel();
+					output.getChannel().transferFrom(channel, 0, channel.size());
+				} finally {
+					output.close();
+				}
+			} finally {
+				input.close();
+			}
+		}
+	}
+
+	/**
+	 * @param name
+	 * @param path
+	 * @param revision
+	 * @param remote
+	 * @param groups
+	 */
+	public RepoProject(String name, String path, String revision,
+			String remote, String groups) {
+		this.name = name;
+		if (path != null)
+			this.path = path;
+		else
+			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$
+		copyfiles = new ArrayList<CopyFile>();
+	}
+
+	/**
+	 * Set the url of the sub repo.
+	 *
+	 * @param url
+	 * @return this for chaining.
+	 */
+	public RepoProject setUrl(String url) {
+		this.url = url;
+		return this;
+	}
+
+	/**
+	 * Set the default revision for the sub repo.
+	 *
+	 * @param defaultRevision
+	 * @return this for chaining.
+	 */
+	public RepoProject setDefaultRevision(String defaultRevision) {
+		this.defaultRevision = defaultRevision;
+		return this;
+	}
+
+	/**
+	 * Get the revision of the sub repo.
+	 *
+	 * @return revision if set, or default revision.
+	 */
+	public String getRevision() {
+		return revision == null ? defaultRevision : revision;
+	}
+
+	/**
+	 * Add a copy file configuration.
+	 *
+	 * @param copyfile
+	 */
+	public void addCopyFile(CopyFile copyfile) {
+		copyfiles.add(copyfile);
+	}
+
+	String getPathWithSlash() {
+		if (path.endsWith("/")) //$NON-NLS-1$
+			return path;
+		else
+			return path + "/"; //$NON-NLS-1$
+	}
+
+	/**
+	 * Check if this sub repo is the ancestor of given sub repo.
+	 *
+	 * @param that
+	 *            non null
+	 * @return true if this sub repo is the ancestor of given sub repo.
+	 */
+	public boolean isAncestorOf(RepoProject that) {
+		return that.getPathWithSlash().startsWith(this.getPathWithSlash());
+	}
+
+	@Override
+	public boolean equals(Object o) {
+		if (o instanceof RepoProject) {
+			RepoProject that = (RepoProject) o;
+			return this.getPathWithSlash().equals(that.getPathWithSlash());
+		}
+		return false;
+	}
+
+	@Override
+	public int hashCode() {
+		return this.getPathWithSlash().hashCode();
+	}
+
+	@Override
+	public int compareTo(RepoProject that) {
+		return this.getPathWithSlash().compareTo(that.getPathWithSlash());
+	}
+}
+
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 3077e18..b53c7c9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/JGitText.java
@@ -86,6 +86,7 @@
 	/***/ public String badEscape;
 	/***/ public String badGroupHeader;
 	/***/ public String badObjectType;
+	/***/ public String badRef;
 	/***/ public String badSectionEntry;
 	/***/ public String bareRepositoryNoWorkdirAndIndex;
 	/***/ public String base64InputNotProperlyPadded;
@@ -117,16 +118,23 @@
 	/***/ public String cannotCreateTempDir;
 	/***/ public String cannotDeleteCheckedOutBranch;
 	/***/ public String cannotDeleteFile;
+	/***/ public String cannotDeleteObjectsPath;
 	/***/ public String cannotDeleteStaleTrackingRef;
 	/***/ public String cannotDeleteStaleTrackingRef2;
 	/***/ public String cannotDetermineProxyFor;
 	/***/ public String cannotDownload;
+	/***/ public String cannotEnterObjectsPath;
+	/***/ public String cannotEnterPathFromParent;
 	/***/ public String cannotExecute;
 	/***/ public String cannotGet;
+	/***/ public String cannotGetObjectsPath;
+	/***/ public String cannotListObjectsPath;
+	/***/ public String cannotListPackPath;
 	/***/ public String cannotListRefs;
 	/***/ public String cannotLock;
 	/***/ public String cannotLockPackIn;
 	/***/ public String cannotMatchOnEmptyString;
+	/***/ public String cannotMkdirObjectPath;
 	/***/ public String cannotMoveIndexTo;
 	/***/ public String cannotMovePackTo;
 	/***/ public String cannotOpenService;
@@ -139,13 +147,16 @@
 	/***/ public String cannotReadFile;
 	/***/ public String cannotReadHEAD;
 	/***/ public String cannotReadObject;
+	/***/ public String cannotReadObjectsPath;
 	/***/ public String cannotReadTree;
 	/***/ public String cannotRebaseWithoutCurrentHead;
 	/***/ public String cannotResolveLocalTrackingRefForUpdating;
 	/***/ public String cannotSquashFixupWithoutPreviousCommit;
 	/***/ public String cannotStoreObjects;
+	/***/ public String cannotResolveUniquelyAbbrevObjectId;
 	/***/ public String cannotUnloadAModifiedTree;
 	/***/ public String cannotWorkWithOtherStagesThanZeroRightNow;
+	/***/ public String cannotWriteObjectsPath;
 	/***/ public String canOnlyCherryPickCommitsWithOneParent;
 	/***/ public String canOnlyRevertCommitsWithOneParent;
 	/***/ public String commitDoesNotHaveGivenParent;
@@ -172,26 +183,60 @@
 	/***/ public String corruptionDetectedReReadingAt;
 	/***/ public String corruptObjectBadStream;
 	/***/ public String corruptObjectBadStreamCorruptHeader;
+	/***/ public String corruptObjectDuplicateEntryNames;
 	/***/ public String corruptObjectGarbageAfterSize;
 	/***/ public String corruptObjectIncorrectLength;
+	/***/ public String corruptObjectIncorrectSorting;
+	/***/ public String corruptObjectInvalidAuthor;
+	/***/ public String corruptObjectInvalidCommitter;
 	/***/ public String corruptObjectInvalidEntryMode;
 	/***/ public String corruptObjectInvalidMode;
+	/***/ public String corruptObjectInvalidModeChar;
+	/***/ public String corruptObjectInvalidModeStartsZero;
 	/***/ public String corruptObjectInvalidMode2;
 	/***/ public String corruptObjectInvalidMode3;
+	/***/ public String corruptObjectInvalidName;
+	/***/ public String corruptObjectInvalidNameAux;
+	/***/ public String corruptObjectInvalidNameCon;
+	/***/ public String corruptObjectInvalidNameCom;
+	/***/ public String corruptObjectInvalidNameEnd;
+	/***/ public String corruptObjectInvalidNameIgnorableUnicode;
+	/***/ public String corruptObjectInvalidNameInvalidUtf8;
+	/***/ public String corruptObjectInvalidNameLpt;
+	/***/ public String corruptObjectInvalidNameNul;
+	/***/ public String corruptObjectInvalidNamePrn;
+	/***/ public String corruptObjectInvalidObject;
+	/***/ public String corruptObjectInvalidParent;
+	/***/ public String corruptObjectInvalidTagger;
+	/***/ public String corruptObjectInvalidTree;
 	/***/ public String corruptObjectInvalidType;
 	/***/ public String corruptObjectInvalidType2;
 	/***/ public String corruptObjectMalformedHeader;
+	/***/ public String corruptObjectNameContainsByte;
+	/***/ public String corruptObjectNameContainsChar;
+	/***/ public String corruptObjectNameContainsNullByte;
+	/***/ public String corruptObjectNameContainsSlash;
+	/***/ public String corruptObjectNameDot;
+	/***/ public String corruptObjectNameDotDot;
+	/***/ public String corruptObjectNameZeroLength;
 	/***/ public String corruptObjectNegativeSize;
 	/***/ public String corruptObjectNoAuthor;
 	/***/ public String corruptObjectNoCommitter;
 	/***/ public String corruptObjectNoHeader;
 	/***/ public String corruptObjectNoObject;
+	/***/ public String corruptObjectNoObjectHeader;
 	/***/ public String corruptObjectNoTaggerBadHeader;
 	/***/ public String corruptObjectNoTaggerHeader;
+	/***/ public String corruptObjectNoTagHeader;
 	/***/ public String corruptObjectNoTagName;
 	/***/ public String corruptObjectNotree;
+	/***/ public String corruptObjectNotreeHeader;
 	/***/ public String corruptObjectNoType;
+	/***/ public String corruptObjectNoTypeHeader;
 	/***/ public String corruptObjectPackfileChecksumIncorrect;
+	/***/ public String corruptObjectTruncatedInMode;
+	/***/ public String corruptObjectTruncatedInName;
+	/***/ public String corruptObjectTruncatedInObjectId;
 	/***/ public String corruptPack;
 	/***/ public String couldNotCheckOutBecauseOfConflicts;
 	/***/ public String couldNotDeleteLockFileShouldNotHappen;
@@ -204,6 +249,7 @@
 	/***/ public String couldNotRenameDeleteOldIndex;
 	/***/ public String couldNotRenameTemporaryFile;
 	/***/ public String couldNotRenameTemporaryIndexFileToIndex;
+	/***/ public String couldNotRewindToUpstreamCommit;
 	/***/ public String couldNotURLEncodeToUTF8;
 	/***/ public String couldNotWriteFile;
 	/***/ public String countingObjects;
@@ -239,6 +285,7 @@
 	/***/ public String eitherGitDirOrWorkTreeRequired;
 	/***/ public String emptyCommit;
 	/***/ public String emptyPathNotPermitted;
+	/***/ public String emptyRef;
 	/***/ public String encryptionError;
 	/***/ public String endOfFileInEscape;
 	/***/ public String entryNotFoundByPath;
@@ -299,6 +346,7 @@
 	/***/ public String gcFailed;
 	/***/ public String gitmodulesNotFound;
 	/***/ public String headRequiredToStash;
+	/***/ public String hiddenFilesStartWithDot;
 	/***/ public String hoursAgo;
 	/***/ public String hugeIndexesAreNotSupportedByJgitYet;
 	/***/ public String hunkBelongsToAnotherFile;
@@ -337,6 +385,7 @@
 	/***/ public String invalidGitType;
 	/***/ public String invalidId;
 	/***/ public String invalidIdLength;
+	/***/ public String invalidIgnoreParamSubmodule;
 	/***/ public String invalidIntegerValue;
 	/***/ public String invalidKey;
 	/***/ public String invalidLineInConfigFile;
@@ -369,8 +418,10 @@
 	/***/ public String largeObjectOutOfMemory;
 	/***/ public String lengthExceedsMaximumArraySize;
 	/***/ public String listingAlternates;
+	/***/ public String listingPacks;
 	/***/ public String localObjectsIncomplete;
 	/***/ public String localRefIsMissingObjects;
+	/***/ public String localRepository;
 	/***/ public String lockCountMustBeGreaterOrEqual1;
 	/***/ public String lockError;
 	/***/ public String lockOnNotClosed;
@@ -469,6 +520,8 @@
 	/***/ public String pathNotConfigured;
 	/***/ public String peeledLineBeforeRef;
 	/***/ public String peerDidNotSupplyACompleteObjectGraph;
+	/***/ public String personIdentEmailNonNull;
+	/***/ public String personIdentNameNonNull;
 	/***/ public String prefixRemote;
 	/***/ public String problemWithResolvingPushRefSpecsLocally;
 	/***/ public String progressMonUploading;
@@ -512,6 +565,7 @@
 	/***/ public String repositoryIsRequired;
 	/***/ public String repositoryNotFound;
 	/***/ public String repositoryState_applyMailbox;
+	/***/ public String repositoryState_bare;
 	/***/ public String repositoryState_bisecting;
 	/***/ public String repositoryState_conflicts;
 	/***/ public String repositoryState_merged;
@@ -525,6 +579,9 @@
 	/***/ public String resolvingDeltas;
 	/***/ public String resultLengthIncorrect;
 	/***/ public String rewinding;
+	/***/ public String s3ActionDeletion;
+	/***/ public String s3ActionReading;
+	/***/ public String s3ActionWriting;
 	/***/ public String searchForReuse;
 	/***/ public String searchForSizes;
 	/***/ public String secondsAgo;
@@ -606,6 +663,7 @@
 	/***/ public String unencodeableFile;
 	/***/ public String unexpectedCompareResult;
 	/***/ public String unexpectedEndOfConfigFile;
+	/***/ public String unexpectedEndOfInput;
 	/***/ public String unexpectedHunkTrailer;
 	/***/ public String unexpectedOddResult;
 	/***/ public String unexpectedRefReport;
@@ -617,6 +675,7 @@
 	/***/ public String unknownIndexVersionOrCorruptIndex;
 	/***/ public String unknownObject;
 	/***/ public String unknownObjectType;
+	/***/ public String unknownObjectType2;
 	/***/ public String unknownRepositoryFormat;
 	/***/ public String unknownRepositoryFormat2;
 	/***/ public String unknownZlibError;
@@ -625,16 +684,21 @@
 	/***/ public String unpackException;
 	/***/ public String unreadablePackIndex;
 	/***/ public String unrecognizedRef;
+	/***/ public String unsetMark;
+	/***/ public String unsupportedAlternates;
 	/***/ public String unsupportedArchiveFormat;
 	/***/ public String unsupportedCommand0;
 	/***/ public String unsupportedEncryptionAlgorithm;
 	/***/ public String unsupportedEncryptionVersion;
 	/***/ public String unsupportedGC;
+	/***/ public String unsupportedMark;
 	/***/ public String unsupportedOperationNotAddAtEnd;
 	/***/ public String unsupportedPackIndexVersion;
 	/***/ public String unsupportedPackVersion;
+	/***/ public String updatingHeadFailed;
 	/***/ public String updatingReferences;
 	/***/ public String updatingRefFailed;
+	/***/ public String upstreamBranchName;
 	/***/ public String uriNotConfigured;
 	/***/ public String uriNotFound;
 	/***/ public String URINotSupported;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java
index fed5338..de66292 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsGarbageCollector.java
@@ -230,7 +230,7 @@
 					objdb.rollbackPack(newPackDesc);
 			}
 		} finally {
-			ctx.release();
+			ctx.close();
 		}
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java
index 5cab473..488eee9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsInserter.java
@@ -216,7 +216,7 @@
 	}
 
 	@Override
-	public void release() {
+	public void close() {
 		if (packOut != null) {
 			try {
 				packOut.close();
@@ -600,8 +600,8 @@
 		}
 
 		@Override
-		public void release() {
-			ctx.release();
+		public void close() {
+			ctx.close();
 		}
 	}
 
@@ -631,7 +631,7 @@
 					// The newly created pack is registered in the cache.
 					return ctx.open(id, type).openStream();
 				} finally {
-					ctx.release();
+					ctx.close();
 				}
 			}
 
@@ -642,7 +642,7 @@
 							new ReadBackStream(pos), inf, bufsz), bufsz)) {
 				@Override
 				public void close() throws IOException {
-					ctx.release();
+					ctx.close();
 					super.close();
 				}
 			};
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
index 8372884..dbe72b2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsPackCompactor.java
@@ -179,11 +179,8 @@
 	 */
 	public DfsPackCompactor exclude(DfsPackFile pack) throws IOException {
 		final PackIndex idx;
-		DfsReader ctx = (DfsReader) repo.newObjectReader();
-		try {
+		try (DfsReader ctx = (DfsReader) repo.newObjectReader()) {
 			idx = pack.getPackIndex(ctx);
-		} finally {
-			ctx.release();
 		}
 		return exclude(new PackWriter.ObjectIdSet() {
 			public boolean contains(AnyObjectId id) {
@@ -206,8 +203,7 @@
 			pm = NullProgressMonitor.INSTANCE;
 
 		DfsObjDatabase objdb = repo.getObjectDatabase();
-		DfsReader ctx = (DfsReader) objdb.newReader();
-		try {
+		try (DfsReader ctx = (DfsReader) objdb.newReader()) {
 			PackConfig pc = new PackConfig(repo);
 			pc.setIndexVersion(2);
 			pc.setDeltaCompress(false);
@@ -236,7 +232,7 @@
 					writeIndex(objdb, pack, pw);
 
 					PackWriter.Statistics stats = pw.getStatistics();
-					pw.release();
+					pw.close();
 					pw = null;
 
 					pack.setPackStats(stats);
@@ -250,11 +246,10 @@
 				}
 			} finally {
 				if (pw != null)
-					pw.release();
+					pw.close();
 			}
 		} finally {
 			rw = null;
-			ctx.release();
 		}
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java
index f5f3375..1665c2c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsReader.java
@@ -61,6 +61,7 @@
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException;
+import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.internal.storage.file.BitmapIndexImpl;
 import org.eclipse.jgit.internal.storage.file.PackBitmapIndex;
 import org.eclipse.jgit.internal.storage.file.PackIndex;
@@ -210,7 +211,8 @@
 		}
 
 		if (typeHint == OBJ_ANY)
-			throw new MissingObjectException(objectId.copy(), "unknown");
+			throw new MissingObjectException(objectId.copy(),
+					JGitText.get().unknownObjectType2);
 		throw new MissingObjectException(objectId.copy(), typeHint);
 	}
 
@@ -339,7 +341,8 @@
 
 			public ObjectLoader open() throws IOException {
 				if (cur.pack == null)
-					throw new MissingObjectException(cur.id, "unknown");
+					throw new MissingObjectException(cur.id,
+							JGitText.get().unknownObjectType2);
 				return cur.pack.load(DfsReader.this, cur.offset);
 			}
 
@@ -376,7 +379,8 @@
 				if (idItr.hasNext()) {
 					cur = idItr.next();
 					if (cur.pack == null)
-						throw new MissingObjectException(cur.id, "unknown");
+						throw new MissingObjectException(cur.id,
+								JGitText.get().unknownObjectType2);
 					sz = cur.pack.getObjectSize(DfsReader.this, cur.offset);
 					return true;
 				} else if (findAllError != null) {
@@ -429,7 +433,8 @@
 		}
 
 		if (typeHint == OBJ_ANY)
-			throw new MissingObjectException(objectId.copy(), "unknown");
+			throw new MissingObjectException(objectId.copy(),
+					JGitText.get().unknownObjectType2);
 		throw new MissingObjectException(objectId.copy(), typeHint);
 	}
 
@@ -618,7 +623,7 @@
 
 	/** Release the current window cursor. */
 	@Override
-	public void release() {
+	public void close() {
 		last = null;
 		block = null;
 		baseCache = null;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java
index 593aaac..ed8acd5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRefDatabase.java
@@ -183,8 +183,7 @@
 
 	private Ref doPeel(final Ref leaf) throws MissingObjectException,
 			IOException {
-		RevWalk rw = new RevWalk(repository);
-		try {
+		try (RevWalk rw = new RevWalk(repository)) {
 			RevObject obj = rw.parseAny(leaf.getObjectId());
 			if (obj instanceof RevTag) {
 				return new ObjectIdRef.PeeledTag(
@@ -198,8 +197,6 @@
 						leaf.getName(),
 						leaf.getObjectId());
 			}
-		} finally {
-			rw.release();
 		}
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepositoryBuilder.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepositoryBuilder.java
index e0c0d0a..77e060a 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepositoryBuilder.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/DfsRepositoryBuilder.java
@@ -46,6 +46,7 @@
 import java.io.File;
 import java.io.IOException;
 
+import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.lib.BaseRepositoryBuilder;
 
 /**
@@ -141,7 +142,8 @@
 
 	@Override
 	public B addAlternateObjectDirectory(File other) {
-		throw new UnsupportedOperationException("Alternates not supported");
+		throw new UnsupportedOperationException(
+				JGitText.get().unsupportedAlternates);
 	}
 
 	@Override
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/LargePackedWholeObject.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/LargePackedWholeObject.java
index 4b050c5..6d40a75 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/LargePackedWholeObject.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/LargePackedWholeObject.java
@@ -112,8 +112,10 @@
 				ObjectId obj = pack.getReverseIdx(ctx).findObject(objectOffset);
 				return ctx.open(obj, type).openStream();
 			} finally {
-				ctx.release();
+				ctx.close();
 			}
+		} finally {
+			ctx.close();
 		}
 
 		// Align buffer to inflater size, at a larger than default block.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/PackInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/PackInputStream.java
index 805d243..bb8445b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/PackInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/dfs/PackInputStream.java
@@ -80,6 +80,6 @@
 
 	@Override
 	public void close() {
-		ctx.release();
+		ctx.close();
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java
index eb87460..fb41172 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/ObjectDirectoryInserter.java
@@ -145,7 +145,7 @@
 	}
 
 	@Override
-	public void release() {
+	public void close() {
 		if (deflate != null) {
 			try {
 				deflate.end();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
index 75c361e..b29966e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/PackFile.java
@@ -51,6 +51,7 @@
 import java.io.EOFException;
 import java.io.File;
 import java.io.IOException;
+import java.io.InterruptedIOException;
 import java.io.RandomAccessFile;
 import java.nio.MappedByteBuffer;
 import java.nio.channels.FileChannel.MapMode;
@@ -177,6 +178,9 @@
 							packFile.getPath()));
 				}
 				loadedIdx = idx;
+			} catch (InterruptedIOException e) {
+				// don't invalidate the pack, we are interrupted from another thread
+				throw e;
 			} catch (IOException e) {
 				invalid = true;
 				throw e;
@@ -605,22 +609,26 @@
 				length = fd.length();
 				onOpenPack();
 			}
+		} catch (InterruptedIOException e) {
+			// don't invalidate the pack, we are interrupted from another thread
+			openFail(false);
+			throw e;
 		} catch (IOException ioe) {
-			openFail();
+			openFail(true);
 			throw ioe;
 		} catch (RuntimeException re) {
-			openFail();
+			openFail(true);
 			throw re;
 		} catch (Error re) {
-			openFail();
+			openFail(true);
 			throw re;
 		}
 	}
 
-	private void openFail() {
+	private void openFail(boolean invalidate) {
 		activeWindows = 0;
 		activeCopyRawData = 0;
-		invalid = true;
+		invalid = invalidate;
 		doClose();
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
index 0abf0c8..6d6d0ca 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectory.java
@@ -477,8 +477,7 @@
 
 	private ObjectIdRef doPeel(final Ref leaf) throws MissingObjectException,
 			IOException {
-		RevWalk rw = new RevWalk(getRepository());
-		try {
+		try (RevWalk rw = new RevWalk(getRepository())) {
 			RevObject obj = rw.parseAny(leaf.getObjectId());
 			if (obj instanceof RevTag) {
 				return new ObjectIdRef.PeeledTag(leaf.getStorage(), leaf
@@ -487,8 +486,6 @@
 				return new ObjectIdRef.PeeledNonTag(leaf.getStorage(), leaf
 						.getName(), leaf.getObjectId());
 			}
-		} finally {
-			rw.release();
 		}
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryRename.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryRename.java
index 878fc19..ba4a63d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryRename.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryRename.java
@@ -96,8 +96,7 @@
 		objId = source.getOldObjectId();
 		updateHEAD = needToUpdateHEAD();
 		tmp = refdb.newTemporaryUpdate();
-		final RevWalk rw = new RevWalk(refdb.getRepository());
-		try {
+		try (final RevWalk rw = new RevWalk(refdb.getRepository())) {
 			// First backup the source so its never unreachable.
 			tmp.setNewObjectId(objId);
 			tmp.setForceUpdate(true);
@@ -178,7 +177,6 @@
 			} catch (IOException err) {
 				FileUtils.delete(refdb.fileFor(tmp.getName()));
 			}
-			rw.release();
 		}
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java
index 8ad7ad2..7858ee1 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/RefDirectoryUpdate.java
@@ -128,11 +128,11 @@
 	private String toResultString(final Result status) {
 		switch (status) {
 		case FORCED:
-			return "forced-update";
+			return "forced-update"; //$NON-NLS-1$
 		case FAST_FORWARD:
-			return "fast forward";
+			return "fast forward"; //$NON-NLS-1$
 		case NEW:
-			return "created";
+			return "created"; //$NON-NLS-1$
 		default:
 			return null;
 		}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
index 21d6cd2..3e6cb58 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/file/WindowCursor.java
@@ -56,6 +56,7 @@
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.errors.StoredObjectRepresentationNotAvailableException;
+import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.internal.storage.pack.CachedPack;
 import org.eclipse.jgit.internal.storage.pack.ObjectReuseAsIs;
 import org.eclipse.jgit.internal.storage.pack.ObjectToPack;
@@ -141,7 +142,8 @@
 		final ObjectLoader ldr = db.openObject(this, objectId);
 		if (ldr == null) {
 			if (typeHint == OBJ_ANY)
-				throw new MissingObjectException(objectId.copy(), "unknown");
+				throw new MissingObjectException(objectId.copy(),
+						JGitText.get().unknownObjectType2);
 			throw new MissingObjectException(objectId.copy(), typeHint);
 		}
 		if (typeHint != OBJ_ANY && ldr.getType() != typeHint)
@@ -160,7 +162,8 @@
 		long sz = db.getObjectSize(this, objectId);
 		if (sz < 0) {
 			if (typeHint == OBJ_ANY)
-				throw new MissingObjectException(objectId.copy(), "unknown");
+				throw new MissingObjectException(objectId.copy(),
+						JGitText.get().unknownObjectType2);
 			throw new MissingObjectException(objectId.copy(), typeHint);
 		}
 		return sz;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaTask.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaTask.java
index 9534053..8ea0c23 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaTask.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/DeltaTask.java
@@ -288,7 +288,7 @@
 				runWindow(w);
 		} finally {
 			block.pm.endWorker();
-			or.release();
+			or.close();
 			or = null;
 		}
 		return null;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
index b30315a..8fac907 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/internal/storage/pack/PackWriter.java
@@ -987,7 +987,7 @@
 		}
 
 		stats.totalBytes = out.length();
-		reader.release();
+		reader.close();
 		endPhase(writeMonitor);
 	}
 
@@ -1006,14 +1006,6 @@
 	}
 
 	/**
-	 * Release all resources used by this writer. Use {@link #close()} instead.
-	 */
-	@Deprecated
-	public void release() {
-		close();
-	}
-
-	/**
 	 * Release all resources used by this writer.
 	 *
 	 * @since 4.0
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
index 1b049f6..3fde2f9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/IndexDiff.java
@@ -48,6 +48,7 @@
 package org.eclipse.jgit.lib;
 
 import java.io.IOException;
+import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -63,6 +64,7 @@
 import org.eclipse.jgit.errors.IncorrectObjectTypeException;
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.errors.StopWalkException;
+import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.revwalk.RevTree;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.submodule.SubmoduleWalk;
@@ -400,118 +402,122 @@
 			throws IOException {
 		dirCache = repository.readDirCache();
 
-		TreeWalk treeWalk = new TreeWalk(repository);
-		treeWalk.setRecursive(true);
-		// add the trees (tree, dirchache, workdir)
-		if (tree != null)
-			treeWalk.addTree(tree);
-		else
-			treeWalk.addTree(new EmptyTreeIterator());
-		treeWalk.addTree(new DirCacheIterator(dirCache));
-		treeWalk.addTree(initialWorkingTreeIterator);
-		Collection<TreeFilter> filters = new ArrayList<TreeFilter>(4);
+		try (TreeWalk treeWalk = new TreeWalk(repository)) {
+			treeWalk.setRecursive(true);
+			// add the trees (tree, dirchache, workdir)
+			if (tree != null)
+				treeWalk.addTree(tree);
+			else
+				treeWalk.addTree(new EmptyTreeIterator());
+			treeWalk.addTree(new DirCacheIterator(dirCache));
+			treeWalk.addTree(initialWorkingTreeIterator);
+			Collection<TreeFilter> filters = new ArrayList<TreeFilter>(4);
 
-		if (monitor != null) {
-			// Get the maximum size of the work tree and index
-			// and add some (quite arbitrary)
-			if (estIndexSize == 0)
-				estIndexSize = dirCache.getEntryCount();
-			int total = Math.max(estIndexSize * 10 / 9,
-					estWorkTreeSize * 10 / 9);
-			monitor.beginTask(title, total);
-			filters.add(new ProgressReportingFilter(monitor, total));
-		}
-
-		if (filter != null)
-			filters.add(filter);
-		filters.add(new SkipWorkTreeFilter(INDEX));
-		indexDiffFilter = new IndexDiffFilter(INDEX, WORKDIR);
-		filters.add(indexDiffFilter);
-		treeWalk.setFilter(AndTreeFilter.create(filters));
-		fileModes.clear();
-		while (treeWalk.next()) {
-			AbstractTreeIterator treeIterator = treeWalk.getTree(TREE,
-					AbstractTreeIterator.class);
-			DirCacheIterator dirCacheIterator = treeWalk.getTree(INDEX,
-					DirCacheIterator.class);
-			WorkingTreeIterator workingTreeIterator = treeWalk.getTree(WORKDIR,
-					WorkingTreeIterator.class);
-
-			if (dirCacheIterator != null) {
-				final DirCacheEntry dirCacheEntry = dirCacheIterator
-						.getDirCacheEntry();
-				if (dirCacheEntry != null) {
-					int stage = dirCacheEntry.getStage();
-					if (stage > 0) {
-						String path = treeWalk.getPathString();
-						addConflict(path, stage);
-						continue;
-					}
-				}
+			if (monitor != null) {
+				// Get the maximum size of the work tree and index
+				// and add some (quite arbitrary)
+				if (estIndexSize == 0)
+					estIndexSize = dirCache.getEntryCount();
+				int total = Math.max(estIndexSize * 10 / 9,
+						estWorkTreeSize * 10 / 9);
+				monitor.beginTask(title, total);
+				filters.add(new ProgressReportingFilter(monitor, total));
 			}
 
-			if (treeIterator != null) {
+			if (filter != null)
+				filters.add(filter);
+			filters.add(new SkipWorkTreeFilter(INDEX));
+			indexDiffFilter = new IndexDiffFilter(INDEX, WORKDIR);
+			filters.add(indexDiffFilter);
+			treeWalk.setFilter(AndTreeFilter.create(filters));
+			fileModes.clear();
+			while (treeWalk.next()) {
+				AbstractTreeIterator treeIterator = treeWalk.getTree(TREE,
+						AbstractTreeIterator.class);
+				DirCacheIterator dirCacheIterator = treeWalk.getTree(INDEX,
+						DirCacheIterator.class);
+				WorkingTreeIterator workingTreeIterator = treeWalk
+						.getTree(WORKDIR, WorkingTreeIterator.class);
+
 				if (dirCacheIterator != null) {
-					if (!treeIterator.idEqual(dirCacheIterator)
-							|| treeIterator.getEntryRawMode()
-							!= dirCacheIterator.getEntryRawMode()) {
-						// in repo, in index, content diff => changed
+					final DirCacheEntry dirCacheEntry = dirCacheIterator
+							.getDirCacheEntry();
+					if (dirCacheEntry != null) {
+						int stage = dirCacheEntry.getStage();
+						if (stage > 0) {
+							String path = treeWalk.getPathString();
+							addConflict(path, stage);
+							continue;
+						}
+					}
+				}
+
+				if (treeIterator != null) {
+					if (dirCacheIterator != null) {
+						if (!treeIterator.idEqual(dirCacheIterator)
+								|| treeIterator
+										.getEntryRawMode() != dirCacheIterator
+												.getEntryRawMode()) {
+							// in repo, in index, content diff => changed
+							if (!isEntryGitLink(treeIterator)
+									|| !isEntryGitLink(dirCacheIterator)
+									|| ignoreSubmoduleMode != IgnoreSubmoduleMode.ALL)
+								changed.add(treeWalk.getPathString());
+						}
+					} else {
+						// in repo, not in index => removed
 						if (!isEntryGitLink(treeIterator)
-								|| !isEntryGitLink(dirCacheIterator)
 								|| ignoreSubmoduleMode != IgnoreSubmoduleMode.ALL)
-							changed.add(treeWalk.getPathString());
+							removed.add(treeWalk.getPathString());
+						if (workingTreeIterator != null)
+							untracked.add(treeWalk.getPathString());
 					}
 				} else {
-					// in repo, not in index => removed
-					if (!isEntryGitLink(treeIterator)
-							|| ignoreSubmoduleMode != IgnoreSubmoduleMode.ALL)
-						removed.add(treeWalk.getPathString());
-					if (workingTreeIterator != null)
-						untracked.add(treeWalk.getPathString());
+					if (dirCacheIterator != null) {
+						// not in repo, in index => added
+						if (!isEntryGitLink(dirCacheIterator)
+								|| ignoreSubmoduleMode != IgnoreSubmoduleMode.ALL)
+							added.add(treeWalk.getPathString());
+					} else {
+						// not in repo, not in index => untracked
+						if (workingTreeIterator != null
+								&& !workingTreeIterator.isEntryIgnored()) {
+							untracked.add(treeWalk.getPathString());
+						}
+					}
 				}
-			} else {
+
 				if (dirCacheIterator != null) {
-					// not in repo, in index => added
-					if (!isEntryGitLink(dirCacheIterator)
-							|| ignoreSubmoduleMode != IgnoreSubmoduleMode.ALL)
-						added.add(treeWalk.getPathString());
-				} else {
-					// not in repo, not in index => untracked
-					if (workingTreeIterator != null
-							&& !workingTreeIterator.isEntryIgnored()) {
-						untracked.add(treeWalk.getPathString());
+					if (workingTreeIterator == null) {
+						// in index, not in workdir => missing
+						if (!isEntryGitLink(dirCacheIterator)
+								|| ignoreSubmoduleMode != IgnoreSubmoduleMode.ALL)
+							missing.add(treeWalk.getPathString());
+					} else {
+						if (workingTreeIterator.isModified(
+								dirCacheIterator.getDirCacheEntry(), true,
+								treeWalk.getObjectReader())) {
+							// in index, in workdir, content differs => modified
+							if (!isEntryGitLink(dirCacheIterator)
+									|| !isEntryGitLink(workingTreeIterator)
+									|| (ignoreSubmoduleMode != IgnoreSubmoduleMode.ALL
+											&& ignoreSubmoduleMode != IgnoreSubmoduleMode.DIRTY))
+								modified.add(treeWalk.getPathString());
+						}
 					}
 				}
-			}
 
-			if (dirCacheIterator != null) {
-				if (workingTreeIterator == null) {
-					// in index, not in workdir => missing
-					if (!isEntryGitLink(dirCacheIterator)
-							|| ignoreSubmoduleMode != IgnoreSubmoduleMode.ALL)
-						missing.add(treeWalk.getPathString());
-				} else {
-					if (workingTreeIterator.isModified(
-							dirCacheIterator.getDirCacheEntry(), true,
-							treeWalk.getObjectReader())) {
-						// in index, in workdir, content differs => modified
-						if (!isEntryGitLink(dirCacheIterator) || !isEntryGitLink(workingTreeIterator)
-								|| (ignoreSubmoduleMode != IgnoreSubmoduleMode.ALL && ignoreSubmoduleMode != IgnoreSubmoduleMode.DIRTY))
-							modified.add(treeWalk.getPathString());
+				for (int i = 0; i < treeWalk.getTreeCount(); i++) {
+					Set<String> values = fileModes.get(treeWalk.getFileMode(i));
+					String path = treeWalk.getPathString();
+					if (path != null) {
+						if (values == null)
+							values = new HashSet<String>();
+						values.add(path);
+						fileModes.put(treeWalk.getFileMode(i), values);
 					}
 				}
 			}
-
-			for (int i = 0; i < treeWalk.getTreeCount(); i++) {
-				Set<String> values = fileModes.get(treeWalk.getFileMode(i));
-				String path = treeWalk.getPathString();
-				if (path != null) {
-					if (values == null)
-						values = new HashSet<String>();
-					values.add(path);
-					fileModes.put(treeWalk.getFileMode(i), values);
-				}
-			}
 		}
 
 		if (ignoreSubmoduleMode != IgnoreSubmoduleMode.ALL) {
@@ -525,9 +531,9 @@
 							.equals(localIgnoreSubmoduleMode))
 						continue;
 				} catch (ConfigInvalidException e) {
-					IOException e1 = new IOException(
-							"Found invalid ignore param for submodule "
-									+ smw.getPath());
+					IOException e1 = new IOException(MessageFormat.format(
+							JGitText.get().invalidIgnoreParamSubmodule,
+							smw.getPath()));
 					e1.initCause(e);
 					throw e1;
 				}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
index 359b592..33c65ab 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectChecker.java
@@ -254,25 +254,32 @@
 		int ptr = 0;
 
 		if ((ptr = match(raw, ptr, tree)) < 0)
-			throw new CorruptObjectException("no tree header");
+			throw new CorruptObjectException(
+					JGitText.get().corruptObjectNotreeHeader);
 		if ((ptr = id(raw, ptr)) < 0 || raw[ptr++] != '\n')
-			throw new CorruptObjectException("invalid tree");
+			throw new CorruptObjectException(
+					JGitText.get().corruptObjectInvalidTree);
 
 		while (match(raw, ptr, parent) >= 0) {
 			ptr += parent.length;
 			if ((ptr = id(raw, ptr)) < 0 || raw[ptr++] != '\n')
-				throw new CorruptObjectException("invalid parent");
+				throw new CorruptObjectException(
+						JGitText.get().corruptObjectInvalidParent);
 		}
 
 		if ((ptr = match(raw, ptr, author)) < 0)
-			throw new CorruptObjectException("no author");
+			throw new CorruptObjectException(
+					JGitText.get().corruptObjectNoAuthor);
 		if ((ptr = personIdent(raw, ptr)) < 0 || raw[ptr++] != '\n')
-			throw new CorruptObjectException("invalid author");
+			throw new CorruptObjectException(
+					JGitText.get().corruptObjectInvalidAuthor);
 
 		if ((ptr = match(raw, ptr, committer)) < 0)
-			throw new CorruptObjectException("no committer");
+			throw new CorruptObjectException(
+					JGitText.get().corruptObjectNoCommitter);
 		if ((ptr = personIdent(raw, ptr)) < 0 || raw[ptr++] != '\n')
-			throw new CorruptObjectException("invalid committer");
+			throw new CorruptObjectException(
+					JGitText.get().corruptObjectInvalidCommitter);
 	}
 
 	/**
@@ -287,21 +294,26 @@
 		int ptr = 0;
 
 		if ((ptr = match(raw, ptr, object)) < 0)
-			throw new CorruptObjectException("no object header");
+			throw new CorruptObjectException(
+					JGitText.get().corruptObjectNoObjectHeader);
 		if ((ptr = id(raw, ptr)) < 0 || raw[ptr++] != '\n')
-			throw new CorruptObjectException("invalid object");
+			throw new CorruptObjectException(
+					JGitText.get().corruptObjectInvalidObject);
 
 		if ((ptr = match(raw, ptr, type)) < 0)
-			throw new CorruptObjectException("no type header");
+			throw new CorruptObjectException(
+					JGitText.get().corruptObjectNoTypeHeader);
 		ptr = nextLF(raw, ptr);
 
 		if ((ptr = match(raw, ptr, tag)) < 0)
-			throw new CorruptObjectException("no tag header");
+			throw new CorruptObjectException(
+					JGitText.get().corruptObjectNoTagHeader);
 		ptr = nextLF(raw, ptr);
 
 		if ((ptr = match(raw, ptr, tagger)) > 0) {
 			if ((ptr = personIdent(raw, ptr)) < 0 || raw[ptr++] != '\n')
-				throw new CorruptObjectException("invalid tagger");
+				throw new CorruptObjectException(
+						JGitText.get().corruptObjectInvalidTagger);
 		}
 	}
 
@@ -382,37 +394,46 @@
 			int thisMode = 0;
 			for (;;) {
 				if (ptr == sz)
-					throw new CorruptObjectException("truncated in mode");
+					throw new CorruptObjectException(
+							JGitText.get().corruptObjectTruncatedInMode);
 				final byte c = raw[ptr++];
 				if (' ' == c)
 					break;
 				if (c < '0' || c > '7')
-					throw new CorruptObjectException("invalid mode character");
+					throw new CorruptObjectException(
+							JGitText.get().corruptObjectInvalidModeChar);
 				if (thisMode == 0 && c == '0' && !allowZeroMode)
-					throw new CorruptObjectException("mode starts with '0'");
+					throw new CorruptObjectException(
+							JGitText.get().corruptObjectInvalidModeStartsZero);
 				thisMode <<= 3;
 				thisMode += c - '0';
 			}
 
 			if (FileMode.fromBits(thisMode).getObjectType() == Constants.OBJ_BAD)
-				throw new CorruptObjectException("invalid mode " + thisMode);
+				throw new CorruptObjectException(MessageFormat.format(
+						JGitText.get().corruptObjectInvalidMode2,
+						Integer.valueOf(thisMode)));
 
 			final int thisNameB = ptr;
 			ptr = scanPathSegment(raw, ptr, sz);
 			if (ptr == sz || raw[ptr] != 0)
-				throw new CorruptObjectException("truncated in name");
+				throw new CorruptObjectException(
+						JGitText.get().corruptObjectTruncatedInName);
 			checkPathSegment2(raw, thisNameB, ptr);
 			if (normalized != null) {
 				if (!normalized.add(normalize(raw, thisNameB, ptr)))
-					throw new CorruptObjectException("duplicate entry names");
+					throw new CorruptObjectException(
+							JGitText.get().corruptObjectDuplicateEntryNames);
 			} else if (duplicateName(raw, thisNameB, ptr))
-				throw new CorruptObjectException("duplicate entry names");
+				throw new CorruptObjectException(
+						JGitText.get().corruptObjectDuplicateEntryNames);
 
 			if (lastNameB != 0) {
 				final int cmp = pathCompare(raw, lastNameB, lastNameE,
 						lastMode, thisNameB, ptr, thisMode);
 				if (cmp > 0)
-					throw new CorruptObjectException("incorrectly sorted");
+					throw new CorruptObjectException(
+							JGitText.get().corruptObjectIncorrectSorting);
 			}
 
 			lastNameB = thisNameB;
@@ -421,7 +442,8 @@
 
 			ptr += 1 + Constants.OBJECT_ID_LENGTH;
 			if (ptr > sz)
-				throw new CorruptObjectException("truncated in object id");
+				throw new CorruptObjectException(
+						JGitText.get().corruptObjectTruncatedInObjectId);
 		}
 	}
 
@@ -432,13 +454,16 @@
 			if (c == 0)
 				return ptr;
 			if (c == '/')
-				throw new CorruptObjectException("name contains '/'");
+				throw new CorruptObjectException(
+						JGitText.get().corruptObjectNameContainsSlash);
 			if (windows && isInvalidOnWindows(c)) {
 				if (c > 31)
 					throw new CorruptObjectException(String.format(
-							"name contains '%c'", c));
+							JGitText.get().corruptObjectNameContainsChar,
+							Byte.valueOf(c)));
 				throw new CorruptObjectException(String.format(
-						"name contains byte 0x%x", c & 0xff));
+						JGitText.get().corruptObjectNameContainsByte,
+						Integer.valueOf(c & 0xff)));
 			}
 		}
 		return ptr;
@@ -496,49 +521,55 @@
 			throws CorruptObjectException {
 		int e = scanPathSegment(raw, ptr, end);
 		if (e < end && raw[e] == 0)
-			throw new CorruptObjectException("name contains byte 0x00");
+			throw new CorruptObjectException(
+					JGitText.get().corruptObjectNameContainsNullByte);
 		checkPathSegment2(raw, ptr, end);
 	}
 
 	private void checkPathSegment2(byte[] raw, int ptr, int end)
 			throws CorruptObjectException {
 		if (ptr == end)
-			throw new CorruptObjectException("zero length name");
+			throw new CorruptObjectException(
+					JGitText.get().corruptObjectNameZeroLength);
 		if (raw[ptr] == '.') {
 			switch (end - ptr) {
 			case 1:
-				throw new CorruptObjectException("invalid name '.'");
+				throw new CorruptObjectException(
+						JGitText.get().corruptObjectNameDot);
 			case 2:
 				if (raw[ptr + 1] == '.')
-					throw new CorruptObjectException("invalid name '..'");
+					throw new CorruptObjectException(
+							JGitText.get().corruptObjectNameDotDot);
 				break;
 			case 4:
 				if (isGit(raw, ptr + 1))
 					throw new CorruptObjectException(String.format(
-							"invalid name '%s'",
+							JGitText.get().corruptObjectInvalidName,
 							RawParseUtils.decode(raw, ptr, end)));
 				break;
 			default:
 				if (end - ptr > 4 && isNormalizedGit(raw, ptr + 1, end))
 					throw new CorruptObjectException(String.format(
-							"invalid name '%s'",
+							JGitText.get().corruptObjectInvalidName,
 							RawParseUtils.decode(raw, ptr, end)));
 			}
 		} else if (isGitTilde1(raw, ptr, end)) {
-			throw new CorruptObjectException(String.format("invalid name '%s'",
+			throw new CorruptObjectException(String.format(
+					JGitText.get().corruptObjectInvalidName,
 					RawParseUtils.decode(raw, ptr, end)));
 		}
 
 		if (macosx && isMacHFSGit(raw, ptr, end))
 			throw new CorruptObjectException(String.format(
-					"invalid name '%s' contains ignorable Unicode characters",
+					JGitText.get().corruptObjectInvalidNameIgnorableUnicode,
 					RawParseUtils.decode(raw, ptr, end)));
 
 		if (windows) {
 			// Windows ignores space and dot at end of file name.
 			if (raw[end - 1] == ' ' || raw[end - 1] == '.')
-				throw new CorruptObjectException("invalid name ends with '"
-						+ ((char) raw[end - 1]) + "'");
+				throw new CorruptObjectException(String.format(
+						JGitText.get().corruptObjectInvalidNameEnd,
+						Character.valueOf(((char) raw[end - 1]))));
 			if (end - ptr >= 3)
 				checkNotWindowsDevice(raw, ptr, end);
 		}
@@ -615,7 +646,7 @@
 			throws CorruptObjectException {
 		if ((ptr + 2) >= end)
 			throw new CorruptObjectException(MessageFormat.format(
-				"invalid name contains byte sequence ''{0}'' which is not a valid UTF-8 character",
+					JGitText.get().corruptObjectInvalidNameInvalidUtf8,
 					toHexString(raw, ptr, end)));
 	}
 
@@ -634,7 +665,8 @@
 					&& toLower(raw[ptr + 1]) == 'u'
 					&& toLower(raw[ptr + 2]) == 'x'
 					&& (end - ptr == 3 || raw[ptr + 3] == '.'))
-				throw new CorruptObjectException("invalid name 'AUX'");
+				throw new CorruptObjectException(
+						JGitText.get().corruptObjectInvalidNameAux);
 			break;
 
 		case 'c': // CON, COM[1-9]
@@ -642,14 +674,16 @@
 					&& toLower(raw[ptr + 2]) == 'n'
 					&& toLower(raw[ptr + 1]) == 'o'
 					&& (end - ptr == 3 || raw[ptr + 3] == '.'))
-				throw new CorruptObjectException("invalid name 'CON'");
+				throw new CorruptObjectException(
+						JGitText.get().corruptObjectInvalidNameCon);
 			if (end - ptr >= 4
 					&& toLower(raw[ptr + 2]) == 'm'
 					&& toLower(raw[ptr + 1]) == 'o'
 					&& isPositiveDigit(raw[ptr + 3])
 					&& (end - ptr == 4 || raw[ptr + 4] == '.'))
-				throw new CorruptObjectException("invalid name 'COM"
-						+ ((char) raw[ptr + 3]) + "'");
+				throw new CorruptObjectException(String.format(
+						JGitText.get().corruptObjectInvalidNameCom,
+						Character.valueOf(((char) raw[ptr + 3]))));
 			break;
 
 		case 'l': // LPT[1-9]
@@ -658,8 +692,9 @@
 					&& toLower(raw[ptr + 2]) == 't'
 					&& isPositiveDigit(raw[ptr + 3])
 					&& (end - ptr == 4 || raw[ptr + 4] == '.'))
-				throw new CorruptObjectException("invalid name 'LPT"
-						+ ((char) raw[ptr + 3]) + "'");
+				throw new CorruptObjectException(String.format(
+						JGitText.get().corruptObjectInvalidNameLpt,
+						Character.valueOf(((char) raw[ptr + 3]))));
 			break;
 
 		case 'n': // NUL
@@ -667,7 +702,8 @@
 					&& toLower(raw[ptr + 1]) == 'u'
 					&& toLower(raw[ptr + 2]) == 'l'
 					&& (end - ptr == 3 || raw[ptr + 3] == '.'))
-				throw new CorruptObjectException("invalid name 'NUL'");
+				throw new CorruptObjectException(
+						JGitText.get().corruptObjectInvalidNameNul);
 			break;
 
 		case 'p': // PRN
@@ -675,7 +711,8 @@
 					&& toLower(raw[ptr + 1]) == 'r'
 					&& toLower(raw[ptr + 2]) == 'n'
 					&& (end - ptr == 3 || raw[ptr + 3] == '.'))
-				throw new CorruptObjectException("invalid name 'PRN'");
+				throw new CorruptObjectException(
+						JGitText.get().corruptObjectInvalidNamePrn);
 			break;
 		}
 	}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java
index 2f04751..bdbffee 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectId.java
@@ -45,6 +45,7 @@
 package org.eclipse.jgit.lib;
 
 import org.eclipse.jgit.errors.InvalidObjectIdException;
+import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.util.NB;
 import org.eclipse.jgit.util.RawParseUtils;
 
@@ -52,6 +53,7 @@
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.io.Serializable;
+import java.text.MessageFormat;
 
 /**
  * A SHA-1 abstraction.
@@ -229,7 +231,8 @@
 	 */
 	public static ObjectId fromString(final String str) {
 		if (str.length() != Constants.OBJECT_ID_STRING_LENGTH)
-			throw new IllegalArgumentException("Invalid id: " + str);
+			throw new IllegalArgumentException(
+					MessageFormat.format(JGitText.get().invalidId, str));
 		return fromHexString(Constants.encodeASCII(str), 0);
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectInserter.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectInserter.java
index f053269..d9da65f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectInserter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectInserter.java
@@ -52,6 +52,7 @@
 import java.io.InputStream;
 import java.security.MessageDigest;
 
+import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.transport.PackParser;
 
 /**
@@ -63,7 +64,7 @@
  * <p>
  * Objects written by an inserter may not be immediately visible for reading
  * after the insert method completes. Callers must invoke either
- * {@link #release()} or {@link #flush()} prior to updating references or
+ * {@link #close()} or {@link #flush()} prior to updating references or
  * otherwise making the returned ObjectIds visible to other code.
  */
 public abstract class ObjectInserter implements AutoCloseable {
@@ -91,7 +92,7 @@
 		}
 
 		@Override
-		public void release() {
+		public void close() {
 			// Do nothing.
 		}
 	}
@@ -149,8 +150,8 @@
 			delegate().flush();
 		}
 
-		public void release() {
-			delegate().release();
+		public void close() {
+			delegate().close();
 		}
 	}
 
@@ -263,7 +264,7 @@
 		while (length > 0) {
 			int n = in.read(buf, 0, (int) Math.min(length, buf.length));
 			if (n < 0)
-				throw new EOFException("Unexpected end of input");
+				throw new EOFException(JGitText.get().unexpectedEndOfInput);
 			md.update(buf, 0, n);
 			length -= n;
 		}
@@ -420,21 +421,10 @@
 	 * Release any resources used by this inserter.
 	 * <p>
 	 * An inserter that has been released can be used again, but may need to be
-	 * released after the subsequent usage. Use {@link #close()} instead
-	 */
-	@Deprecated
-	public abstract void release();
-
-	/**
-	 * Release any resources used by this inserter.
-	 * <p>
-	 * An inserter that has been released can be used again, but may need to be
 	 * released after the subsequent usage.
 	 *
 	 * @since 4.0
 	 */
 	@Override
-	public void close() {
-		release();
-	}
+	public abstract void close();
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java
index 4c4e534..4c9af85 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/ObjectReader.java
@@ -425,17 +425,6 @@
 	 * Release any resources used by this reader.
 	 * <p>
 	 * A reader that has been released can be used again, but may need to be
-	 * released after the subsequent usage. Use {@link #close()} instead.
-	 */
-	@Deprecated
-	public void release() {
-		close();
-	}
-
-	/**
-	 * Release any resources used by this reader.
-	 * <p>
-	 * A reader that has been released can be used again, but may need to be
 	 * released after the subsequent usage.
 	 *
 	 * @since 4.0
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java
index 8f7e3ef..e859119 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/PersonIdent.java
@@ -51,6 +51,7 @@
 import java.util.Locale;
 import java.util.TimeZone;
 
+import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.util.SystemReader;
 
 /**
@@ -181,10 +182,10 @@
 			final long aWhen, final int aTZ) {
 		if (aName == null)
 			throw new IllegalArgumentException(
-					"Name of PersonIdent must not be null.");
+					JGitText.get().personIdentNameNonNull);
 		if (aEmailAddress == null)
 			throw new IllegalArgumentException(
-					"E-mail address of PersonIdent must not be null.");
+					JGitText.get().personIdentEmailNonNull);
 		name = aName;
 		emailAddress = aEmailAddress;
 		when = aWhen;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java
index f47dff7..aeef9f0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RefUpdate.java
@@ -460,11 +460,8 @@
 	 *             an unexpected IO error occurred while writing changes.
 	 */
 	public Result update() throws IOException {
-		RevWalk rw = new RevWalk(getRepository());
-		try {
+		try (RevWalk rw = new RevWalk(getRepository())) {
 			return update(rw);
-		} finally {
-			rw.release();
 		}
 	}
 
@@ -510,11 +507,8 @@
 	 * @throws IOException
 	 */
 	public Result delete() throws IOException {
-		RevWalk rw = new RevWalk(getRepository());
-		try {
+		try (RevWalk rw = new RevWalk(getRepository())) {
 			return delete(rw);
-		} finally {
-			rw.release();
 		}
 	}
 
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 b0fe331..fc7dca2 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/Repository.java
@@ -379,8 +379,7 @@
 	public ObjectId resolve(final String revstr)
 			throws AmbiguousObjectException, IncorrectObjectTypeException,
 			RevisionSyntaxException, IOException {
-		RevWalk rw = new RevWalk(this);
-		try {
+		try (RevWalk rw = new RevWalk(this)) {
 			Object resolved = resolve(rw, revstr);
 			if (resolved instanceof String) {
 				final Ref ref = getRef((String)resolved);
@@ -388,8 +387,6 @@
 			} else {
 				return (ObjectId) resolved;
 			}
-		} finally {
-			rw.release();
 		}
 	}
 
@@ -406,8 +403,7 @@
 	 */
 	public String simplify(final String revstr)
 			throws AmbiguousObjectException, IOException {
-		RevWalk rw = new RevWalk(this);
-		try {
+		try (RevWalk rw = new RevWalk(this)) {
 			Object resolved = resolve(rw, revstr);
 			if (resolved != null)
 				if (resolved instanceof String)
@@ -415,8 +411,6 @@
 				else
 					return ((AnyObjectId) resolved).getName();
 			return null;
-		} finally {
-			rw.release();
 		}
 	}
 
@@ -757,8 +751,11 @@
 
 	private String resolveReflogCheckout(int checkoutNo)
 			throws IOException {
-		List<ReflogEntry> reflogEntries = getReflogReader(Constants.HEAD)
-				.getReverseEntries();
+		ReflogReader reader = getReflogReader(Constants.HEAD);
+		if (reader == null) {
+			return null;
+		}
+		List<ReflogEntry> reflogEntries = reader.getReverseEntries();
 		for (ReflogEntry entry : reflogEntries) {
 			CheckoutEntry checkout = entry.parseCheckout();
 			if (checkout != null)
@@ -779,6 +776,11 @@
 		}
 		assert number >= 0;
 		ReflogReader reader = getReflogReader(ref.getName());
+		if (reader == null) {
+			throw new RevisionSyntaxException(
+					MessageFormat.format(JGitText.get().reflogEntryNotFound,
+							Integer.valueOf(number), ref.getName()));
+		}
 		ReflogEntry entry = reader.getReverseEntry(number);
 		if (entry == null)
 			throw new RevisionSyntaxException(MessageFormat.format(
@@ -791,8 +793,7 @@
 	private ObjectId resolveAbbreviation(final String revstr) throws IOException,
 			AmbiguousObjectException {
 		AbbreviatedObjectId id = AbbreviatedObjectId.fromString(revstr);
-		ObjectReader reader = newObjectReader();
-		try {
+		try (ObjectReader reader = newObjectReader()) {
 			Collection<ObjectId> matches = reader.resolve(id);
 			if (matches.size() == 0)
 				return null;
@@ -800,8 +801,6 @@
 				return matches.iterator().next();
 			else
 				throw new AmbiguousObjectException(id, matches);
-		} finally {
-			reader.release();
 		}
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryState.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryState.java
index 4fac2eb..9b7234b 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryState.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/RepositoryState.java
@@ -73,7 +73,9 @@
 		public boolean isRebasing() { return false; }
 
 		@Override
-		public String getDescription() { return "Bare"; }
+		public String getDescription() {
+			return JGitText.get().repositoryState_bare;
+		}
 	},
 
 	/**
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java
index d94e728..191f3d8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/MergeMessageFormatter.java
@@ -97,27 +97,27 @@
 		List<String> listings = new ArrayList<String>();
 
 		if (!branches.isEmpty())
-			listings.add(joinNames(branches, "branch", "branches"));
+			listings.add(joinNames(branches, "branch", "branches")); //$NON-NLS-1$//$NON-NLS-2$
 
 		if (!remoteBranches.isEmpty())
-			listings.add(joinNames(remoteBranches, "remote-tracking branch",
-					"remote-tracking branches"));
+			listings.add(joinNames(remoteBranches, "remote-tracking branch", //$NON-NLS-1$
+					"remote-tracking branches")); //$NON-NLS-1$
 
 		if (!tags.isEmpty())
-			listings.add(joinNames(tags, "tag", "tags"));
+			listings.add(joinNames(tags, "tag", "tags")); //$NON-NLS-1$ //$NON-NLS-2$
 
 		if (!commits.isEmpty())
-			listings.add(joinNames(commits, "commit", "commits"));
+			listings.add(joinNames(commits, "commit", "commits")); //$NON-NLS-1$ //$NON-NLS-2$
 
 		if (!others.isEmpty())
-			listings.add(StringUtils.join(others, ", ", " and ")); //$NON-NLS-1$
+			listings.add(StringUtils.join(others, ", ", " and ")); //$NON-NLS-1$ //$NON-NLS-2$
 
 		sb.append(StringUtils.join(listings, ", ")); //$NON-NLS-1$
 
 		String targetName = target.getLeaf().getName();
 		if (!targetName.equals(Constants.R_HEADS + Constants.MASTER)) {
 			String targetShortName = Repository.shortenRefName(targetName);
-			sb.append(" into " + targetShortName);
+			sb.append(" into " + targetShortName); //$NON-NLS-1$
 		}
 
 		return sb.toString();
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java
index 36ffe7a..aef47c5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/RecursiveMerger.java
@@ -269,14 +269,15 @@
 	private DirCache dircacheFromTree(ObjectId treeId) throws IOException {
 		DirCache ret = DirCache.newInCore();
 		DirCacheBuilder aBuilder = ret.builder();
-		TreeWalk atw = new TreeWalk(reader);
-		atw.addTree(treeId);
-		atw.setRecursive(true);
-		while (atw.next()) {
-			DirCacheEntry e = new DirCacheEntry(atw.getRawPath());
-			e.setFileMode(atw.getFileMode(0));
-			e.setObjectId(atw.getObjectId(0));
-			aBuilder.add(e);
+		try (TreeWalk atw = new TreeWalk(reader)) {
+			atw.addTree(treeId);
+			atw.setRecursive(true);
+			while (atw.next()) {
+				DirCacheEntry e = new DirCacheEntry(atw.getRawPath());
+				e.setFileMode(atw.getFileMode(0));
+				e.setObjectId(atw.getObjectId(0));
+				aBuilder.add(e);
+			}
 		}
 		aBuilder.finish();
 		return ret;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/SquashMessageFormatter.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/SquashMessageFormatter.java
index 8931fd6..39138b9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/SquashMessageFormatter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/SquashMessageFormatter.java
@@ -76,9 +76,9 @@
 	 */
 	public String format(List<RevCommit> squashedCommits, Ref target) {
 		StringBuilder sb = new StringBuilder();
-		sb.append("Squashed commit of the following:\n");
+		sb.append("Squashed commit of the following:\n"); //$NON-NLS-1$
 		for (RevCommit c : squashedCommits) {
-			sb.append("\ncommit ");
+			sb.append("\ncommit "); //$NON-NLS-1$
 			sb.append(c.getName());
 			sb.append("\n"); //$NON-NLS-1$
 			sb.append(toString(c.getAuthorIdent()));
@@ -92,12 +92,12 @@
 	private String toString(PersonIdent author) {
 		final StringBuilder a = new StringBuilder();
 
-		a.append("Author: ");
+		a.append("Author: "); //$NON-NLS-1$
 		a.append(author.getName());
 		a.append(" <"); //$NON-NLS-1$
 		a.append(author.getEmailAddress());
 		a.append(">\n"); //$NON-NLS-1$
-		a.append("Date:   ");
+		a.append("Date:   "); //$NON-NLS-1$
 		a.append(dateFormatter.formatDate(author));
 		a.append("\n"); //$NON-NLS-1$
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyRecursive.java b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyRecursive.java
index 58c1ed2..22e608e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyRecursive.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/merge/StrategyRecursive.java
@@ -64,6 +64,6 @@
 
 	@Override
 	public String getName() {
-		return "recursive";
+		return "recursive"; //$NON-NLS-1$
 	}
 }
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/notes/LeafBucket.java b/org.eclipse.jgit/src/org/eclipse/jgit/notes/LeafBucket.java
index ea4d7bc..41f7501 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/notes/LeafBucket.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/notes/LeafBucket.java
@@ -53,6 +53,7 @@
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.ObjectId;
 import org.eclipse.jgit.lib.ObjectInserter;
+import org.eclipse.jgit.lib.ObjectInserter.Formatter;
 import org.eclipse.jgit.lib.ObjectReader;
 import org.eclipse.jgit.lib.TreeFormatter;
 
@@ -183,7 +184,9 @@
 
 	@Override
 	ObjectId getTreeId() {
-		return new ObjectInserter.Formatter().idFor(build());
+		try (Formatter f = new ObjectInserter.Formatter()) {
+			return f.idFor(build());
+		}
 	}
 
 	private TreeFormatter build() {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
index d1009ab..afb208e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/RevWalk.java
@@ -245,17 +245,6 @@
 	 * Release any resources used by this walker's reader.
 	 * <p>
 	 * A walker that has been released can be used again, but may need to be
-	 * released after the subsequent usage. Use {@link #close()} instead.
-	 */
-	@Deprecated
-	public void release() {
-		close();
-	}
-
-	/**
-	 * Release any resources used by this walker's reader.
-	 * <p>
-	 * A walker that has been released can be used again, but may need to be
 	 * released after the subsequent usage.
 	 *
 	 * @since 4.0
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 a01f006..7d9bca0 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/submodule/SubmoduleWalk.java
@@ -122,7 +122,7 @@
 			DirCache index = repository.readDirCache();
 			generator.setTree(new DirCacheIterator(index));
 		} catch (IOException e) {
-			generator.release();
+			generator.close();
 			throw e;
 		}
 		return generator;
@@ -152,10 +152,10 @@
 				if (filter.isDone(generator.walk))
 					return generator;
 		} catch (IOException e) {
-			generator.release();
+			generator.close();
 			throw e;
 		}
-		generator.release();
+		generator.close();
 		return null;
 	}
 
@@ -183,10 +183,10 @@
 				if (filter.isDone(generator.walk))
 					return generator;
 		} catch (IOException e) {
-			generator.release();
+			generator.close();
 			throw e;
 		}
-		generator.release();
+		generator.close();
 		return null;
 	}
 
@@ -419,8 +419,7 @@
 			config.load();
 			modulesConfig = config;
 		} else {
-			TreeWalk configWalk = new TreeWalk(repository);
-			try {
+			try (TreeWalk configWalk = new TreeWalk(repository)) {
 				configWalk.addTree(rootTree);
 
 				// The root tree may be part of the submodule walk, so we need to revert
@@ -446,8 +445,6 @@
 					if (idx > 0)
 						rootTree.next(idx);
 				}
-			} finally {
-				configWalk.release();
 			}
 		}
 		return this;
@@ -730,15 +727,6 @@
 	}
 
 	/**
-	 * Release any resources used by this walker's reader. Use {@link #close()}
-	 * instead.
-	 */
-	@Deprecated
-	public void release() {
-		close();
-	}
-
-	/**
 	 * Release any resources used by this walker's reader.
 	 *
 	 * @since 4.0
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java
index f43ea63..d3cdba5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/AmazonS3.java
@@ -292,10 +292,10 @@
 			case HttpURLConnection.HTTP_INTERNAL_ERROR:
 				continue;
 			default:
-				throw error("Reading", key, c);
+				throw error(JGitText.get().s3ActionReading, key, c);
 			}
 		}
-		throw maxAttempts("Reading", key);
+		throw maxAttempts(JGitText.get().s3ActionReading, key);
 	}
 
 	/**
@@ -365,10 +365,10 @@
 			case HttpURLConnection.HTTP_INTERNAL_ERROR:
 				continue;
 			default:
-				throw error("Deletion", key, c);
+				throw error(JGitText.get().s3ActionDeletion, key, c);
 			}
 		}
-		throw maxAttempts("Deletion", key);
+		throw maxAttempts(JGitText.get().s3ActionDeletion, key);
 	}
 
 	/**
@@ -426,10 +426,10 @@
 			case HttpURLConnection.HTTP_INTERNAL_ERROR:
 				continue;
 			default:
-				throw error("Writing", key, c);
+				throw error(JGitText.get().s3ActionWriting, key, c);
 			}
 		}
-		throw maxAttempts("Writing", key);
+		throw maxAttempts(JGitText.get().s3ActionWriting, key);
 	}
 
 	/**
@@ -512,10 +512,10 @@
 			case HttpURLConnection.HTTP_INTERNAL_ERROR:
 				continue;
 			default:
-				throw error("Writing", key, c);
+				throw error(JGitText.get().s3ActionWriting, key, c);
 			}
 		}
-		throw maxAttempts("Writing", key);
+		throw maxAttempts(JGitText.get().s3ActionWriting, key);
 	}
 
 	private IOException error(final String action, final String key,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
index a18df0d..eb77012 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/BaseReceivePack.java
@@ -46,6 +46,7 @@
 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_ATOMIC;
 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_DELETE_REFS;
 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_OFS_DELTA;
+import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_QUIET;
 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_REPORT_STATUS;
 import static org.eclipse.jgit.transport.GitProtocolConstants.CAPABILITY_SIDE_BAND_64K;
 import static org.eclipse.jgit.transport.GitProtocolConstants.OPTION_AGENT;
@@ -176,6 +177,7 @@
 	private boolean allowNonFastForwards;
 
 	private boolean allowOfsDelta;
+	private boolean allowQuiet = true;
 
 	/** Identity to record action as within the reflog. */
 	private PersonIdent refLogIdent;
@@ -234,6 +236,8 @@
 	/** If {@link BasePackPushConnection#CAPABILITY_SIDE_BAND_64K} is enabled. */
 	private boolean sideBand;
 
+	private boolean quiet;
+
 	/** Lock around the received pack file, while updating refs. */
 	private PackLock packLock;
 
@@ -741,6 +745,45 @@
 	}
 
 	/**
+	 * @return true if clients may request avoiding noisy progress messages.
+	 * @since 4.0
+	 */
+	public boolean isAllowQuiet() {
+		return allowQuiet;
+	}
+
+	/**
+	 * Configure if clients may request the server skip noisy messages.
+	 *
+	 * @param allow
+	 *            true to allow clients to request quiet behavior; false to
+	 *            refuse quiet behavior and send messages anyway. This may be
+	 *            necessary if processing is slow and the client-server network
+	 *            connection can timeout.
+	 * @since 4.0
+	 */
+	public void setAllowQuiet(boolean allow) {
+		allowQuiet = allow;
+	}
+
+	/**
+	 * True if the client wants less verbose output.
+	 *
+	 * @return true if the client has requested the server to be less verbose.
+	 * @throws RequestNotYetReadException
+	 *             if the client's request has not yet been read from the wire,
+	 *             so we do not know if they expect side-band. Note that the
+	 *             client may have already written the request, it just has not
+	 *             been read.
+	 * @since 4.0
+	 */
+	public boolean isQuiet() throws RequestNotYetReadException {
+		if (enabledCapabilities == null)
+			throw new RequestNotYetReadException();
+		return quiet;
+	}
+
+	/**
 	 * Get the user agent of the client.
 	 * <p>
 	 * If the client is new enough to use {@code agent=} capability that value
@@ -969,6 +1012,8 @@
 		adv.advertiseCapability(CAPABILITY_SIDE_BAND_64K);
 		adv.advertiseCapability(CAPABILITY_DELETE_REFS);
 		adv.advertiseCapability(CAPABILITY_REPORT_STATUS);
+		if (allowQuiet)
+			adv.advertiseCapability(CAPABILITY_QUIET);
 		if (pushCertificateParser.enabled())
 			adv.advertiseCapability(
 				pushCertificateParser.getAdvertiseNonce());
@@ -1046,6 +1091,7 @@
 	/** Enable capabilities based on a previously read capabilities line. */
 	protected void enableCapabilities() {
 		sideBand = isCapabilityEnabled(CAPABILITY_SIDE_BAND_64K);
+		quiet = allowQuiet && isCapabilityEnabled(CAPABILITY_QUIET);
 		if (sideBand) {
 			OutputStream out = rawOut;
 
@@ -1093,7 +1139,7 @@
 
 		ProgressMonitor receiving = NullProgressMonitor.INSTANCE;
 		ProgressMonitor resolving = NullProgressMonitor.INSTANCE;
-		if (sideBand)
+		if (sideBand && !quiet)
 			resolving = new SideBandProgressMonitor(msgOut);
 
 		try (ObjectInserter ins = db.newObjectInserter()) {
@@ -1130,7 +1176,7 @@
 		ObjectIdSubclassMap<ObjectId> baseObjects = null;
 		ObjectIdSubclassMap<ObjectId> providedObjects = null;
 		ProgressMonitor checking = NullProgressMonitor.INSTANCE;
-		if (sideBand) {
+		if (sideBand && !quiet) {
 			SideBandProgressMonitor m = new SideBandProgressMonitor(msgOut);
 			m.setDelayStart(750, TimeUnit.MILLISECONDS);
 			checking = m;
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
index 8d9d2b7..8d2d554 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/GitProtocolConstants.java
@@ -152,6 +152,13 @@
 	public static final String CAPABILITY_ATOMIC = "atomic"; //$NON-NLS-1$
 
 	/**
+	 * The client expects less noise, e.g. no progress.
+	 *
+	 * @since 4.0
+	 */
+	public static final String CAPABILITY_QUIET = "quiet"; //$NON-NLS-1$
+
+	/**
 	 * The client expects a status report after the server processes the pack.
 	 *
 	 * @since 3.2
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java
index e5d59b5..b4a0902 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/JschSession.java
@@ -55,6 +55,7 @@
 import java.io.PipedOutputStream;
 
 import org.eclipse.jgit.errors.TransportException;
+import org.eclipse.jgit.internal.JGitText;
 import org.eclipse.jgit.util.io.StreamCopyThread;
 
 import com.jcraft.jsch.Channel;
@@ -76,7 +77,7 @@
 	/**
 	 * Create a new session object by passing the real Jsch session and the URI
 	 * information.
-	 * 
+	 *
 	 * @param session
 	 *            the real Jsch session created elsewhere.
 	 * @param uri
@@ -149,7 +150,8 @@
 				setupStreams();
 				channel.connect(timeout > 0 ? timeout * 1000 : 0);
 				if (!channel.isConnected())
-					throw new TransportException(uri, "connection failed");
+					throw new TransportException(uri,
+							JGitText.get().connectionFailed);
 			} catch (JSchException e) {
 				throw new TransportException(uri, e.getMessage(), e);
 			}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java
index 00f84f7..9721ee9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/PushProcess.java
@@ -104,7 +104,7 @@
 
 	/**
 	 * Create process for specified transport and refs updates specification.
-	 * 
+	 *
 	 * @param transport
 	 *            transport between remote and local repository, used to create
 	 *            connection.
@@ -177,7 +177,7 @@
 			}
 			return res;
 		} finally {
-			walker.release();
+			walker.close();
 		}
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportSftp.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportSftp.java
index 756a161..c47645c 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportSftp.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/TransportSftp.java
@@ -47,6 +47,7 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.text.MessageFormat;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
@@ -179,8 +180,9 @@
 				close();
 				throw err;
 			} catch (SftpException je) {
-				throw new TransportException("Can't enter " + path + "/objects"
-						+ ": " + je.getMessage(), je); //$NON-NLS-1$
+				throw new TransportException(MessageFormat.format(
+						JGitText.get().cannotEnterObjectsPath, path,
+						je.getMessage()), je);
 			}
 		}
 
@@ -195,8 +197,9 @@
 				close();
 				throw err;
 			} catch (SftpException je) {
-				throw new TransportException("Can't enter " + p + " from "
-						+ parent.objectsPath + ": " + je.getMessage(), je); //$NON-NLS-1$
+				throw new TransportException(MessageFormat.format(
+						JGitText.get().cannotEnterPathFromParent, p,
+						parent.objectsPath, je.getMessage()), je);
 			}
 		}
 
@@ -253,8 +256,10 @@
 					}
 				});
 			} catch (SftpException je) {
-				throw new TransportException("Can't ls " + objectsPath
-						+ "/pack: " + je.getMessage(), je);
+				throw new TransportException(
+						MessageFormat.format(JGitText.get().cannotListPackPath,
+								objectsPath, je.getMessage()),
+						je);
 			}
 			return packs;
 		}
@@ -267,8 +272,9 @@
 			} catch (SftpException je) {
 				if (je.id == ChannelSftp.SSH_FX_NO_SUCH_FILE)
 					throw new FileNotFoundException(path);
-				throw new TransportException("Can't get " + objectsPath + "/" //$NON-NLS-2$
-						+ path + ": " + je.getMessage(), je); //$NON-NLS-1$
+				throw new TransportException(MessageFormat.format(
+						JGitText.get().cannotGetObjectsPath, objectsPath, path,
+						je.getMessage()), je);
 			}
 		}
 
@@ -279,8 +285,9 @@
 			} catch (SftpException je) {
 				if (je.id == ChannelSftp.SSH_FX_NO_SUCH_FILE)
 					return;
-				throw new TransportException("Can't delete " + objectsPath
-						+ "/" + path + ": " + je.getMessage(), je); //$NON-NLS-1$//$NON-NLS-2$
+				throw new TransportException(MessageFormat.format(
+						JGitText.get().cannotDeleteObjectsPath, objectsPath,
+						path, je.getMessage()), je);
 			}
 
 			// Prune any now empty directories.
@@ -318,8 +325,9 @@
 					}
 				}
 
-				throw new TransportException("Can't write " + objectsPath + "/" //$NON-NLS-2$
-						+ path + ": " + je.getMessage(), je); //$NON-NLS-1$
+				throw new TransportException(MessageFormat.format(
+						JGitText.get().cannotWriteObjectsPath, objectsPath,
+						path, je.getMessage()), je);
 			}
 		}
 
@@ -331,8 +339,9 @@
 				try {
 					ftp.rename(lock, path);
 				} catch (SftpException je) {
-					throw new TransportException("Can't write " + objectsPath
-							+ "/" + path + ": " + je.getMessage(), je); //$NON-NLS-1$//$NON-NLS-2$
+					throw new TransportException(MessageFormat.format(
+							JGitText.get().cannotWriteObjectsPath, objectsPath,
+							path, je.getMessage()), je);
 				}
 			} catch (IOException err) {
 				try {
@@ -364,8 +373,9 @@
 					}
 				}
 
-				throw new TransportException("Can't mkdir " + objectsPath + "/"
-						+ path + ": " + je.getMessage(), je);
+				throw new TransportException(MessageFormat.format(
+						JGitText.get().cannotMkdirObjectPath, objectsPath, path,
+						je.getMessage()), je);
 			}
 		}
 
@@ -385,8 +395,9 @@
 			try {
 				list = ftp.ls(dir);
 			} catch (SftpException je) {
-				throw new TransportException("Can't ls " + objectsPath + "/" //$NON-NLS-2$
-						+ dir + ": " + je.getMessage(), je); //$NON-NLS-1$
+				throw new TransportException(MessageFormat.format(
+						JGitText.get().cannotListObjectsPath, objectsPath, dir,
+						je.getMessage()), je);
 			}
 
 			for (final ChannelSftp.LsEntry ent : list) {
@@ -415,12 +426,14 @@
 			} catch (FileNotFoundException noRef) {
 				return null;
 			} catch (IOException err) {
-				throw new TransportException("Cannot read " + objectsPath + "/" //$NON-NLS-2$
-						+ path + ": " + err.getMessage(), err); //$NON-NLS-1$
+				throw new TransportException(MessageFormat.format(
+						JGitText.get().cannotReadObjectsPath, objectsPath, path,
+						err.getMessage()), err);
 			}
 
 			if (line == null)
-				throw new TransportException("Empty ref: " + name);
+				throw new TransportException(
+						MessageFormat.format(JGitText.get().emptyRef, name));
 
 			if (line.startsWith("ref: ")) { //$NON-NLS-1$
 				final String target = line.substring("ref: ".length()); //$NON-NLS-1$
@@ -441,7 +454,8 @@
 				return r;
 			}
 
-			throw new TransportException("Bad ref: " + name + ": " + line); //$NON-NLS-2$
+			throw new TransportException(
+					MessageFormat.format(JGitText.get().badRef, name, line));
 		}
 
 		private Storage loose(final Ref r) {
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 3afdb61..c60590d 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -630,7 +630,7 @@
 			service();
 		} finally {
 			msgOut = NullOutputStream.INSTANCE;
-			walk.release();
+			walk.close();
 			if (timer != null) {
 				try {
 					timer.terminate();
@@ -737,35 +737,35 @@
 	}
 
 	private void processShallow() throws IOException {
-		DepthWalk.RevWalk depthWalk =
-			new DepthWalk.RevWalk(walk.getObjectReader(), depth);
+		try (DepthWalk.RevWalk depthWalk = new DepthWalk.RevWalk(
+				walk.getObjectReader(), depth)) {
 
-		// Find all the commits which will be shallow
-		for (ObjectId o : wantIds) {
-			try {
-				depthWalk.markRoot(depthWalk.parseCommit(o));
-			} catch (IncorrectObjectTypeException notCommit) {
-				// Ignore non-commits in this loop.
+			// Find all the commits which will be shallow
+			for (ObjectId o : wantIds) {
+				try {
+					depthWalk.markRoot(depthWalk.parseCommit(o));
+				} catch (IncorrectObjectTypeException notCommit) {
+					// Ignore non-commits in this loop.
+				}
+			}
+
+			RevCommit o;
+			while ((o = depthWalk.next()) != null) {
+				DepthWalk.Commit c = (DepthWalk.Commit) o;
+
+				// Commits at the boundary which aren't already shallow in
+				// the client need to be marked as such
+				if (c.getDepth() == depth && !clientShallowCommits.contains(c))
+					pckOut.writeString("shallow " + o.name()); //$NON-NLS-1$
+
+				// Commits not on the boundary which are shallow in the client
+				// need to become unshallowed
+				if (c.getDepth() < depth && clientShallowCommits.remove(c)) {
+					unshallowCommits.add(c.copy());
+					pckOut.writeString("unshallow " + c.name()); //$NON-NLS-1$
+				}
 			}
 		}
-
-		RevCommit o;
-		while ((o = depthWalk.next()) != null) {
-			DepthWalk.Commit c = (DepthWalk.Commit) o;
-
-			// Commits at the boundary which aren't already shallow in
-			// the client need to be marked as such
-			if (c.getDepth() == depth && !clientShallowCommits.contains(c))
-				pckOut.writeString("shallow " + o.name()); //$NON-NLS-1$
-
-			// Commits not on the boundary which are shallow in the client
-			// need to become unshallowed
-			if (c.getDepth() < depth && clientShallowCommits.remove(c)) {
-				unshallowCommits.add(c.copy());
-				pckOut.writeString("unshallow " + c.name()); //$NON-NLS-1$
-			}
-		}
-
 		pckOut.end();
 	}
 
@@ -1460,7 +1460,7 @@
 			statistics = pw.getStatistics();
 			if (statistics != null)
 				logger.onPackStatistics(statistics);
-			pw.release();
+			pw.close();
 		}
 
 		if (sideband)
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java
index 6b7183b..dc9dee5 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkFetchConnection.java
@@ -252,8 +252,8 @@
 
 	@Override
 	public void close() {
-		inserter.release();
-		reader.release();
+		inserter.close();
+		reader.close();
 		for (final RemotePack p : unfetchedPacks) {
 			if (p.tmpIdx != null)
 				p.tmpIdx.delete();
@@ -430,7 +430,8 @@
 				final WalkRemoteObjectDatabase wrr = noPacksYet.removeFirst();
 				final Collection<String> packNameList;
 				try {
-					pm.beginTask("Listing packs", ProgressMonitor.UNKNOWN);
+					pm.beginTask(JGitText.get().listingPacks,
+							ProgressMonitor.UNKNOWN);
 					packNameList = wrr.getPackNames();
 				} catch (IOException e) {
 					// Try another repository.
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java
index 02960bf..deecb8e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/WalkPushConnection.java
@@ -220,9 +220,9 @@
 		String pathPack = null;
 		String pathIdx = null;
 
-		final PackWriter writer = new PackWriter(transport.getPackConfig(),
-				local.newObjectReader());
-		try {
+		try (final PackWriter writer = new PackWriter(transport.getPackConfig(),
+				local.newObjectReader())) {
+
 			final Set<ObjectId> need = new HashSet<ObjectId>();
 			final Set<ObjectId> have = new HashSet<ObjectId>();
 			for (final RemoteRefUpdate r : updates)
@@ -293,8 +293,6 @@
 			safeDelete(pathPack);
 
 			throw new TransportException(uri, JGitText.get().cannotStoreObjects, err);
-		} finally {
-			writer.release();
 		}
 	}
 
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
index a4d2d7e..06e8284 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/TreeWalk.java
@@ -254,17 +254,6 @@
 	 * Release any resources used by this walker's reader.
 	 * <p>
 	 * A walker that has been released can be used again, but may need to be
-	 * released after the subsequent usage. Use {@link #close()} instead.
-	 */
-	@Deprecated
-	public void release() {
-		close();
-	}
-
-	/**
-	 * Release any resources used by this walker's reader.
-	 * <p>
-	 * A walker that has been released can be used again, but may need to be
 	 * released after the subsequent usage.
 	 *
 	 * @since 4.0
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
index d11b03e..fa0292e 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS.java
@@ -53,10 +53,13 @@
 import java.io.OutputStreamWriter;
 import java.io.PrintStream;
 import java.io.PrintWriter;
+import java.nio.charset.Charset;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.text.MessageFormat;
 import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
@@ -154,7 +157,7 @@
 
 	private volatile Holder<File> userHome;
 
-	private volatile Holder<File> gitPrefix;
+	private volatile Holder<File> gitSystemConfig;
 
 	/**
 	 * Constructs a file system abstraction.
@@ -171,7 +174,7 @@
 	 */
 	protected FS(FS src) {
 		userHome = src.userHome;
-		gitPrefix = src.gitPrefix;
+		gitSystemConfig = src.gitSystemConfig;
 	}
 
 	/** @return a new instance of the same type of FS. */
@@ -403,16 +406,41 @@
 	 * @param command
 	 *            as component array
 	 * @param encoding
+	 *            to be used to parse the command's output
 	 * @return the one-line output of the command
 	 */
 	protected static String readPipe(File dir, String[] command, String encoding) {
+		return readPipe(dir, command, encoding, null);
+	}
+
+	/**
+	 * Execute a command and return a single line of output as a String
+	 *
+	 * @param dir
+	 *            Working directory for the command
+	 * @param command
+	 *            as component array
+	 * @param encoding
+	 *            to be used to parse the command's output
+	 * @param env
+	 *            Map of environment variables to be merged with those of the
+	 *            current process
+	 * @return the one-line output of the command
+	 * @since 4.0
+	 */
+	protected static String readPipe(File dir, String[] command, String encoding, Map<String, String> env) {
 		final boolean debug = LOG.isDebugEnabled();
 		try {
 			if (debug) {
 				LOG.debug("readpipe " + Arrays.asList(command) + "," //$NON-NLS-1$ //$NON-NLS-2$
 						+ dir);
 			}
-			final Process p = Runtime.getRuntime().exec(command, null, dir);
+			ProcessBuilder pb = new ProcessBuilder(command);
+			pb.directory(dir);
+			if (env != null) {
+				pb.environment().putAll(env);
+			}
+			final Process p = pb.start();
 			final BufferedReader lineRead = new BufferedReader(
 					new InputStreamReader(p.getInputStream(), encoding));
 			p.getOutputStream().close();
@@ -489,37 +517,80 @@
 		return null;
 	}
 
-	/** @return the $prefix directory C Git would use. */
-	public File gitPrefix() {
-		Holder<File> p = gitPrefix;
-		if (p == null) {
-			String overrideGitPrefix = SystemReader.getInstance().getProperty(
-					"jgit.gitprefix"); //$NON-NLS-1$
-			if (overrideGitPrefix != null)
-				p = new Holder<File>(new File(overrideGitPrefix));
-			else
-				p = new Holder<File>(discoverGitPrefix());
-			gitPrefix = p;
-		}
-		return p.value;
-	}
-
-	/** @return the $prefix directory C Git would use. */
-	protected abstract File discoverGitPrefix();
+	/**
+	 * @return the path to the Git executable or {@code null} if it cannot be
+	 *         determined.
+	 * @since 4.0
+	 */
+	protected abstract File discoverGitExe();
 
 	/**
-	 * Set the $prefix directory C Git uses.
-	 *
-	 * @param path
-	 *            the directory. Null if C Git is not installed.
-	 * @return {@code this}
+	 * @return the path to the system-wide Git configuration file or
+	 *         {@code null} if it cannot be determined.
+	 * @since 4.0
 	 */
-	public FS setGitPrefix(File path) {
-		gitPrefix = new Holder<File>(path);
+	protected File discoverGitSystemConfig() {
+		File gitExe = discoverGitExe();
+		if (gitExe == null) {
+			return null;
+		}
+
+		// Trick Git into printing the path to the config file by using "echo"
+		// as the editor.
+		Map<String, String> env = new HashMap<>();
+		env.put("GIT_EDITOR", "echo"); //$NON-NLS-1$ //$NON-NLS-2$
+
+		String w = readPipe(gitExe.getParentFile(),
+				new String[] { "git", "config", "--system", "--edit" }, //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+				Charset.defaultCharset().name(), env);
+		if (StringUtils.isEmptyOrNull(w)) {
+			return null;
+		}
+
+		return new File(w);
+	}
+
+	/**
+	 * @return the currently used path to the system-wide Git configuration
+	 *         file or {@code null} if none has been set.
+	 * @since 4.0
+	 */
+	public File getGitSystemConfig() {
+		if (gitSystemConfig == null) {
+			gitSystemConfig = new Holder<File>(discoverGitSystemConfig());
+		}
+		return gitSystemConfig.value;
+	}
+
+	/**
+	 * Set the path to the system-wide Git configuration file to use.
+	 *
+	 * @param configFile
+	 *            the path to the config file.
+	 * @return {@code this}
+	 * @since 4.0
+	 */
+	public FS setGitSystemConfig(File configFile) {
+		gitSystemConfig = new Holder<File>(configFile);
 		return this;
 	}
 
 	/**
+	 * @param grandchild
+	 * @return the parent directory of this file's parent directory or
+	 *         {@code null} in case there's no grandparent directory
+	 * @since 4.0
+	 */
+	protected static File resolveGrandparentFile(File grandchild) {
+		if (grandchild != null) {
+			File parent = grandchild.getParentFile();
+			if (parent != null)
+				return parent.getParentFile();
+		}
+		return null;
+	}
+
+	/**
 	 * Check if a file is a symbolic link and read it
 	 *
 	 * @param path
@@ -600,7 +671,7 @@
 	public void setHidden(File path, boolean hidden) throws IOException {
 		if (!path.getName().startsWith(".")) //$NON-NLS-1$
 			throw new IllegalArgumentException(
-					"Hiding only allowed for names that start with a period");
+					JGitText.get().hiddenFilesStartWithDot);
 	}
 
 	/**
@@ -901,7 +972,7 @@
 	}
 
 	/**
-	 * Initialize a ProcesssBuilder to run a command using the system shell.
+	 * Initialize a ProcessBuilder to run a command using the system shell.
 	 *
 	 * @param cmd
 	 *            command to execute. This string should originate from the
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java
index 9c92d7c..b07f859 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_POSIX.java
@@ -134,29 +134,26 @@
 	}
 
 	@Override
-	protected File discoverGitPrefix() {
+	protected File discoverGitExe() {
 		String path = SystemReader.getInstance().getenv("PATH"); //$NON-NLS-1$
 		File gitExe = searchPath(path, "git"); //$NON-NLS-1$
-		if (gitExe != null)
-			return gitExe.getParentFile().getParentFile();
 
-		if (SystemReader.getInstance().isMacOS()) {
-			// On MacOSX, PATH is shorter when Eclipse is launched from the
-			// Finder than from a terminal. Therefore try to launch bash as a
-			// login shell and search using that.
-			//
-			String w = readPipe(userHome(), //
-					new String[] { "bash", "--login", "-c", "which git" }, // //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
-					Charset.defaultCharset().name());
-			if (w == null || w.length() == 0)
-				return null;
-			File parentFile = new File(w).getParentFile();
-			if (parentFile == null)
-				return null;
-			return parentFile.getParentFile();
+		if (gitExe == null) {
+			if (SystemReader.getInstance().isMacOS()) {
+				if (searchPath(path, "bash") != null) { //$NON-NLS-1$
+					// On MacOSX, PATH is shorter when Eclipse is launched from the
+					// Finder than from a terminal. Therefore try to launch bash as a
+					// login shell and search using that.
+					String w = readPipe(userHome(),
+							new String[]{"bash", "--login", "-c", "which git"}, // //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+							Charset.defaultCharset().name());
+					if (!StringUtils.isEmptyOrNull(w))
+						gitExe = new File(w);
+				}
+			}
 		}
 
-		return null;
+		return gitExe;
 	}
 
 	@Override
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java
index 41e8113..5c652be 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/FS_Win32.java
@@ -105,36 +105,24 @@
 	}
 
 	@Override
-	protected File discoverGitPrefix() {
+	protected File discoverGitExe() {
 		String path = SystemReader.getInstance().getenv("PATH"); //$NON-NLS-1$
 		File gitExe = searchPath(path, "git.exe", "git.cmd"); //$NON-NLS-1$ //$NON-NLS-2$
-		if (gitExe != null)
-			return resolveGrandparentFile(gitExe);
 
-		if (searchPath(path, "bash.exe") != null) { //$NON-NLS-1$
-			// This isn't likely to work, but its worth trying:
-			// If bash is in $PATH, git should also be in $PATH.
-			String w = readPipe(userHome(),
-					new String[] { "bash", "--login", "-c", "which git" }, // //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
-					Charset.defaultCharset().name());
-			if (w != null) {
-				// The path may be in cygwin/msys notation so resolve it right away
-				gitExe = resolve(null, w);
-				if (gitExe != null)
-					return resolveGrandparentFile(gitExe);
+		if (gitExe == null) {
+			if (searchPath(path, "bash.exe") != null) { //$NON-NLS-1$
+				// This isn't likely to work, but its worth trying:
+				// If bash is in $PATH, git should also be in $PATH.
+				String w = readPipe(userHome(),
+						new String[]{"bash", "--login", "-c", "which git"}, // //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
+						Charset.defaultCharset().name());
+				if (!StringUtils.isEmptyOrNull(w))
+					// The path may be in cygwin/msys notation so resolve it right away
+					gitExe = resolve(null, w);
 			}
 		}
 
-		return null;
-	}
-
-	private static File resolveGrandparentFile(File grandchild) {
-		if (grandchild != null) {
-			File parent = grandchild.getParentFile();
-			if (parent != null)
-				return parent.getParentFile();
-		}
-		return null;
+		return gitExe;
 	}
 
 	@Override
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
index f6f415e..b4233b6 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/SystemReader.java
@@ -89,8 +89,8 @@
 		}
 
 		public FileBasedConfig openSystemConfig(Config parent, FS fs) {
-			File prefix = fs.gitPrefix();
-			if (prefix == null) {
+			File configFile = fs.getGitSystemConfig();
+			if (configFile == null) {
 				return new FileBasedConfig(null, fs) {
 					public void load() {
 						// empty, do not load
@@ -102,9 +102,7 @@
 					}
 				};
 			}
-			File etc = fs.resolve(prefix, "etc"); //$NON-NLS-1$
-			File config = fs.resolve(etc, "gitconfig"); //$NON-NLS-1$
-			return new FileBasedConfig(parent, config, fs);
+			return new FileBasedConfig(parent, configFile, fs);
 		}
 
 		public FileBasedConfig openUserConfig(Config parent, FS fs) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/LimitedInputStream.java b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/LimitedInputStream.java
index 85c8172..d74532f 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/util/io/LimitedInputStream.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/util/io/LimitedInputStream.java
@@ -48,6 +48,8 @@
 import java.io.IOException;
 import java.io.InputStream;
 
+import org.eclipse.jgit.internal.JGitText;
+
 /**
  * Wraps a {@link InputStream}, limiting the number of bytes which can be
  * read.
@@ -124,10 +126,10 @@
 	@Override
 	public synchronized void reset() throws IOException {
 		if (!in.markSupported())
-			throw new IOException("Mark not supported");
+			throw new IOException(JGitText.get().unsupportedMark);
 
 		if (mark == -1)
-			throw new IOException("Mark not set");
+			throw new IOException(JGitText.get().unsetMark);
 
 		in.reset();
 		left = mark;
diff --git a/pom.xml b/pom.xml
index f02fa29..ce4cc67 100644
--- a/pom.xml
+++ b/pom.xml
@@ -350,7 +350,7 @@
         <plugin>
           <groupId>org.eclipse.cbi.maven.plugins</groupId>
           <artifactId>eclipse-jarsigner-plugin</artifactId>
-          <version>1.1.2-SNAPSHOT</version>
+          <version>1.1.2</version>
         </plugin>
         <plugin>
           <groupId>org.eclipse.tycho.extras</groupId>