diff --git a/org.eclipse.jgit.http.apache/.settings/.api_filters b/org.eclipse.jgit.http.apache/.settings/.api_filters deleted file mode 100644 index d1a066418..000000000 --- a/org.eclipse.jgit.http.apache/.settings/.api_filters +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - 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 9fab24550..dfb5a8f44 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 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target index 909b3307e..dbfd694b2 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.6.target @@ -1,7 +1,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target index 8b064bc1c..be7719d88 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.7.target @@ -1,7 +1,7 @@ - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target index 6f57c9d6a..3de172b82 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.target @@ -1,7 +1,7 @@ - + @@ -33,6 +33,8 @@ + + @@ -66,14 +68,9 @@ - - - - - - + diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd index efcba7c2c..0ea2b99f3 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/jgit-4.8.tpd @@ -3,6 +3,6 @@ target "jgit-4.8" with source configurePhase include "projects/jetty-9.4.8.tpd" include "orbit/R20180606145124-Photon.tpd" -location "http://download.eclipse.org/releases/oxygen/" { +location "http://download.eclipse.org/releases/photon/" { org.eclipse.osgi lazy } diff --git a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20180606145124-Photon.tpd b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20180606145124-Photon.tpd index 808b9d694..ecec41d8c 100644 --- a/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20180606145124-Photon.tpd +++ b/org.eclipse.jgit.packaging/org.eclipse.jgit.target/orbit/R20180606145124-Photon.tpd @@ -12,6 +12,8 @@ location "http://download.eclipse.org/tools/orbit/downloads/drops/R2018060614512 org.apache.commons.logging.source [1.1.1.v201101211721,1.1.1.v201101211721] org.apache.httpcomponents.httpcore [4.4.6.v20170210-0925,4.4.6.v20170210-0925] org.apache.httpcomponents.httpcore.source [4.4.6.v20170210-0925,4.4.6.v20170210-0925] + org.apache.httpcomponents.httpclient [4.5.2.v20180410-1551,4.5.2.v20180410-1551] + org.apache.httpcomponents.httpclient.source [4.5.2.v20180410-1551,4.5.2.v20180410-1551] org.apache.log4j [1.2.15.v201012070815,1.2.15.v201012070815] org.apache.log4j.source [1.2.15.v201012070815,1.2.15.v201012070815] org.kohsuke.args4j [2.33.0.v20160323-2218,2.33.0.v20160323-2218] @@ -44,9 +46,3 @@ location "http://download.eclipse.org/tools/orbit/downloads/drops/R2018060614512 com.jcraft.jzlib [1.1.1.v201205102305,1.1.1.v201205102305] com.jcraft.jzlib.source [1.1.1.v201205102305,1.1.1.v201205102305] } - -location "http://download.eclipse.org/tools/orbit/downloads/drops/R20170919201930/repository/" { - // platform uses this outdated version of httpclient in Photon - org.apache.httpcomponents.httpclient [4.5.2.v20170210-0925,4.5.2.v20170210-0925] - org.apache.httpcomponents.httpclient.source [4.5.2.v20170210-0925,4.5.2.v20170210-0925] -} \ No newline at end of file diff --git a/org.eclipse.jgit.pgm/.settings/.api_filters b/org.eclipse.jgit.pgm/.settings/.api_filters deleted file mode 100644 index facef2df6..000000000 --- a/org.eclipse.jgit.pgm/.settings/.api_filters +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - 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 4c2c0e8d1..adc4d9848 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 @@ -49,7 +49,9 @@ import static org.junit.Assert.assertTrue; import java.io.File; +import java.util.ArrayList; import java.util.Collection; +import java.util.List; import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.RepositoryTestCase; @@ -61,6 +63,7 @@ import org.eclipse.jgit.lib.StoredConfig; import org.eclipse.jgit.revwalk.RevCommit; import org.eclipse.jgit.transport.FetchResult; +import org.eclipse.jgit.transport.RefSpec; import org.eclipse.jgit.transport.RemoteConfig; import org.eclipse.jgit.transport.TagOpt; import org.eclipse.jgit.transport.TrackingRefUpdate; @@ -125,6 +128,91 @@ public void testForcedFetch() throws Exception { res.getTrackingRefUpdate("refs/heads/master").getResult()); } + @Test + public void fetchAddsBranches() throws Exception { + final String branch1 = "b1"; + final String branch2 = "b2"; + final String remoteBranch1 = "test/" + branch1; + final String remoteBranch2 = "test/" + branch2; + remoteGit.commit().setMessage("commit").call(); + Ref branchRef1 = remoteGit.branchCreate().setName(branch1).call(); + remoteGit.commit().setMessage("commit").call(); + Ref branchRef2 = remoteGit.branchCreate().setName(branch2).call(); + + String spec = "refs/heads/*:refs/remotes/test/*"; + git.fetch().setRemote("test").setRefSpecs(spec).call(); + assertEquals(branchRef1.getObjectId(), db.resolve(remoteBranch1)); + assertEquals(branchRef2.getObjectId(), db.resolve(remoteBranch2)); + } + + @Test + public void fetchDoesntDeleteBranches() throws Exception { + final String branch1 = "b1"; + final String branch2 = "b2"; + final String remoteBranch1 = "test/" + branch1; + final String remoteBranch2 = "test/" + branch2; + remoteGit.commit().setMessage("commit").call(); + Ref branchRef1 = remoteGit.branchCreate().setName(branch1).call(); + remoteGit.commit().setMessage("commit").call(); + Ref branchRef2 = remoteGit.branchCreate().setName(branch2).call(); + + String spec = "refs/heads/*:refs/remotes/test/*"; + git.fetch().setRemote("test").setRefSpecs(spec).call(); + assertEquals(branchRef1.getObjectId(), db.resolve(remoteBranch1)); + assertEquals(branchRef2.getObjectId(), db.resolve(remoteBranch2)); + + remoteGit.branchDelete().setBranchNames(branch1).call(); + git.fetch().setRemote("test").setRefSpecs(spec).call(); + assertEquals(branchRef1.getObjectId(), db.resolve(remoteBranch1)); + assertEquals(branchRef2.getObjectId(), db.resolve(remoteBranch2)); + } + + @Test + public void fetchUpdatesBranches() throws Exception { + final String branch1 = "b1"; + final String branch2 = "b2"; + final String remoteBranch1 = "test/" + branch1; + final String remoteBranch2 = "test/" + branch2; + remoteGit.commit().setMessage("commit").call(); + Ref branchRef1 = remoteGit.branchCreate().setName(branch1).call(); + remoteGit.commit().setMessage("commit").call(); + Ref branchRef2 = remoteGit.branchCreate().setName(branch2).call(); + + String spec = "refs/heads/*:refs/remotes/test/*"; + git.fetch().setRemote("test").setRefSpecs(spec).call(); + assertEquals(branchRef1.getObjectId(), db.resolve(remoteBranch1)); + assertEquals(branchRef2.getObjectId(), db.resolve(remoteBranch2)); + + remoteGit.commit().setMessage("commit").call(); + branchRef2 = remoteGit.branchCreate().setName(branch2).setForce(true).call(); + git.fetch().setRemote("test").setRefSpecs(spec).call(); + assertEquals(branchRef1.getObjectId(), db.resolve(remoteBranch1)); + assertEquals(branchRef2.getObjectId(), db.resolve(remoteBranch2)); + } + + @Test + public void fetchPrunesBranches() throws Exception { + final String branch1 = "b1"; + final String branch2 = "b2"; + final String remoteBranch1 = "test/" + branch1; + final String remoteBranch2 = "test/" + branch2; + remoteGit.commit().setMessage("commit").call(); + Ref branchRef1 = remoteGit.branchCreate().setName(branch1).call(); + remoteGit.commit().setMessage("commit").call(); + Ref branchRef2 = remoteGit.branchCreate().setName(branch2).call(); + + String spec = "refs/heads/*:refs/remotes/test/*"; + git.fetch().setRemote("test").setRefSpecs(spec).call(); + assertEquals(branchRef1.getObjectId(), db.resolve(remoteBranch1)); + assertEquals(branchRef2.getObjectId(), db.resolve(remoteBranch2)); + + remoteGit.branchDelete().setBranchNames(branch1).call(); + git.fetch().setRemote("test").setRefSpecs(spec) + .setRemoveDeletedRefs(true).call(); + assertNull(db.resolve(remoteBranch1)); + assertEquals(branchRef2.getObjectId(), db.resolve(remoteBranch2)); + } + @Test public void fetchShouldAutoFollowTag() throws Exception { remoteGit.commit().setMessage("commit").call(); @@ -248,4 +336,75 @@ public void testFetchWithPruneShouldKeepOriginHead() throws Exception { assertEquals("origin/HEAD should be unchanged", originHeadId, clonedRepo.resolve("refs/remotes/origin/HEAD")); } + + @Test + public void fetchAddRefsWithDuplicateRefspec() throws Exception { + final String branchName = "branch"; + final String remoteBranchName = "test/" + branchName; + remoteGit.commit().setMessage("commit").call(); + Ref branchRef = remoteGit.branchCreate().setName(branchName).call(); + + final String spec1 = "+refs/heads/*:refs/remotes/test/*"; + final String spec2 = "refs/heads/*:refs/remotes/test/*"; + final StoredConfig config = db.getConfig(); + RemoteConfig remoteConfig = new RemoteConfig(config, "test"); + remoteConfig.addFetchRefSpec(new RefSpec(spec1)); + remoteConfig.addFetchRefSpec(new RefSpec(spec2)); + remoteConfig.update(config); + + git.fetch().setRemote("test").setRefSpecs(spec1).call(); + assertEquals(branchRef.getObjectId(), db.resolve(remoteBranchName)); + } + + @Test + public void fetchPruneRefsWithDuplicateRefspec() + throws Exception { + final String branchName = "branch"; + final String remoteBranchName = "test/" + branchName; + remoteGit.commit().setMessage("commit").call(); + Ref branchRef = remoteGit.branchCreate().setName(branchName).call(); + + final String spec1 = "+refs/heads/*:refs/remotes/test/*"; + final String spec2 = "refs/heads/*:refs/remotes/test/*"; + final StoredConfig config = db.getConfig(); + RemoteConfig remoteConfig = new RemoteConfig(config, "test"); + remoteConfig.addFetchRefSpec(new RefSpec(spec1)); + remoteConfig.addFetchRefSpec(new RefSpec(spec2)); + remoteConfig.update(config); + + git.fetch().setRemote("test").setRefSpecs(spec1).call(); + assertEquals(branchRef.getObjectId(), db.resolve(remoteBranchName)); + + remoteGit.branchDelete().setBranchNames(branchName).call(); + git.fetch().setRemote("test").setRefSpecs(spec1) + .setRemoveDeletedRefs(true).call(); + assertNull(db.resolve(remoteBranchName)); + } + + @Test + public void fetchUpdateRefsWithDuplicateRefspec() throws Exception { + final String tagName = "foo"; + remoteGit.commit().setMessage("commit").call(); + Ref tagRef1 = remoteGit.tag().setName(tagName).call(); + List refSpecs = new ArrayList<>(); + refSpecs.add(new RefSpec("+refs/heads/*:refs/remotes/origin/*")); + refSpecs.add(new RefSpec("+refs/tags/*:refs/tags/*")); + // Updating tags via the RefSpecs and setting TagOpt.FETCH_TAGS (or + // AUTO_FOLLOW) will result internally in *two* updates for the same + // ref. + git.fetch().setRemote("test").setRefSpecs(refSpecs) + .setTagOpt(TagOpt.AUTO_FOLLOW).call(); + assertEquals(tagRef1.getObjectId(), db.resolve(tagName)); + + remoteGit.commit().setMessage("commit 2").call(); + Ref tagRef2 = remoteGit.tag().setName(tagName).setForceUpdate(true) + .call(); + FetchResult result = git.fetch().setRemote("test").setRefSpecs(refSpecs) + .setTagOpt(TagOpt.FETCH_TAGS).call(); + assertEquals(2, result.getTrackingRefUpdates().size()); + TrackingRefUpdate update = result + .getTrackingRefUpdate(Constants.R_TAGS + tagName); + assertEquals(RefUpdate.Result.FORCED, update.getResult()); + assertEquals(tagRef2.getObjectId(), db.resolve(tagName)); + } } diff --git a/org.eclipse.jgit.ui/.settings/.api_filters b/org.eclipse.jgit.ui/.settings/.api_filters deleted file mode 100644 index aed9c7a35..000000000 --- a/org.eclipse.jgit.ui/.settings/.api_filters +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/org.eclipse.jgit/.settings/.api_filters b/org.eclipse.jgit/.settings/.api_filters deleted file mode 100644 index e51bf20c2..000000000 --- a/org.eclipse.jgit/.settings/.api_filters +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - - - - - - - - - - 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 836cd2cc6..b088d7266 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 @@ -65,6 +65,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.InterruptedIOException; +import java.nio.file.DirectoryNotEmptyException; import java.nio.file.Files; import java.nio.file.Path; import java.security.DigestInputStream; @@ -1287,6 +1288,10 @@ private static void delete(File file, int depth, LockFile rLck) for (int i = 0; i < depth; ++i) { try { Files.delete(dir.toPath()); + } catch (DirectoryNotEmptyException e) { + // Don't log; normal case when there are other refs with the + // same prefix + break; } catch (IOException e) { LOG.warn("Unable to remove path {}", dir, e); break; 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 ff183c897..c43ab18c3 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java @@ -203,12 +203,10 @@ else if (tagopt == TagOpt.FETCH_TAGS) ((BatchingProgressMonitor) monitor).setDelayStart( 250, TimeUnit.MILLISECONDS); } - if (transport.isRemoveDeletedRefs()) + if (transport.isRemoveDeletedRefs()) { deleteStaleTrackingRefs(result, batch); - for (TrackingRefUpdate u : localUpdates) { - result.add(u); - batch.addCommand(u.asReceiveCommand()); } + addUpdateBatchCommands(result, batch); for (ReceiveCommand cmd : batch.getCommands()) { cmd.updateType(walk); if (cmd.getType() == UPDATE_NONFASTFORWARD @@ -221,8 +219,11 @@ else if (tagopt == TagOpt.FETCH_TAGS) if (cmd.getResult() == NOT_ATTEMPTED) cmd.setResult(OK); } - } else + } else { batch.execute(walk, monitor); + } + } catch (TransportException e) { + throw e; } catch (IOException err) { throw new TransportException(MessageFormat.format( JGitText.get().failureUpdatingTrackingRef, @@ -239,6 +240,23 @@ else if (tagopt == TagOpt.FETCH_TAGS) } } + private void addUpdateBatchCommands(FetchResult result, + BatchRefUpdate batch) throws TransportException { + Map refs = new HashMap<>(); + for (TrackingRefUpdate u : localUpdates) { + // Try to skip duplicates if they'd update to the same object ID + ObjectId existing = refs.get(u.getLocalName()); + if (existing == null) { + refs.put(u.getLocalName(), u.getNewObjectId()); + result.add(u); + batch.addCommand(u.asReceiveCommand()); + } else if (!existing.equals(u.getNewObjectId())) { + throw new TransportException(MessageFormat + .format(JGitText.get().duplicateRef, u.getLocalName())); + } + } + } + private void fetchObjects(ProgressMonitor monitor) throws TransportException { try { @@ -479,15 +497,17 @@ private Map localRefs() throws TransportException { private void deleteStaleTrackingRefs(FetchResult result, BatchRefUpdate batch) throws IOException { + Set processed = new HashSet<>(); for (Ref ref : localRefs().values()) { if (ref.isSymbolic()) { continue; } - final String refname = ref.getName(); + String refname = ref.getName(); for (RefSpec spec : toFetch) { if (spec.matchDestination(refname)) { - final RefSpec s = spec.expandFromDestination(refname); - if (result.getAdvertisedRef(s.getSource()) == null) { + RefSpec s = spec.expandFromDestination(refname); + if (result.getAdvertisedRef(s.getSource()) == null + && processed.add(ref)) { deleteTrackingRef(result, batch, s, ref); } }