[
Date Prev][
Date Next][
Thread Prev][
Thread Next][
Date Index][
Thread Index]
[
List Home]
Re: [jgit-dev] Implementing shallow clones
|
Ok, that actually ended up being pretty easy. Here's a new version of
the patch which I think does everything in a fairly non-hairy way.
Please let me know what you think.
--Matt
P.S. I tried to submit this as a gerrit change, but ran into issues
uploading. I followed all the instructions on the website to register
an account and all that, but every time I try to contact the server I
get "ssh_exchange_identification: Connection closed by remote host".
Is there something else I need to do in order for that to work?
On Tue, Aug 10, 2010 at 9:08 AM, Shawn Pearce <spearce@xxxxxxxxxxx> wrote:
> On Tue, Aug 3, 2010 at 2:18 PM, Matt Fischer <mattfischer84@xxxxxxxxx> wrote:
>> The most efficient way to do this (and what C git does) is the following:
>>
>> 1. Set up a queue (FIFORevQueue in jgit parlance), and seed it with
>> all the root commits. Mark them as depth 0.
>> 2. Pop a commit from the front of the queue, and examine its depth.
>> 3. Set all parents of this commit to depth n + 1, unless their depth
>> is already less than this.
>> 4. Add any parents whose depth is less than the cutoff to the back of
>> the queue.
>> 5. Produce the popped commit, and repeat from 2 until the queue is empty.
>>
>> This works because it's basically a breadth-first descent into the
>> graph. If you have a commit that can be arrived at by two different
>> routes, you'll always get there by the shortest route first, because
>> the queue is FIFO.
>
> Oh, great idea. I knew we had a reason for FIFORevQueue. :-)
> (IIRC right now its unused.)
>
>> PendingGenerator almost does this, but it's built around a
>> DateRevQueue, so it's not guaranteed to get the ordering right. It
>> kind of feels like the right way to do this would just be to
>> completely forgo use of the PendingGenerator, and have DepthGenerator
>> start directly from the root commits and spin out its own tree.
>
> I agree.
>
>> That's kind of an invasive change to StartGenerator, though--would
>> something like that be ok with you, or is there some other way to
>> integrate this algorithm into the existing structure?
>
> Yes, its fine. But IIRC it shouldn't be that bad to insert into
> StartGenerator. Most of the pipeline doesn't care that its a
> PendingGenerator or some other type of Generator... just that a
> Generator exists for it to wrap its stage around. So you should be
> able to conditionally create your new DepthGenerator or the
> PendingGenerator based on the type of walk being done.
>
> --
> Shawn.
>
From ed5f501f9c8d1fe90ab2ba44fac5fa67ed0035a4 Mon Sep 17 00:00:00 2001
From: Matt Fischer <matt.fischer@xxxxxxxxxx>
Date: Mon, 26 Jul 2010 22:39:37 -0500
Subject: [PATCH] Implemented shallow clones
This implements the server side of shallow clones only (i.e. git-upload-pack),
not the client side.
---
.../org/eclipse/jgit/revwalk/DepthGenerator.java | 148 +++++++++++++
.../src/org/eclipse/jgit/revwalk/DepthWalk.java | 221 ++++++++++++++++++++
.../org/eclipse/jgit/revwalk/StartGenerator.java | 21 ++-
.../org/eclipse/jgit/storage/pack/PackWriter.java | 29 +++-
.../src/org/eclipse/jgit/transport/UploadPack.java | 82 +++++++-
5 files changed, 489 insertions(+), 12 deletions(-)
create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthGenerator.java
create mode 100644 org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthWalk.java
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthGenerator.java
new file mode 100644
index 0000000..d37194b
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthGenerator.java
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2010, Garmin International
+ * Copyright (C) 2010, Matt Fischer <matt.fischer@xxxxxxxxxx>
+ * 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.revwalk;
+
+import java.io.IOException;
+
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+
+/**
+ * Only produce commits which are below a specified depth.
+ */
+public class DepthGenerator extends Generator {
+ private final FIFORevQueue pending;
+
+ private final int outputType;
+ private final int depth;
+ private final DepthWalk.CompareMode compareMode;
+ private final RevWalk walk;
+
+ /**
+ * @param w
+ * @param s Parent generator
+ * @param depth Maximum depth of commits.
+ * @param compareMode Comparison mode
+ * @throws MissingObjectException
+ * @throws IncorrectObjectTypeException
+ * @throws IOException
+ */
+ public DepthGenerator(RevWalk w, Generator s, int depth, DepthWalk.CompareMode compareMode) throws MissingObjectException,
+ IncorrectObjectTypeException, IOException {
+ pending = new FIFORevQueue();
+ outputType = s.outputType();
+ walk = w;
+ this.depth = depth;
+ this.compareMode = compareMode;
+
+ s.shareFreeList(pending);
+
+ // Begin by sucking out all of the source's commits, and
+ // adding them to the pending queue
+ for (;;) {
+ final RevCommit c = s.next();
+ if (c == null)
+ break;
+ pending.add(c);
+ }
+ }
+
+ @Override
+ int outputType() {
+ return outputType;
+ }
+
+ @Override
+ void shareFreeList(final BlockRevQueue q) {
+ q.shareFreeList(pending);
+ }
+
+ @Override
+ RevCommit next() throws MissingObjectException,
+ IncorrectObjectTypeException, IOException {
+ for (;;) {
+ final RevCommit c = pending.next();
+ if (c == null)
+ return null;
+
+ c.parseHeaders(walk);
+
+ DepthWalk.Commit dc = (DepthWalk.Commit)c;
+ int newDepth = dc.getDepth() + 1;
+
+ for (final RevCommit p : c.parents) {
+ // Carry this child's depth up to the parent if it is
+ // less than the parent's current depth
+ DepthWalk.Commit dp = (DepthWalk.Commit)p;
+
+ if (dp.getDepth() > newDepth) {
+ dp.setDepth(newDepth);
+
+ // If the parent is not too deep, add it to the queue
+ // so that we can produce it later
+ if (newDepth <= depth)
+ pending.add(p);
+ }
+ }
+
+ // Determine whether or not we will produce this commit
+ boolean produce = true;
+ switch (compareMode) {
+ case EQUAL:
+ produce = (dc.getDepth() == depth);
+ break;
+
+ case LESS_THAN_EQUAL:
+ produce = (dc.getDepth() <= depth);
+ break;
+ }
+
+ if (produce)
+ return c;
+ else
+ continue;
+ }
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthWalk.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthWalk.java
new file mode 100644
index 0000000..3ce8c86
--- /dev/null
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/DepthWalk.java
@@ -0,0 +1,221 @@
+/*
+ * Copyright (C) 2010, Garmin International
+ * Copyright (C) 2010, Matt Fischer <matt.fischer@xxxxxxxxxx>
+ * 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.revwalk;
+
+import java.io.IOException;
+
+import org.eclipse.jgit.errors.IncorrectObjectTypeException;
+import org.eclipse.jgit.errors.MissingObjectException;
+import org.eclipse.jgit.lib.AnyObjectId;
+import org.eclipse.jgit.lib.ObjectReader;
+import org.eclipse.jgit.lib.Repository;
+
+/**
+ * Interface for revision walkers which perform depth filtering
+ */
+public interface DepthWalk {
+
+ /**
+ * Comparison modes for depth testing
+ */
+ public enum CompareMode {
+ /** Commits must be exactly equal to the specified depth */
+ EQUAL,
+
+ /** Commits must be less than or equal to the specified depth */
+ LESS_THAN_EQUAL
+ }
+
+ /**
+ * @return Depth to filter to
+ */
+ public int getDepth();
+
+ /**
+ * @return Comparison mode for this walker
+ */
+ public CompareMode getCompareMode();
+
+ /**
+ * Wrapper object for RevCommit which adds a depth tag.
+ */
+ public class Commit extends RevCommit {
+
+ private int depth;
+
+ /**
+ * @param id
+ */
+ protected Commit(AnyObjectId id) {
+ super(id);
+ depth = Integer.MAX_VALUE;
+ }
+
+ /**
+ * Set the depth of this commit
+ * @param depth Distance to nearest root in commit graph
+ */
+ public void setDepth(int depth) {
+ this.depth = depth;
+ }
+
+ /**
+ * @return The depth of this commit
+ */
+ public int getDepth() {
+ return depth;
+ }
+ }
+
+ /**
+ * Subclass of RevWalk which performs depth filtering
+ */
+ public class RevWalk extends org.eclipse.jgit.revwalk.RevWalk implements DepthWalk {
+ private final int depth;
+ private final CompareMode compareMode;
+
+ /**
+ * @param repo Repository to walk
+ * @param depth Maximum depth to return
+ * @param compareMode Comparison mode
+ */
+ public RevWalk(Repository repo, int depth, CompareMode compareMode) {
+ super(repo);
+
+ this.depth = depth;
+ this.compareMode = compareMode;
+ }
+
+ /** Mark a commit as a root (i.e., depth 0)
+ * @param c Commit to mark
+ * @throws MissingObjectException
+ * @throws IncorrectObjectTypeException
+ * @throws IOException
+ */
+ public void markStart(RevCommit c) throws MissingObjectException,
+ IncorrectObjectTypeException, IOException {
+ if (c instanceof Commit) {
+ ((Commit)c).setDepth(0);
+ }
+
+ super.markStart(c);
+ }
+
+ @Override
+ protected RevCommit createCommit(final AnyObjectId id) {
+ // Wrap this commit with a depth tag
+ return new Commit(id);
+ }
+
+ public int getDepth() {
+ return depth;
+ }
+
+ public CompareMode getCompareMode() {
+ return compareMode;
+ }
+ }
+
+ /**
+ * Subclass of ObjectWalk which performs depth filtering
+ */
+ public class ObjectWalk extends org.eclipse.jgit.revwalk.ObjectWalk implements DepthWalk {
+ private final int depth;
+ private final CompareMode compareMode;
+
+ /**
+ * @param repo Repository to walk
+ * @param depth Maximum depth to return
+ * @param compareMode Comparison mode
+ */
+ public ObjectWalk(Repository repo, int depth, CompareMode compareMode) {
+ super(repo);
+
+ this.depth = depth;
+ this.compareMode = compareMode;
+ }
+
+ /**
+ * @param or Object Reader
+ * @param depth Maximum depth to return
+ * @param compareMode Comparison mode
+ */
+ public ObjectWalk(ObjectReader or, int depth, CompareMode compareMode) {
+ super(or);
+
+ this.depth = depth;
+ this.compareMode = compareMode;
+ }
+
+ /** Mark a commit as a root (i.e., depth 0)
+ * @param c Commit to mark
+ * @throws MissingObjectException
+ * @throws IncorrectObjectTypeException
+ * @throws IOException
+ */
+ public void markStart(RevObject c) throws MissingObjectException,
+ IncorrectObjectTypeException, IOException {
+ if (c instanceof Commit) {
+ ((Commit)c).setDepth(0);
+ }
+
+ super.markStart(c);
+ }
+
+ @Override
+ protected RevCommit createCommit(final AnyObjectId id) {
+ // Wrap this commit with a depth tag
+ return new Commit(id);
+ }
+
+ public int getDepth() {
+ return depth;
+ }
+
+ public CompareMode getCompareMode() {
+ return compareMode;
+ }
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java
index 5e778a4..4c71282 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/revwalk/StartGenerator.java
@@ -54,6 +54,7 @@
import org.eclipse.jgit.revwalk.filter.AndRevFilter;
import org.eclipse.jgit.revwalk.filter.RevFilter;
import org.eclipse.jgit.treewalk.filter.TreeFilter;
+import org.eclipse.jgit.revwalk.DepthWalk;
/**
* Initial RevWalk generator that bootstraps a new walk.
@@ -130,14 +131,20 @@ RevCommit next() throws MissingObjectException,
}
walker.queue = q;
- g = new PendingGenerator(w, pending, rf, pendingOutputType);
- if (boundary) {
- // Because the boundary generator may produce uninteresting
- // commits we cannot allow the pending generator to dispose
- // of them early.
- //
- ((PendingGenerator) g).canDispose = false;
+ if (walker instanceof DepthWalk) {
+ DepthWalk dw = (DepthWalk) walker;
+ g = new DepthGenerator(w, pending, dw.getDepth(), dw.getCompareMode());
+ } else {
+ g = new PendingGenerator(w, pending, rf, pendingOutputType);
+
+ if (boundary) {
+ // Because the boundary generator may produce uninteresting
+ // commits we cannot allow the pending generator to dispose
+ // of them early.
+ //
+ ((PendingGenerator) g).canDispose = false;
+ }
}
if ((g.outputType() & NEEDS_REWRITE) != 0) {
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackWriter.java b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackWriter.java
index df5594c..6603dea 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackWriter.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/storage/pack/PackWriter.java
@@ -84,6 +84,7 @@
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.ThreadSafeProgressMonitor;
+import org.eclipse.jgit.revwalk.DepthWalk;
import org.eclipse.jgit.revwalk.ObjectWalk;
import org.eclipse.jgit.revwalk.RevFlag;
import org.eclipse.jgit.revwalk.RevObject;
@@ -376,7 +377,24 @@ public void preparePack(ProgressMonitor countingMonitor,
if (countingMonitor == null)
countingMonitor = NullProgressMonitor.INSTANCE;
ObjectWalk walker = setUpWalker(interestingObjects,
- uninterestingObjects);
+ uninterestingObjects, 0);
+ findObjectsToPack(countingMonitor, walker);
+ }
+
+ /**
+ * @param countingMonitor
+ * @param interestingObjects
+ * @param depth
+ * @throws IOException
+ */
+ public void preparePack(ProgressMonitor countingMonitor,
+ final Collection<? extends ObjectId> interestingObjects,
+ int depth)
+ throws IOException {
+ if (countingMonitor == null)
+ countingMonitor = NullProgressMonitor.INSTANCE;
+ ObjectWalk walker = setUpWalker(interestingObjects,
+ null, depth);
findObjectsToPack(countingMonitor, walker);
}
@@ -947,10 +965,15 @@ private void writeChecksum(PackOutputStream out) throws IOException {
private ObjectWalk setUpWalker(
final Collection<? extends ObjectId> interestingObjects,
- final Collection<? extends ObjectId> uninterestingObjects)
+ final Collection<? extends ObjectId> uninterestingObjects,
+ int depth)
throws MissingObjectException, IOException,
IncorrectObjectTypeException {
- final ObjectWalk walker = new ObjectWalk(reader);
+ final ObjectWalk walker;
+ if (depth > 0)
+ walker = new DepthWalk.ObjectWalk(reader, depth - 1, DepthWalk.CompareMode.LESS_THAN_EQUAL);
+ else
+ walker = new ObjectWalk(reader);
walker.setRetainBody(false);
walker.sort(RevSort.COMMIT_TIME_DESC);
if (thin)
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 16d56df..d459789 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -63,6 +63,7 @@
import org.eclipse.jgit.lib.ProgressMonitor;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.lib.Repository;
+import org.eclipse.jgit.revwalk.DepthWalk;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.revwalk.RevFlag;
import org.eclipse.jgit.revwalk.RevFlagSet;
@@ -97,6 +98,8 @@
static final String OPTION_NO_PROGRESS = BasePackFetchConnection.OPTION_NO_PROGRESS;
+ static final String OPTION_SHALLOW = BasePackFetchConnection.OPTION_SHALLOW;
+
/** Database we read the objects from. */
private final Repository db;
@@ -151,6 +154,12 @@
/** Objects on both sides, these don't have to be sent. */
private final List<RevObject> commonBase = new ArrayList<RevObject>();
+ /** Shallow commits that we will be sending. */
+ private final List<RevCommit> localShallowCommits = new ArrayList<RevCommit>();
+
+ /** Shallow commits the remote already has. */
+ private final List<RevCommit> remoteShallowCommits = new ArrayList<RevCommit>();
+
/** null if {@link #commonBase} should be examined again. */
private Boolean okToGiveUp;
@@ -170,6 +179,8 @@
private MultiAck multiAck = MultiAck.OFF;
+ private int depth = 0;
+
/**
* Create a new pack upload for an open repository.
*
@@ -347,8 +358,59 @@ else if (options.contains(OPTION_MULTI_ACK))
else
multiAck = MultiAck.OFF;
- if (negotiate())
+ if (depth != 0) {
+ processShallow();
+ }
+
+ if (negotiate()) {
sendPack();
+ }
+ }
+
+ private void processShallow() throws IOException {
+ DepthWalk.RevWalk depthWalk = new DepthWalk.RevWalk(db, depth - 1, DepthWalk.CompareMode.EQUAL);
+
+ // Find all the commits which will be shallow
+ for (RevCommit c : wantCommits) {
+ RevCommit commit = depthWalk.parseCommit(c);
+ depthWalk.markStart(commit);
+ }
+
+ RevObject o;
+
+ // Find all commits at the boundary, and mark them as shallow
+ while ((o = depthWalk.next()) != null) {
+ localShallowCommits.add((RevCommit)o);
+
+ boolean found = false;
+ for (RevCommit c : remoteShallowCommits) {
+ if (c.name() == o.name()) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ pckOut.writeString("shallow " + o.name());
+ }
+ }
+
+ // Unshallow any commits which we're expanding on
+ for (RevCommit remote : remoteShallowCommits) {
+ boolean found = false;
+ for(RevCommit local : localShallowCommits) {
+ if(remote.name() == local.name()) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ pckOut.writeString("unshallow " + remote.name());
+ }
+ }
+
+ pckOut.end();
}
/**
@@ -369,8 +431,10 @@ public void sendAdvertisedRefs(final RefAdvertiser adv) throws IOException {
adv.advertiseCapability(OPTION_SIDE_BAND_64K);
adv.advertiseCapability(OPTION_THIN_PACK);
adv.advertiseCapability(OPTION_NO_PROGRESS);
+ adv.advertiseCapability(OPTION_SHALLOW);
adv.setDerefTags(true);
refs = refFilter.filter(db.getAllRefs());
+
adv.send(refs);
adv.end();
}
@@ -389,6 +453,16 @@ private void recvWants() throws IOException {
if (line == PacketLineIn.END)
break;
+
+ if (line.startsWith("deepen ")) {
+ depth = Integer.parseInt(line.substring(7));
+ continue;
+ }
+ if (line.startsWith("shallow ")) {
+ final ObjectId id = ObjectId.fromString(line.substring(8));
+ remoteShallowCommits.add(walk.parseCommit(id));
+ continue;
+ }
if (!line.startsWith("want ") || line.length() < 45)
throw new PackProtocolException(MessageFormat.format(JGitText.get().expectedGot, "want", line));
@@ -588,7 +662,11 @@ private void sendPack() throws IOException {
try {
pw.setDeltaBaseAsOffset(options.contains(OPTION_OFS_DELTA));
pw.setThin(options.contains(OPTION_THIN_PACK));
- pw.preparePack(pm, wantAll, commonBase);
+ if(depth > 0) {
+ pw.preparePack(pm, wantAll, depth);
+ } else {
+ pw.preparePack(pm, wantAll, commonBase);
+ }
if (options.contains(OPTION_INCLUDE_TAG)) {
for (final Ref r : refs.values()) {
final RevObject o;
--
1.6.0.6