aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--org.eclipse.jgit.http.server/src/org/eclipse/jgit/http/server/UploadPackServlet.java2
-rw-r--r--org.eclipse.jgit.packaging/pom.xml5
-rw-r--r--org.eclipse.jgit.test/META-INF/MANIFEST.MF2
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/CloneCommandTest.java44
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java20
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/CGitIgnoreTest.java82
-rw-r--r--org.eclipse.jgit/META-INF/MANIFEST.MF1
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java9
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java37
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java64
10 files changed, 239 insertions, 27 deletions
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 d3437b7eb9..23a398f9db 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
@@ -208,6 +208,8 @@ class UploadPackServlet extends HttpServlet {
log(up.getRepository(), e.getCause());
consumeRequestBody(req);
out.close();
+ } finally {
+ up.close();
}
};
diff --git a/org.eclipse.jgit.packaging/pom.xml b/org.eclipse.jgit.packaging/pom.xml
index 1c581eec17..56946faeca 100644
--- a/org.eclipse.jgit.packaging/pom.xml
+++ b/org.eclipse.jgit.packaging/pom.xml
@@ -259,6 +259,11 @@
<ws>cocoa</ws>
<arch>x86_64</arch>
</environment>
+ <environment>
+ <os>macosx</os>
+ <ws>cocoa</ws>
+ <arch>aarch64</arch>
+ </environment>
</environments>
</configuration>
</plugin>
diff --git a/org.eclipse.jgit.test/META-INF/MANIFEST.MF b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
index 0ba71f982d..bb155eace0 100644
--- a/org.eclipse.jgit.test/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit.test/META-INF/MANIFEST.MF
@@ -86,4 +86,4 @@ Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
org.mockito.stubbing;version="[2.23.0,3.0.0)",
org.objenesis;version="[2.6.0,3.0.0)",
org.slf4j;version="[1.7.0,2.0.0)",
- org.tukaani.xz;version="[1.6.0,2.0)"
+ org.tukaani.xz
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 de25870bd0..c928d2ad22 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
@@ -22,6 +22,7 @@ import java.net.URISyntaxException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import java.util.stream.Stream;
import org.eclipse.jgit.api.ListBranchCommand.ListMode;
import org.eclipse.jgit.api.errors.GitAPIException;
@@ -115,6 +116,49 @@ public class CloneCommandTest extends RepositoryTestCase {
}
@Test
+ public void testCloneRepository_refLogForLocalRefs()
+ throws IOException, JGitInternalException, GitAPIException {
+ File directory = createTempDirectory("testCloneRepository");
+ CloneCommand command = Git.cloneRepository();
+ command.setDirectory(directory);
+ command.setURI(fileUri());
+ Git git2 = command.call();
+ Repository clonedRepo = git2.getRepository();
+ addRepoToClose(clonedRepo);
+
+ List<Ref> clonedRefs = clonedRepo.getRefDatabase().getRefs();
+ Stream<Ref> remoteRefs = clonedRefs.stream()
+ .filter(CloneCommandTest::isRemote);
+ Stream<Ref> localHeadsRefs = clonedRefs.stream()
+ .filter(CloneCommandTest::isLocalHead);
+
+ remoteRefs.forEach(ref -> assertFalse(
+ "Ref " + ref.getName()
+ + " is remote and should not have a reflog",
+ hasRefLog(clonedRepo, ref)));
+ localHeadsRefs.forEach(ref -> assertTrue(
+ "Ref " + ref.getName()
+ + " is local head and should have a reflog",
+ hasRefLog(clonedRepo, ref)));
+ }
+
+ private static boolean isRemote(Ref ref) {
+ return ref.getName().startsWith(Constants.R_REMOTES);
+ }
+
+ private static boolean isLocalHead(Ref ref) {
+ return !isRemote(ref) && ref.getName().startsWith(Constants.R_HEADS);
+ }
+
+ private static boolean hasRefLog(Repository repo, Ref ref) {
+ try {
+ return repo.getReflogReader(ref.getName()).getLastEntry() != null;
+ } catch (IOException ioe) {
+ throw new IllegalStateException(ioe);
+ }
+ }
+
+ @Test
public void testCloneRepositoryExplicitGitDir() throws IOException,
JGitInternalException, GitAPIException {
File directory = createTempDirectory("testCloneRepository");
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java
index 0884d72235..3ec454cfc3 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/FetchCommandTest.java
@@ -77,6 +77,26 @@ public class FetchCommandTest extends RepositoryTestCase {
}
@Test
+ public void testFetchHasRefLogForRemoteRef() throws Exception {
+ // create an initial commit SHA1 for the default branch
+ ObjectId defaultBranchSha1 = remoteGit.commit()
+ .setMessage("initial commit").call().getId();
+
+ git.fetch().setRemote("test")
+ .setRefSpecs("refs/heads/*:refs/remotes/origin/*").call();
+
+ List<Ref> allFetchedRefs = git.getRepository().getRefDatabase()
+ .getRefs();
+ assertEquals(allFetchedRefs.size(), 1);
+ Ref remoteRef = allFetchedRefs.get(0);
+
+ assertTrue(remoteRef.getName().startsWith(Constants.R_REMOTES));
+ assertEquals(defaultBranchSha1, remoteRef.getObjectId());
+ assertNotNull(git.getRepository().getReflogReader(remoteRef.getName())
+ .getLastEntry());
+ }
+
+ @Test
public void testForcedFetch() throws Exception {
remoteGit.commit().setMessage("commit").call();
remoteGit.commit().setMessage("commit2").call();
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/CGitIgnoreTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/CGitIgnoreTest.java
index ae3f05111f..083e6cd005 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/CGitIgnoreTest.java
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/ignore/CGitIgnoreTest.java
@@ -13,6 +13,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
@@ -20,6 +21,7 @@ import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
+import java.nio.file.Files;
import java.util.LinkedHashSet;
import java.util.Set;
@@ -354,4 +356,84 @@ public class CGitIgnoreTest extends RepositoryTestCase {
writeTrashFile("src/.gitignore", "*\n!*.java\n!*/");
assertSameAsCGit();
}
+
+ @Test
+ public void testMultipleEntriesIgnored() throws Exception {
+ createFiles("dir/a");
+ writeTrashFile(".gitignore", "!dir/a\ndir/a");
+ assertSameAsCGit();
+ }
+
+ @Test
+ public void testMultipleEntriesNotIgnored() throws Exception {
+ createFiles("dir/a");
+ writeTrashFile(".gitignore", "dir/a\n!dir/a");
+ assertSameAsCGit("dir/a");
+ }
+
+ @Test
+ public void testInfoExcludes() throws Exception {
+ createFiles("dir/a", "dir/b");
+ File gitDir = db.getDirectory();
+ File info = new File(gitDir, "info");
+ assertTrue(info.mkdirs());
+ File infoExclude = new File(info, "exclude");
+ Files.writeString(infoExclude.toPath(), "dir/a");
+ assertSameAsCGit("dir/b");
+ }
+
+ @Test
+ public void testInfoExcludesPrecedence() throws Exception {
+ createFiles("dir/a", "dir/b");
+ writeTrashFile(".gitignore", "!dir/a");
+ File gitDir = db.getDirectory();
+ File info = new File(gitDir, "info");
+ assertTrue(info.mkdirs());
+ File infoExclude = new File(info, "exclude");
+ Files.writeString(infoExclude.toPath(), "dir/a");
+ assertSameAsCGit("dir/a", "dir/b");
+ }
+
+ @Test
+ public void testCoreExcludes() throws Exception {
+ createFiles("dir/a", "dir/b");
+ writeTrashFile(".fake_git_ignore", "dir/a");
+ assertSameAsCGit("dir/b");
+ }
+
+ @Test
+ public void testInfoCoreExcludes() throws Exception {
+ createFiles("dir/a", "dir/b");
+ File gitDir = db.getDirectory();
+ File info = new File(gitDir, "info");
+ assertTrue(info.mkdirs());
+ File infoExclude = new File(info, "exclude");
+ Files.writeString(infoExclude.toPath(), "!a");
+ writeTrashFile(".fake_git_ignore", "dir/a");
+ assertSameAsCGit("dir/b");
+ }
+
+ @Test
+ public void testInfoCoreExcludesPrecedence() throws Exception {
+ createFiles("dir/a", "dir/b");
+ File gitDir = db.getDirectory();
+ File info = new File(gitDir, "info");
+ assertTrue(info.mkdirs());
+ File infoExclude = new File(info, "exclude");
+ Files.writeString(infoExclude.toPath(), "!dir/a");
+ writeTrashFile(".fake_git_ignore", "dir/a");
+ assertSameAsCGit("dir/a", "dir/b");
+ }
+
+ @Test
+ public void testInfoCoreExcludesPrecedence2() throws Exception {
+ createFiles("dir/a", "dir/b");
+ File gitDir = db.getDirectory();
+ File info = new File(gitDir, "info");
+ assertTrue(info.mkdirs());
+ File infoExclude = new File(info, "exclude");
+ Files.writeString(infoExclude.toPath(), "dir/a");
+ writeTrashFile(".fake_git_ignore", "!dir/a");
+ assertSameAsCGit("dir/b");
+ }
}
diff --git a/org.eclipse.jgit/META-INF/MANIFEST.MF b/org.eclipse.jgit/META-INF/MANIFEST.MF
index b919140989..d1e612593c 100644
--- a/org.eclipse.jgit/META-INF/MANIFEST.MF
+++ b/org.eclipse.jgit/META-INF/MANIFEST.MF
@@ -230,6 +230,7 @@ Export-Package: org.eclipse.jgit.annotations;version="6.3.0",
Bundle-RequiredExecutionEnvironment: JavaSE-11
Import-Package: com.googlecode.javaewah;version="[1.1.6,2.0.0)",
javax.crypto,
+ javax.management,
javax.net.ssl,
org.slf4j;version="[1.7.0,2.0.0)",
org.xml.sax,
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
index 87e5476036..7bface49d9 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java
@@ -214,8 +214,13 @@ class FetchProcess {
BatchRefUpdate batch = transport.local.getRefDatabase()
.newBatchUpdate()
- .setAllowNonFastForwards(true)
- .setRefLogMessage("fetch", true); //$NON-NLS-1$
+ .setAllowNonFastForwards(true);
+
+ // Generate reflog only when fetching updates and not at the first clone
+ if (initialBranch == null) {
+ batch.setRefLogMessage("fetch", true); //$NON-NLS-1$
+ }
+
try (RevWalk walk = new RevWalk(transport.local)) {
walk.setRetainBody(false);
if (monitor instanceof BatchingProgressMonitor) {
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 8b47d846a8..dcd806a3da 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/UploadPack.java
@@ -39,6 +39,7 @@ import static org.eclipse.jgit.transport.GitProtocolConstants.VERSION_2_REQUEST;
import static org.eclipse.jgit.util.RefMap.toRefMap;
import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;
@@ -105,7 +106,7 @@ import org.eclipse.jgit.util.io.TimeoutOutputStream;
/**
* Implements the server side of a fetch connection, transmitting objects.
*/
-public class UploadPack {
+public class UploadPack implements Closeable {
/** Policy the server uses to validate client requests */
public enum RequestPolicy {
/** Client may only ask for objects the server advertised a reference for. */
@@ -733,6 +734,17 @@ public class UploadPack {
&& clientRequestedV2;
}
+ @Override
+ public void close() {
+ if (timer != null) {
+ try {
+ timer.terminate();
+ } finally {
+ timer = null;
+ }
+ }
+ }
+
/**
* Execute the upload task on the socket.
*
@@ -780,6 +792,8 @@ public class UploadPack {
throw new UploadPackInternalServerErrorException(err);
}
throw err;
+ } finally {
+ close();
}
}
@@ -789,6 +803,10 @@ public class UploadPack {
* <p>
* If the client passed extra parameters (e.g., "version=2") through a side
* channel, the caller must call setExtraParameters first to supply them.
+ * Callers of this method should call {@link #close()} to terminate the
+ * internal interrupt timer thread. If the caller fails to terminate the
+ * thread, it will (eventually) terminate itself when the InterruptTimer
+ * instance is garbage collected.
*
* @param input
* raw input to read client commands from. Caller must ensure the
@@ -845,13 +863,6 @@ public class UploadPack {
} finally {
msgOut = NullOutputStream.INSTANCE;
walk.close();
- if (timer != null) {
- try {
- timer.terminate();
- } finally {
- timer = null;
- }
- }
}
}
@@ -1998,12 +2009,16 @@ public class UploadPack {
throws IOException {
ObjectReader reader = up.getRevWalk().getObjectReader();
+ Set<ObjectId> directlyVisibleObjects = refIdSet(visibleRefs);
+ List<ObjectId> nonTipWants = notAdvertisedWants.stream()
+ .filter(not(directlyVisibleObjects::contains))
+ .collect(Collectors.toList());
try (RevWalk walk = new RevWalk(reader)) {
walk.setRetainBody(false);
// Missing "wants" throw exception here
List<RevObject> wantsAsObjs = objectIdsToRevObjects(walk,
- notAdvertisedWants);
+ nonTipWants);
List<RevCommit> wantsAsCommits = wantsAsObjs.stream()
.filter(obj -> obj instanceof RevCommit)
.map(obj -> (RevCommit) obj)
@@ -2069,6 +2084,10 @@ public class UploadPack {
}
}
+ private static <T> Predicate<T> not(Predicate<T> t) {
+ return t.negate();
+ }
+
static Stream<Ref> importantRefsFirst(
Collection<Ref> visibleRefs) {
Predicate<Ref> startsWithRefsHeads = ref -> ref.getName()
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
index 427eac5b53..b108b0a959 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/treewalk/WorkingTreeIterator.java
@@ -1274,11 +1274,15 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
}
IgnoreNode load() throws IOException {
- IgnoreNode r = new IgnoreNode();
+ return load(null);
+ }
+
+ IgnoreNode load(IgnoreNode parent) throws IOException {
+ IgnoreNodeWithParent r = new IgnoreNodeWithParent(parent);
try (InputStream in = entry.openInputStream()) {
r.parse(name, in);
}
- return r.getRules().isEmpty() ? null : r;
+ return r.getRules().isEmpty() && parent == null ? null : r;
}
}
@@ -1292,29 +1296,41 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
}
@Override
- IgnoreNode load() throws IOException {
- IgnoreNode r;
- if (entry != null) {
- r = super.load();
- if (r == null)
- r = new IgnoreNode();
- } else {
- r = new IgnoreNode();
- }
-
+ IgnoreNode load(IgnoreNode parent) throws IOException {
+ IgnoreNode coreExclude = new IgnoreNodeWithParent(parent);
FS fs = repository.getFS();
Path path = repository.getConfig().getPath(
ConfigConstants.CONFIG_CORE_SECTION, null,
ConfigConstants.CONFIG_KEY_EXCLUDESFILE, fs, null, null);
if (path != null) {
- loadRulesFromFile(r, path.toFile());
+ loadRulesFromFile(coreExclude, path.toFile());
+ }
+ if (coreExclude.getRules().isEmpty()) {
+ coreExclude = parent;
}
+ IgnoreNode infoExclude = new IgnoreNodeWithParent(
+ coreExclude);
File exclude = fs.resolve(repository.getDirectory(),
Constants.INFO_EXCLUDE);
- loadRulesFromFile(r, exclude);
+ loadRulesFromFile(infoExclude, exclude);
+ if (infoExclude.getRules().isEmpty()) {
+ infoExclude = null;
+ }
- return r.getRules().isEmpty() ? null : r;
+ IgnoreNode parentNode = infoExclude != null ? infoExclude
+ : coreExclude;
+
+ IgnoreNode r;
+ if (entry != null) {
+ r = super.load(parentNode);
+ if (r == null) {
+ return null;
+ }
+ } else {
+ return parentNode;
+ }
+ return r.getRules().isEmpty() ? parentNode : r;
}
private static void loadRulesFromFile(IgnoreNode r, File exclude)
@@ -1327,6 +1343,24 @@ public abstract class WorkingTreeIterator extends AbstractTreeIterator {
}
}
+ private static class IgnoreNodeWithParent extends IgnoreNode {
+
+ private final IgnoreNode parent;
+
+ IgnoreNodeWithParent(IgnoreNode parent) {
+ this.parent = parent;
+ }
+
+ @Override
+ public Boolean checkIgnored(String path, boolean isDirectory) {
+ Boolean result = super.checkIgnored(path, isDirectory);
+ if (result == null && parent != null) {
+ return parent.checkIgnored(path, isDirectory);
+ }
+ return result;
+ }
+ }
+
/** Magic type indicating we know rules exist, but they aren't loaded. */
private static class PerDirectoryAttributesNode extends AttributesNode {
final Entry entry;