Skip to main content
diff options
authorThomas Wolf2018-08-19 18:43:50 +0000
committerThomas Wolf2018-08-22 09:09:01 +0000
commitffd1ac5dde053e861ad249d7d8d27df7cef56eb9 (patch)
tree25046d2a1da5054134d78e4b7eac9d206e2d5bfd /org.eclipse.jgit.test/tst
parent65a0cfc82a75146113b9e138cb9fdd5f04c018d0 (diff)
Fix fetching with duplicate ref updates
If packed refs are used, duplicate updates result in an exception because JGit tries to lock the same lock file twice. With non-atomic ref updates, this used to work, since the same ref would simply be locked and updated twice in succession. Let's be more lenient in this case and remove duplicates before trying to do the ref updates. Silently skip duplicate updates for the same ref, if they both would update the ref to the same object ID. (If they don't, behavior is undefined anyway, and we still throw an exception.) Add a test that results in a duplicate ref update for a tag. Bug: 529400 Change-Id: Ide97f20b219646ac24c22e28de0c194a29cb62a5 Signed-off-by: Thomas Wolf <>
Diffstat (limited to 'org.eclipse.jgit.test/tst')
1 files changed, 29 insertions, 0 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/
index 0622851822..530fb1b2fe 100644
--- a/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/api/
@@ -45,7 +45,9 @@ package org.eclipse.jgit.api;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
+import java.util.ArrayList;
import java.util.Collection;
+import java.util.List;
import org.eclipse.jgit.junit.RepositoryTestCase;
import org.eclipse.jgit.lib.Constants;
@@ -315,4 +317,31 @@ public class FetchCommandTest extends RepositoryTestCase {
+ @Test
+ public void fetchUpdateRefsWithDuplicateRefspec() throws Exception {
+ final String tagName = "foo";
+ remoteGit.commit().setMessage("commit").call();
+ Ref tagRef1 = remoteGit.tag().setName(tagName).call();
+ List<RefSpec> 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));
+ }

Back to the top