From de21c58d03d9f54e0a80d358948517d3ea518312 Mon Sep 17 00:00:00 2001 From: Thomas Wolf Date: Thu, 24 May 2018 16:26:36 +0200 Subject: [PATCH] Don't prune symbolic refs when fetch.prune = true The canonical implementation also doesn't. Compare current code in remote.c, function get_stale_heads_cb.[1] Not handling symrefs in this case was introduced in canonical git in [2] in 2008. [1] https://github.com/git/git/blob/v2.17.0/remote.c#L2259 [2] https://github.com/git/git/commit/740fdd27f0 Bug: 533549 Change-Id: If348d56bb4a96b8aa7141f7e7b5a0d3dd4e7808b Signed-off-by: Thomas Wolf --- .../eclipse/jgit/api/FetchCommandTest.java | 44 +++++++++++++++++++ .../eclipse/jgit/transport/FetchProcess.java | 3 ++ 2 files changed, 47 insertions(+) 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 cf1afceae..4c2c0e8d1 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 @@ -43,10 +43,15 @@ package org.eclipse.jgit.api; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import java.io.File; import java.util.Collection; +import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; @@ -204,4 +209,43 @@ public void fetchWithExplicitTagsShouldUpdateLocal() throws Exception { assertEquals(RefUpdate.Result.FORCED, update.getResult()); assertEquals(tagRef2.getObjectId(), db.resolve(tagName)); } + + @Test + public void testFetchWithPruneShouldKeepOriginHead() throws Exception { + // Create a commit in the test repo. + commitFile("foo", "foo", "master"); + // Produce a real clone of the git repo + Git cloned = Git.cloneRepository() + .setDirectory(createTempDirectory("testCloneRepository")) + .setURI("file://" + + git.getRepository().getWorkTree().getAbsolutePath()) + .call(); + assertNotNull(cloned); + Repository clonedRepo = cloned.getRepository(); + addRepoToClose(clonedRepo); + ObjectId originMasterId = clonedRepo + .resolve("refs/remotes/origin/master"); + assertNotNull("Should have origin/master", originMasterId); + assertNotEquals("origin/master should not be zero ID", + ObjectId.zeroId(), originMasterId); + // Canonical git creates origin/HEAD; JGit (for now) doesn't. Let's + // pretend we did the clone via command-line git. + ObjectId originHeadId = clonedRepo.resolve("refs/remotes/origin/HEAD"); + if (originHeadId == null) { + JGitTestUtil.write( + new File(clonedRepo.getDirectory(), + "refs/remotes/origin/HEAD"), + "ref: refs/remotes/origin/master\n"); + originHeadId = clonedRepo.resolve("refs/remotes/origin/HEAD"); + } + assertEquals("Should have origin/HEAD", originMasterId, originHeadId); + FetchResult result = cloned.fetch().setRemote("origin") + .setRemoveDeletedRefs(true).call(); + assertTrue("Fetch after clone should be up-to-date", + result.getTrackingRefUpdates().isEmpty()); + assertEquals("origin/master should still exist", originMasterId, + clonedRepo.resolve("refs/remotes/origin/master")); + assertEquals("origin/HEAD should be unchanged", originHeadId, + clonedRepo.resolve("refs/remotes/origin/HEAD")); + } } 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 51f900b24..ff183c897 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java @@ -480,6 +480,9 @@ private Map localRefs() throws TransportException { private void deleteStaleTrackingRefs(FetchResult result, BatchRefUpdate batch) throws IOException { for (Ref ref : localRefs().values()) { + if (ref.isSymbolic()) { + continue; + } final String refname = ref.getName(); for (RefSpec spec : toFetch) { if (spec.matchDestination(refname)) {