Update to JGit 0.8.4.240-g8e9cc82

Change-Id: Id43a1846b31bb1aad40ca0ae295a268fcacd162f
Signed-off-by: Shawn O. Pearce <sop@google.com>
diff --git a/Documentation/config-gerrit.txt b/Documentation/config-gerrit.txt
index 4b7aead..6034169 100644
--- a/Documentation/config-gerrit.txt
+++ b/Documentation/config-gerrit.txt
@@ -1313,6 +1313,32 @@
   safe = true
 ----
 
+
+[[pack]]Section pack
+~~~~~~~~~~~~~~~~~~~~
+Global settings controlling how Gerrit Code Review creates pack
+streams for Git clients running clone, fetch, or pull.  Most of these
+variables are per-client request, and thus should be carefully set
+given the expected concurrent request load and available CPU and
+memory resources.
+
+[[pack.deltacompression]]pack.deltacompression::
++
+If true, delta compression between objects is enabled.  This may
+result in a smaller overall transfer for the client, but requires
+more server memory and CPU time.
++
+False (off) by default, matching Gerrit Code Review 2.1.4.
+
+[[pack.threads]]pack.threads::
++
+Maximum number of threads to use for delta compression (if enabled).
+This is per-client request.  If set to 0 then the number of CPUs is
+auto-detected and one thread per CPU is used, per client request.
++
+By default, 1.
+
+
 [[repository]]Section repository
 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 Repositories in this sense are the same as projects.
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectServlet.java
index 3f7f68d..6a7fb06 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/ProjectServlet.java
@@ -23,6 +23,7 @@
 import com.google.gerrit.server.config.CanonicalWebUrl;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.ReceiveCommits;
+import com.google.gerrit.server.git.TransferConfig;
 import com.google.gerrit.server.git.VisibleRefFilter;
 import com.google.gerrit.server.project.NoSuchProjectException;
 import com.google.gerrit.server.project.ProjectControl;
@@ -40,6 +41,7 @@
 import org.eclipse.jgit.http.server.resolver.ServiceNotEnabledException;
 import org.eclipse.jgit.http.server.resolver.UploadPackFactory;
 import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.storage.pack.PackConfig;
 import org.eclipse.jgit.transport.ReceivePack;
 import org.eclipse.jgit.transport.UploadPack;
 import org.slf4j.Logger;
@@ -175,10 +177,12 @@
 
   static class Upload implements UploadPackFactory {
     private final Provider<ReviewDb> db;
+    private final PackConfig packConfig;
 
     @Inject
-    Upload(final Provider<ReviewDb> db) {
+    Upload(final Provider<ReviewDb> db, final TransferConfig tc) {
       this.db = db;
+      this.packConfig = tc.getPackConfig();
     }
 
     @Override
@@ -188,6 +192,7 @@
       //
       ProjectControl pc = getProjectControl(req);
       UploadPack up = new UploadPack(repo);
+      up.setPackConfig(packConfig);
       if (!pc.allRefsAreVisible()) {
         up.setRefFilter(new VisibleRefFilter(repo, pc, db.get()));
       }
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/CatServlet.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/CatServlet.java
index 3ecfa62..57e0c0c 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/CatServlet.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/raw/CatServlet.java
@@ -33,14 +33,16 @@
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectLoader;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevWalk;
 import org.eclipse.jgit.treewalk.TreeWalk;
 import org.eclipse.jgit.util.NB;
 
-import java.io.ByteArrayOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.io.UnsupportedEncodingException;
 import java.net.URLDecoder;
 import java.security.MessageDigest;
@@ -162,7 +164,7 @@
       return;
     }
 
-    final byte[] blobData;
+    final ObjectLoader blobLoader;
     final RevCommit fromCommit;
     final String suffix;
     final String path = patchKey.getFileName();
@@ -196,7 +198,7 @@
       }
 
       if (tw.getFileMode(0).getObjectType() == Constants.OBJ_BLOB) {
-        blobData = repo.openBlob(tw.getObjectId(0)).getCachedBytes();
+        blobLoader = repo.open(tw.getObjectId(0), Constants.OBJ_BLOB);
 
       } else {
         rsp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
@@ -214,14 +216,20 @@
       repo.close();
     }
 
+    final byte[] raw =
+        blobLoader.isLarge() ? null : blobLoader.getCachedBytes();
     final long when = fromCommit.getCommitTime() * 1000L;
-    MimeType contentType = registry.getMimeType(path, blobData);
-    final byte[] outData;
 
-    if (registry.isSafeInline(contentType)) {
-      outData = blobData;
+    rsp.setDateHeader("Last-Modified", when);
+    rsp.setDateHeader("Expires", 0L);
+    rsp.setHeader("Pragma", "no-cache");
+    rsp.setHeader("Cache-Control", "no-cache, must-revalidate");
 
-    } else {
+    OutputStream out;
+    ZipOutputStream zo;
+
+    final MimeType contentType = registry.getMimeType(path, raw);
+    if (!registry.isSafeInline(contentType)) {
       // The content may not be safe to transmit inline, as a browser might
       // interpret it as HTML or JavaScript hosted by this site. Such code
       // might then run in the site's security domain, and may be able to use
@@ -230,31 +238,51 @@
       // Usually, wrapping the content into a ZIP file forces the browser to
       // save the content to the local system instead.
       //
-      final ByteArrayOutputStream zip = new ByteArrayOutputStream();
-      final ZipOutputStream zo = new ZipOutputStream(zip);
-      final ZipEntry e = new ZipEntry(safeFileName(path, rand(req, suffix)));
-      e.setComment(fromCommit.name() + ":" + path);
-      e.setSize(blobData.length);
-      e.setTime(when);
-      zo.putNextEntry(e);
-      zo.write(blobData);
-      zo.closeEntry();
-      zo.close();
 
-      outData = zip.toByteArray();
-      contentType = ZIP;
-
+      rsp.setContentType(ZIP.toString());
       rsp.setHeader("Content-Disposition", "attachment; filename=\""
           + safeFileName(path, suffix) + ".zip" + "\"");
+
+      zo = new ZipOutputStream(rsp.getOutputStream());
+
+      final ZipEntry e = new ZipEntry(safeFileName(path, rand(req, suffix)));
+      e.setComment(fromCommit.name() + ":" + path);
+      e.setSize(blobLoader.getSize());
+      e.setTime(when);
+      zo.putNextEntry(e);
+      out = zo;
+
+    } else {
+      rsp.setContentType(contentType.toString());
+      rsp.setHeader("Content-Length", "" + blobLoader.getSize());
+
+      out = rsp.getOutputStream();
+      zo = null;
     }
 
-    rsp.setContentType(contentType.toString());
-    rsp.setContentLength(outData.length);
-    rsp.setDateHeader("Last-Modified", when);
-    rsp.setDateHeader("Expires", 0L);
-    rsp.setHeader("Pragma", "no-cache");
-    rsp.setHeader("Cache-Control", "no-cache, must-revalidate");
-    rsp.getOutputStream().write(outData);
+    if (raw != null) {
+      out.write(raw);
+    } else {
+      InputStream in = blobLoader.openStream();
+      try {
+        byte[] buf = new byte[8192];
+        for (;;) {
+          int n = in.read(buf);
+          if (0 < n) {
+            out.write(buf, 0, n);
+          } else {
+            break;
+          }
+        }
+      } finally {
+        in.close();
+      }
+    }
+
+    if (zo != null) {
+      zo.closeEntry();
+    }
+    out.close();
   }
 
   private static String safeFileName(String fileName, final String suffix) {
diff --git a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptBuilder.java b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptBuilder.java
index a58c7b9..9218edd 100644
--- a/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptBuilder.java
+++ b/gerrit-httpd/src/main/java/com/google/gerrit/httpd/rpc/patch/PatchScriptBuilder.java
@@ -40,7 +40,6 @@
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.ObjectLoader;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevTree;
 import org.eclipse.jgit.revwalk.RevWalk;
@@ -377,14 +376,7 @@
           srcContent = other.srcContent;
 
         } else if (mode.getObjectType() == Constants.OBJ_BLOB) {
-          final ObjectLoader ldr = db.openObject(id);
-          if (ldr == null) {
-            throw new MissingObjectException(id, Constants.TYPE_BLOB);
-          }
-          srcContent = ldr.getCachedBytes();
-          if (ldr.getType() != Constants.OBJ_BLOB) {
-            throw new IncorrectObjectTypeException(id, Constants.TYPE_BLOB);
-          }
+          srcContent = Text.asByteArray(db.open(id, Constants.OBJ_BLOB));
 
         } else {
           srcContent = Text.NO_BYTES;
diff --git a/gerrit-patch-jgit/src/main/java/org/eclipse/jgit/lib/WindowCacheStatAccessor.java b/gerrit-patch-jgit/src/main/java/org/eclipse/jgit/storage/file/WindowCacheStatAccessor.java
similarity index 95%
rename from gerrit-patch-jgit/src/main/java/org/eclipse/jgit/lib/WindowCacheStatAccessor.java
rename to gerrit-patch-jgit/src/main/java/org/eclipse/jgit/storage/file/WindowCacheStatAccessor.java
index 7d12e47..7e29536 100644
--- a/gerrit-patch-jgit/src/main/java/org/eclipse/jgit/lib/WindowCacheStatAccessor.java
+++ b/gerrit-patch-jgit/src/main/java/org/eclipse/jgit/storage/file/WindowCacheStatAccessor.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package org.eclipse.jgit.lib;
+package org.eclipse.jgit.storage.file;
 
 // Hack to obtain visibility to package level methods only.
 // These aren't yet part of the public JGit API.
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitFlags.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitFlags.java
index 5ca7e41..992c616 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitFlags.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitFlags.java
@@ -19,7 +19,8 @@
 import com.google.inject.Singleton;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
-import org.eclipse.jgit.lib.FileBasedConfig;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
 
 import java.io.IOException;
 
@@ -40,8 +41,8 @@
 
   @Inject
   InitFlags(final SitePaths site) throws IOException, ConfigInvalidException {
-    cfg = new FileBasedConfig(site.gerrit_config);
-    sec = new FileBasedConfig(site.secure_config);
+    cfg = new FileBasedConfig(site.gerrit_config, FS.DETECTED);
+    sec = new FileBasedConfig(site.secure_config, FS.DETECTED);
 
     cfg.load();
     sec.load();
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitUtil.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitUtil.java
index 17f0146..074d965 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitUtil.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitUtil.java
@@ -17,15 +17,16 @@
 import com.google.gerrit.pgm.util.Die;
 
 import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.FileBasedConfig;
-import org.eclipse.jgit.lib.LockFile;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.storage.file.LockFile;
+import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.SystemReader;
 
-import java.io.OutputStream;
 import java.io.File;
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.net.InetAddress;
 import java.net.URI;
 import java.net.URISyntaxException;
@@ -48,7 +49,7 @@
   static void saveSecure(final FileBasedConfig sec) throws IOException {
     final byte[] out = Constants.encode(sec.toText());
     final File path = sec.getFile();
-    final LockFile lf = new LockFile(path);
+    final LockFile lf = new LockFile(path, FS.DETECTED);
     if (!lf.lock()) {
       throw new IOException("Cannot lock " + path);
     }
@@ -169,7 +170,7 @@
       throws FileNotFoundException, IOException {
     try {
       dst.getParentFile().mkdirs();
-      LockFile lf = new LockFile(dst);
+      LockFile lf = new LockFile(dst, FS.DETECTED);
       if (!lf.lock()) {
         throw new IOException("Cannot lock " + dst);
       }
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/UpgradeFrom2_0_x.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/UpgradeFrom2_0_x.java
index fad5878..9f62fc5 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/UpgradeFrom2_0_x.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/UpgradeFrom2_0_x.java
@@ -26,7 +26,7 @@
 import com.google.inject.Singleton;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
-import org.eclipse.jgit.lib.FileBasedConfig;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
 
 import java.io.File;
 import java.io.FileInputStream;
diff --git a/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/InitTestCase.java b/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/InitTestCase.java
index 2964f50..4d7370b 100644
--- a/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/InitTestCase.java
+++ b/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/InitTestCase.java
@@ -21,6 +21,6 @@
 
 public abstract class InitTestCase extends LocalDiskRepositoryTestCase {
   protected File newSitePath() throws IOException {
-    return new File(createWorkRepository().getWorkDir(), "test_site");
+    return new File(createWorkRepository().getWorkTree(), "test_site");
   }
 }
diff --git a/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/UpgradeFrom2_0_xTest.java b/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/UpgradeFrom2_0_xTest.java
index 72b02d5..00185581 100644
--- a/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/UpgradeFrom2_0_xTest.java
+++ b/gerrit-pgm/src/test/java/com/google/gerrit/pgm/init/UpgradeFrom2_0_xTest.java
@@ -24,7 +24,8 @@
 import com.google.gerrit.server.config.SitePaths;
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
-import org.eclipse.jgit.lib.FileBasedConfig;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.IO;
 
 import java.io.File;
@@ -50,7 +51,9 @@
       }
     }
 
-    FileBasedConfig old = new FileBasedConfig(new File(p, "gerrit.config"));
+    FileBasedConfig old =
+        new FileBasedConfig(new File(p, "gerrit.config"), FS.DETECTED);
+
     old.setString("ldap", null, "username", "ldap.user");
     old.setString("ldap", null, "password", "ldap.s3kr3t");
 
@@ -84,8 +87,8 @@
           new String(IO.readFully(new File(site.etc_dir, n)), "UTF-8"));
     }
 
-    FileBasedConfig cfg = new FileBasedConfig(site.gerrit_config);
-    FileBasedConfig sec = new FileBasedConfig(site.secure_config);
+    FileBasedConfig cfg = new FileBasedConfig(site.gerrit_config, FS.DETECTED);
+    FileBasedConfig sec = new FileBasedConfig(site.secure_config, FS.DETECTED);
     cfg.load();
     sec.load();
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
index fa2aaad..b70682c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -46,6 +46,7 @@
 import com.google.gerrit.server.git.PushReplication;
 import com.google.gerrit.server.git.ReloadSubmitQueueOp;
 import com.google.gerrit.server.git.ReplicationQueue;
+import com.google.gerrit.server.git.TransferConfig;
 import com.google.gerrit.server.git.WorkQueue;
 import com.google.gerrit.server.mail.EmailSender;
 import com.google.gerrit.server.mail.FromAddressGenerator;
@@ -123,6 +124,7 @@
     bind(WorkQueue.class);
     bind(ToolsCatalog.class);
     bind(EventFactory.class);
+    bind(TransferConfig.class);
 
     bind(ReplicationQueue.class).to(PushReplication.class).in(SINGLETON);
     factory(PushAllProjectsOp.Factory.class);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigProvider.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigProvider.java
index 6592ac7..92a2614 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigProvider.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritServerConfigProvider.java
@@ -20,7 +20,8 @@
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Config;
-import org.eclipse.jgit.lib.FileBasedConfig;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
+import org.eclipse.jgit.util.FS;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -40,7 +41,7 @@
 
   @Override
   public Config get() {
-    FileBasedConfig cfg = new FileBasedConfig(site.gerrit_config);
+    FileBasedConfig cfg = new FileBasedConfig(site.gerrit_config, FS.DETECTED);
 
     if (!cfg.getFile().exists()) {
       log.info("No " + site.gerrit_config.getAbsolutePath()
@@ -57,7 +58,7 @@
     }
 
     if (site.secure_config.exists()) {
-      cfg = new FileBasedConfig(cfg, site.secure_config);
+      cfg = new FileBasedConfig(cfg, site.secure_config, FS.DETECTED);
       try {
         cfg.load();
       } catch (IOException e) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
index e8df230..b8cfb71 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/LocalDiskRepositoryManager.java
@@ -23,12 +23,12 @@
 import org.eclipse.jgit.errors.RepositoryNotFoundException;
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.Constants;
-import org.eclipse.jgit.lib.LockFile;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.RepositoryCache;
-import org.eclipse.jgit.lib.WindowCache;
-import org.eclipse.jgit.lib.WindowCacheConfig;
 import org.eclipse.jgit.lib.RepositoryCache.FileKey;
+import org.eclipse.jgit.storage.file.LockFile;
+import org.eclipse.jgit.storage.file.WindowCache;
+import org.eclipse.jgit.storage.file.WindowCacheConfig;
 import org.eclipse.jgit.util.FS;
 import org.eclipse.jgit.util.IO;
 import org.eclipse.jgit.util.RawParseUtils;
@@ -164,7 +164,7 @@
       final LockFile f;
 
       e = openRepository(name);
-      f = new LockFile(new File(e.getDirectory(), "description"));
+      f = new LockFile(new File(e.getDirectory(), "description"), FS.DETECTED);
       if (f.lock()) {
         String d = description;
         if (d != null) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
index 66e8d61..2898369 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeOp.java
@@ -59,6 +59,7 @@
 import org.eclipse.jgit.lib.Commit;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
 import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.Ref;
 import org.eclipse.jgit.lib.RefUpdate;
@@ -76,6 +77,7 @@
 import org.slf4j.LoggerFactory;
 
 import java.io.IOException;
+import java.io.UnsupportedEncodingException;
 import java.sql.Timestamp;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -267,7 +269,7 @@
         branchTip = null;
       }
 
-      for (final Ref r : rw.getRepository().getAllRefs().values()) {
+      for (final Ref r : db.getAllRefs().values()) {
         if (r.getName().startsWith(Constants.R_HEADS)
             || r.getName().startsWith(Constants.R_TAGS)) {
           try {
@@ -554,8 +556,7 @@
     mergeCommit.setCommitter(myIdent);
     mergeCommit.setMessage(msgbuf.toString());
 
-    final ObjectId id = m.getObjectWriter().writeCommit(mergeCommit);
-    mergeTip = (CodeReviewCommit) rw.parseCommit(id);
+    mergeTip = (CodeReviewCommit) rw.parseCommit(commit(m, mergeCommit));
   }
 
   private void markCleanMerges() throws MergeException {
@@ -796,7 +797,7 @@
     mergeCommit.setCommitter(toCommitterIdent(submitAudit));
     mergeCommit.setMessage(msgbuf.toString());
 
-    final ObjectId id = m.getObjectWriter().writeCommit(mergeCommit);
+    final ObjectId id = commit(m, mergeCommit);
     final CodeReviewCommit newCommit = (CodeReviewCommit) rw.parseCommit(id);
     newCommit.copyFrom(n);
     newCommit.statusCode = CommitMergeStatus.CLEAN_PICK;
@@ -806,6 +807,18 @@
     setRefLogIdent(submitAudit);
   }
 
+  private ObjectId commit(final Merger m, final Commit mergeCommit)
+      throws IOException, UnsupportedEncodingException {
+    ObjectInserter oi = m.getObjectInserter();
+    try {
+      ObjectId id = oi.insert(Constants.OBJ_COMMIT, oi.format(mergeCommit));
+      oi.flush();
+      return id;
+    } finally {
+      oi.release();
+    }
+  }
+
   private boolean contains(List<FooterLine> footers, FooterKey key, String val) {
     for (final FooterLine line : footers) {
       if (line.matches(key) && val.equals(line.getValue())) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java
index 76b8bf0..047740b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/PushReplication.java
@@ -37,7 +37,7 @@
 
 import org.eclipse.jgit.errors.ConfigInvalidException;
 import org.eclipse.jgit.lib.Config;
-import org.eclipse.jgit.lib.FileBasedConfig;
+import org.eclipse.jgit.storage.file.FileBasedConfig;
 import org.eclipse.jgit.transport.OpenSshConfig;
 import org.eclipse.jgit.transport.RefSpec;
 import org.eclipse.jgit.transport.RemoteConfig;
@@ -129,7 +129,8 @@
 
   private List<ReplicationConfig> allConfigs(final SitePaths site)
       throws ConfigInvalidException, IOException {
-    final FileBasedConfig cfg = new FileBasedConfig(site.replication_config);
+    final FileBasedConfig cfg =
+        new FileBasedConfig(site.replication_config, FS.DETECTED);
 
     if (!cfg.getFile().exists()) {
       log.warn("No " + cfg.getFile() + "; not replicating");
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/TransferConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/TransferConfig.java
similarity index 78%
rename from gerrit-sshd/src/main/java/com/google/gerrit/sshd/TransferConfig.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/git/TransferConfig.java
index c976e7f..de4130d 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/TransferConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/TransferConfig.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.sshd;
+package com.google.gerrit.server.git;
 
 import com.google.gerrit.server.config.ConfigUtil;
 import com.google.gerrit.server.config.GerritServerConfig;
@@ -20,21 +20,32 @@
 import com.google.inject.Singleton;
 
 import org.eclipse.jgit.lib.Config;
+import org.eclipse.jgit.storage.pack.PackConfig;
 
 import java.util.concurrent.TimeUnit;
 
 @Singleton
 public class TransferConfig {
   private final int timeout;
+  private final PackConfig packConfig;
 
   @Inject
   TransferConfig(@GerritServerConfig final Config cfg) {
     timeout = (int) ConfigUtil.getTimeUnit(cfg, "transfer", null, "timeout", //
         0, TimeUnit.SECONDS);
+
+    packConfig = new PackConfig();
+    packConfig.setDeltaCompress(false);
+    packConfig.setThreads(1);
+    packConfig.fromConfig(cfg);
   }
 
   /** @return configured timeout, in seconds. 0 if the timeout is infinite. */
   public int getTimeout() {
     return timeout;
   }
+
+  public PackConfig getPackConfig() {
+    return packConfig;
+  }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchFile.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchFile.java
index 6c751dc..ebaa175 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchFile.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchFile.java
@@ -23,7 +23,6 @@
 import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.ObjectLoader;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.revwalk.RevCommit;
 import org.eclipse.jgit.revwalk.RevTree;
@@ -105,11 +104,6 @@
     if (tw.getFileMode(0).getObjectType() != Constants.OBJ_BLOB) {
       return Text.EMPTY;
     }
-    final ObjectId id = tw.getObjectId(0);
-    final ObjectLoader ldr = repo.openObject(id);
-    if (ldr == null) {
-      throw new MissingObjectException(id, Constants.TYPE_BLOB);
-    }
-    return new Text(ldr.getCachedBytes());
+    return new Text(repo.open(tw.getObjectId(0), Constants.OBJ_BLOB));
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListCacheImpl.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListCacheImpl.java
index f55763f..eb62fe1 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListCacheImpl.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListCacheImpl.java
@@ -87,13 +87,14 @@
 import org.eclipse.jgit.diff.RawTextIgnoreWhitespaceChange;
 import org.eclipse.jgit.diff.RenameDetector;
 import org.eclipse.jgit.diff.ReplaceEdit;
+import org.eclipse.jgit.errors.MissingObjectException;
 import org.eclipse.jgit.lib.AnyObjectId;
 import org.eclipse.jgit.lib.Config;
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.lib.ObjectId;
+import org.eclipse.jgit.lib.ObjectInserter;
 import org.eclipse.jgit.lib.ObjectLoader;
-import org.eclipse.jgit.lib.ObjectWriter;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.patch.FileHeader;
 import org.eclipse.jgit.patch.FileHeader.PatchType;
@@ -271,8 +272,8 @@
         if (e.getType() == Edit.Type.REPLACE) {
           if (aContent == null) {
             edits = new ArrayList<Edit>(edits);
-            aContent = read(repo, fileHeader.getOldName(), aTree);
-            bContent = read(repo, fileHeader.getNewName(), bTree);
+            aContent = read(repo, fileHeader.getOldPath(), aTree);
+            bContent = read(repo, fileHeader.getNewPath(), bTree);
             combineLineEdits(edits, aContent, bContent);
             i = -1; // restart the entire scan after combining lines.
             continue;
@@ -535,8 +536,10 @@
       if (tw == null || tw.getFileMode(0).getObjectType() != Constants.OBJ_BLOB) {
         return Text.EMPTY;
       }
-      ObjectLoader ldr = repo.openObject(tw.getObjectId(0));
-      if (ldr == null) {
+      ObjectLoader ldr;
+      try {
+        ldr = repo.open(tw.getObjectId(0), Constants.OBJ_BLOB);
+      } catch (MissingObjectException notFound) {
         return Text.EMPTY;
       }
       return new Text(ldr.getCachedBytes());
@@ -560,7 +563,14 @@
     }
 
     private static ObjectId emptyTree(final Repository repo) throws IOException {
-      return new ObjectWriter(repo).writeCanonicalTree(new byte[0]);
+      ObjectInserter oi = repo.newObjectInserter();
+      try {
+        ObjectId id = oi.insert(Constants.OBJ_TREE, new byte[] {});
+        oi.flush();
+        return id;
+      } finally {
+        oi.release();
+      }
     }
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListEntry.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListEntry.java
index 50d6120c..c4484fc 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListEntry.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/PatchListEntry.java
@@ -67,19 +67,19 @@
     switch (changeType) {
       case DELETED:
         oldName = null;
-        newName = hdr.getOldName();
+        newName = hdr.getOldPath();
         break;
 
       case ADDED:
       case MODIFIED:
         oldName = null;
-        newName = hdr.getNewName();
+        newName = hdr.getNewPath();
         break;
 
       case COPIED:
       case RENAMED:
-        oldName = hdr.getOldName();
-        newName = hdr.getNewName();
+        oldName = hdr.getOldPath();
+        newName = hdr.getNewPath();
         break;
 
       default:
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/patch/Text.java b/gerrit-server/src/main/java/com/google/gerrit/server/patch/Text.java
index e5b2411..b0fa947 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/patch/Text.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/patch/Text.java
@@ -15,11 +15,17 @@
 package com.google.gerrit.server.patch;
 
 import org.eclipse.jgit.diff.RawText;
+import org.eclipse.jgit.errors.LargeObjectException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.ObjectLoader;
+import org.eclipse.jgit.util.IO;
 import org.eclipse.jgit.util.RawParseUtils;
 import org.mozilla.universalchardet.UniversalDetector;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.IOException;
+import java.io.InputStream;
 import java.nio.charset.Charset;
 import java.nio.charset.IllegalCharsetNameException;
 import java.nio.charset.UnsupportedCharsetException;
@@ -27,6 +33,7 @@
 public class Text extends RawText {
   private static final Logger log = LoggerFactory.getLogger(Text.class);
   private static final Charset ISO_8859_1 = Charset.forName("ISO-8859-1");
+  private static final int bigFileThreshold = 10 * 1024 * 1024;
 
   public static final byte[] NO_BYTES = {};
   public static final Text EMPTY = new Text(NO_BYTES);
@@ -35,6 +42,36 @@
     return new String(content, charset(content, encoding));
   }
 
+  public static byte[] asByteArray(ObjectLoader ldr)
+      throws MissingObjectException, LargeObjectException, IOException {
+    if (!ldr.isLarge()) {
+      return ldr.getCachedBytes();
+    }
+
+    long sz = ldr.getSize();
+    if (sz > bigFileThreshold || sz > Integer.MAX_VALUE)
+      throw new LargeObjectException();
+
+    byte[] buf;
+    try {
+      buf = new byte[(int) sz];
+    } catch (OutOfMemoryError noMemory) {
+      LargeObjectException e;
+
+      e = new LargeObjectException();
+      e.initCause(noMemory);
+      throw e;
+    }
+
+    InputStream in = ldr.openStream();
+    try {
+      IO.readFully(in, buf, 0, buf.length);
+    } finally {
+      in.close();
+    }
+    return buf;
+  }
+
   private static Charset charset(byte[] content, String encoding) {
     if (encoding == null) {
       UniversalDetector d = new UniversalDetector(null);
@@ -64,6 +101,11 @@
     super(r);
   }
 
+  public Text(ObjectLoader ldr) throws MissingObjectException,
+      LargeObjectException, IOException {
+    this(asByteArray(ldr));
+  }
+
   public byte[] getContent() {
     return content;
   }
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/tools/hooks/CommitMsgHookTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/tools/hooks/CommitMsgHookTest.java
index 4738802..548398f 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/tools/hooks/CommitMsgHookTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/tools/hooks/CommitMsgHookTest.java
@@ -23,7 +23,7 @@
 import org.eclipse.jgit.lib.Constants;
 import org.eclipse.jgit.lib.FileMode;
 import org.eclipse.jgit.lib.ObjectId;
-import org.eclipse.jgit.lib.ObjectWriter;
+import org.eclipse.jgit.lib.ObjectInserter;
 import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.lib.RefUpdate;
 
@@ -144,7 +144,7 @@
         "Change-Id: I7fc3876fee63c766a2063df97fbe04a2dddd8d7c\n",//
         call("a\n"));
 
-    final DirCacheBuilder builder = DirCache.lock(repository).builder();
+    final DirCacheBuilder builder = repository.lockDirCache().builder();
     builder.add(file("A"));
     assertTrue(builder.commit());
 
@@ -386,35 +386,41 @@
   }
 
   private DirCacheEntry file(final String name) throws IOException {
-    final DirCacheEntry e = new DirCacheEntry(name);
-    e.setFileMode(FileMode.REGULAR_FILE);
-    e.setObjectId(writer().writeBlob(Constants.encode(name)));
-    return e;
-  }
-
-  private void setHEAD() throws Exception {
-    final ObjectWriter ow = writer();
-    final Commit commit = new Commit(repository);
-    commit.setTreeId(DirCache.newInCore().writeTree(ow));
-    commit.setAuthor(author);
-    commit.setCommitter(committer);
-    commit.setMessage("test\n");
-    final ObjectId commitId = ow.writeCommit(commit);
-
-    final RefUpdate ref = repository.updateRef(Constants.HEAD);
-    ref.setNewObjectId(commitId);
-    switch (ref.forceUpdate()) {
-      case NEW:
-      case FAST_FORWARD:
-      case FORCED:
-      case NO_CHANGE:
-        break;
-      default:
-        fail(Constants.HEAD + " did not change: " + ref.getResult());
+    final ObjectInserter oi = repository.newObjectInserter();
+    try {
+      final DirCacheEntry e = new DirCacheEntry(name);
+      e.setFileMode(FileMode.REGULAR_FILE);
+      e.setObjectId(oi.insert(Constants.OBJ_BLOB, Constants.encode(name)));
+      oi.flush();
+      return e;
+    } finally {
+      oi.release();
     }
   }
 
-  private ObjectWriter writer() {
-    return new ObjectWriter(repository);
+  private void setHEAD() throws Exception {
+    final ObjectInserter oi = repository.newObjectInserter();
+    try {
+      final Commit commit = new Commit(repository);
+      commit.setTreeId(DirCache.newInCore().writeTree(oi));
+      commit.setAuthor(author);
+      commit.setCommitter(committer);
+      commit.setMessage("test\n");
+      ObjectId commitId = oi.insert(Constants.OBJ_COMMIT, oi.format(commit));
+
+      final RefUpdate ref = repository.updateRef(Constants.HEAD);
+      ref.setNewObjectId(commitId);
+      switch (ref.forceUpdate()) {
+        case NEW:
+        case FAST_FORWARD:
+        case FORCED:
+        case NO_CHANGE:
+          break;
+        default:
+          fail(Constants.HEAD + " did not change: " + ref.getResult());
+      }
+    } finally {
+      oi.release();
+    }
   }
 }
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
index 40d271b..c9e9b72 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/SshModule.java
@@ -26,6 +26,7 @@
 import com.google.gerrit.server.RemotePeer;
 import com.google.gerrit.server.config.FactoryModule;
 import com.google.gerrit.server.config.GerritRequestModule;
+import com.google.gerrit.server.git.TransferConfig;
 import com.google.gerrit.server.git.WorkQueue;
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.server.ssh.SshInfo;
@@ -77,7 +78,6 @@
 
     bind(PublickeyAuthenticator.class).to(DatabasePubKeyAuth.class);
     bind(KeyPairProvider.class).toProvider(HostKeyProvider.class).in(SINGLETON);
-    bind(TransferConfig.class);
 
     install(new DefaultCommandModule());
 
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminShowCaches.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminShowCaches.java
index a78ced5..c27ad0d 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminShowCaches.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/AdminShowCaches.java
@@ -21,7 +21,7 @@
 import net.sf.ehcache.config.CacheConfiguration;
 
 import org.apache.sshd.server.Environment;
-import org.eclipse.jgit.lib.WindowCacheStatAccessor;
+import org.eclipse.jgit.storage.file.WindowCacheStatAccessor;
 
 import java.io.PrintWriter;
 
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
index eb5d1da..b601f42 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Receive.java
@@ -17,8 +17,8 @@
 import com.google.gerrit.reviewdb.Account;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.git.ReceiveCommits;
+import com.google.gerrit.server.git.TransferConfig;
 import com.google.gerrit.sshd.AbstractGitCommand;
-import com.google.gerrit.sshd.TransferConfig;
 import com.google.inject.Inject;
 
 import org.eclipse.jgit.transport.ReceivePack;
diff --git a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Upload.java b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Upload.java
index eca797d..c3be7c7 100644
--- a/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Upload.java
+++ b/gerrit-sshd/src/main/java/com/google/gerrit/sshd/commands/Upload.java
@@ -15,9 +15,9 @@
 package com.google.gerrit.sshd.commands;
 
 import com.google.gerrit.reviewdb.ReviewDb;
+import com.google.gerrit.server.git.TransferConfig;
 import com.google.gerrit.server.git.VisibleRefFilter;
 import com.google.gerrit.sshd.AbstractGitCommand;
-import com.google.gerrit.sshd.TransferConfig;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
 
@@ -40,6 +40,7 @@
     if (!projectControl.allRefsAreVisible()) {
       up.setRefFilter(new VisibleRefFilter(repo, projectControl, db.get()));
     }
+    up.setPackConfig(config.getPackConfig());
     up.setTimeout(config.getTimeout());
     try {
       up.upload(in, out, err);
diff --git a/pom.xml b/pom.xml
index 8eb8b4f..ee4dd65 100644
--- a/pom.xml
+++ b/pom.xml
@@ -46,7 +46,7 @@
   </issueManagement>
 
   <properties>
-    <jgitVersion>0.8.4.88-ge64cb03</jgitVersion>
+    <jgitVersion>0.8.4.240-g8e9cc82</jgitVersion>
     <gwtormVersion>1.1.4</gwtormVersion>
     <gwtjsonrpcVersion>1.2.2</gwtjsonrpcVersion>
     <gwtexpuiVersion>1.2.1</gwtexpuiVersion>