From 68b378a4b5e08b80c35e6ad91df25b1034c379a3 Mon Sep 17 00:00:00 2001 From: Robin Stocker Date: Sat, 27 Apr 2013 16:14:46 +0200 Subject: [PATCH] Only fetch tags that do not exist locally with auto-follow This corresponds to what C Git does, quoting from the fetch man page: This is done by first fetching from the remote using the given s, and if the repository has objects that are pointed by remote tags that it does not yet have, then fetch those missing tags. Before, JGit would also fetch tags that exist locally but point to a different object, resulting in REJECTED results for these. Also add some test cases to cover more cases. Bug: 388095 Change-Id: Ib03d2d82e9c4b60179d626cfd5174be1da6388b2 Also-by: Stefan Lay --- .../eclipse/jgit/api/FetchCommandTest.java | 98 ++++++++++++++++--- .../eclipse/jgit/transport/FetchProcess.java | 23 ++--- 2 files changed, 94 insertions(+), 27 deletions(-) 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 abfbd1548..c30f9a246 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 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010, Chris Aniszczyk + * Copyright (C) 2010, 2013 Chris Aniszczyk * and other copyright owners as documented in the project's IP log. * * This program and the accompanying materials are made available @@ -43,55 +43,129 @@ package org.eclipse.jgit.api; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; import java.io.IOException; import java.net.URISyntaxException; +import java.util.Collection; import org.eclipse.jgit.api.errors.GitAPIException; import org.eclipse.jgit.api.errors.JGitInternalException; import org.eclipse.jgit.junit.RepositoryTestCase; +import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.Repository; 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; import org.eclipse.jgit.transport.URIish; +import org.junit.Before; import org.junit.Test; public class FetchCommandTest extends RepositoryTestCase { - @Test - public void testFetch() throws JGitInternalException, IOException, - GitAPIException, URISyntaxException { + private Git git; + private Git remoteGit; + + @Before + public void setupRemoteRepository() throws IOException, URISyntaxException { + git = new Git(db); // create other repository - Repository db2 = createWorkRepository(); - Git git2 = new Git(db2); + Repository remoteRepository = createWorkRepository(); + remoteGit = new Git(remoteRepository); // setup the first repository to fetch from the second repository final StoredConfig config = db.getConfig(); RemoteConfig remoteConfig = new RemoteConfig(config, "test"); - URIish uri = new URIish(db2.getDirectory().toURI().toURL()); + URIish uri = new URIish(remoteRepository.getDirectory().toURI().toURL()); remoteConfig.addURI(uri); remoteConfig.update(config); config.save(); + } - // create some refs via commits and tag - RevCommit commit = git2.commit().setMessage("initial commit").call(); - Ref tagRef = git2.tag().setName("tag").call(); + @Test + public void testFetch() throws JGitInternalException, IOException, + GitAPIException { - Git git1 = new Git(db); + // create some refs via commits and tag + RevCommit commit = remoteGit.commit().setMessage("initial commit").call(); + Ref tagRef = remoteGit.tag().setName("tag").call(); RefSpec spec = new RefSpec("refs/heads/master:refs/heads/x"); - git1.fetch().setRemote("test").setRefSpecs(spec) + git.fetch().setRemote("test").setRefSpecs(spec) .call(); assertEquals(commit.getId(), db.resolve(commit.getId().getName() + "^{commit}")); assertEquals(tagRef.getObjectId(), db.resolve(tagRef.getObjectId().getName())); + } + + @Test + public void fetchShouldAutoFollowTag() throws Exception { + remoteGit.commit().setMessage("commit").call(); + Ref tagRef = remoteGit.tag().setName("foo").call(); + + RefSpec spec = new RefSpec("refs/heads/*:refs/remotes/origin/*"); + git.fetch().setRemote("test").setRefSpecs(spec) + .setTagOpt(TagOpt.AUTO_FOLLOW).call(); + assertEquals(tagRef.getObjectId(), db.resolve("foo")); } + @Test + public void fetchShouldAutoFollowTagForFetchedObjects() throws Exception { + remoteGit.commit().setMessage("commit").call(); + Ref tagRef = remoteGit.tag().setName("foo").call(); + remoteGit.commit().setMessage("commit2").call(); + RefSpec spec = new RefSpec("refs/heads/*:refs/remotes/origin/*"); + git.fetch().setRemote("test").setRefSpecs(spec) + .setTagOpt(TagOpt.AUTO_FOLLOW).call(); + assertEquals(tagRef.getObjectId(), db.resolve("foo")); + } + + @Test + public void fetchShouldNotFetchTagsFromOtherBranches() throws Exception { + remoteGit.commit().setMessage("commit").call(); + remoteGit.checkout().setName("other").setCreateBranch(true).call(); + remoteGit.commit().setMessage("commit2").call(); + remoteGit.tag().setName("foo").call(); + RefSpec spec = new RefSpec( + "refs/heads/master:refs/remotes/origin/master"); + git.fetch().setRemote("test").setRefSpecs(spec) + .setTagOpt(TagOpt.AUTO_FOLLOW).call(); + assertNull(db.resolve("foo")); + } + + @Test + public void fetchWithUpdatedTagShouldNotTryToUpdateLocal() throws Exception { + final String tagName = "foo"; + remoteGit.commit().setMessage("commit").call(); + Ref tagRef = remoteGit.tag().setName(tagName).call(); + ObjectId originalId = tagRef.getObjectId(); + + RefSpec spec = new RefSpec("refs/heads/*:refs/remotes/origin/*"); + git.fetch().setRemote("test").setRefSpecs(spec) + .setTagOpt(TagOpt.AUTO_FOLLOW).call(); + assertEquals(originalId, db.resolve(tagName)); + + remoteGit.commit().setMessage("commit 2").call(); + remoteGit.tag().setName(tagName).setForceUpdate(true).call(); + + FetchResult result = git.fetch().setRemote("test").setRefSpecs(spec) + .setTagOpt(TagOpt.AUTO_FOLLOW).call(); + + Collection refUpdates = result + .getTrackingRefUpdates(); + assertEquals(1, refUpdates.size()); + TrackingRefUpdate update = refUpdates.iterator().next(); + assertEquals("refs/heads/master", update.getRemoteName()); + + assertEquals(originalId, db.resolve(tagName)); + } } 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 d3e38f9c8..9a11dbda6 100644 --- a/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java +++ b/org.eclipse.jgit/src/org/eclipse/jgit/transport/FetchProcess.java @@ -382,23 +382,16 @@ class FetchProcess { continue; Ref local = haveRefs.get(r.getName()); - ObjectId obj = r.getObjectId(); - - if (r.getPeeledObjectId() == null) { - if (local != null && obj.equals(local.getObjectId())) - continue; - if (askFor.containsKey(obj) || transport.local.hasObject(obj)) - wantTag(r); - else - additionalTags.add(r); + if (local != null) + // We already have a tag with this name, don't fetch it (even if + // the local is different). continue; - } - if (local != null) { - if (!obj.equals(local.getObjectId())) - wantTag(r); - } else if (askFor.containsKey(r.getPeeledObjectId()) - || transport.local.hasObject(r.getPeeledObjectId())) + ObjectId obj = r.getPeeledObjectId(); + if (obj == null) + obj = r.getObjectId(); + + if (askFor.containsKey(obj) || transport.local.hasObject(obj)) wantTag(r); else additionalTags.add(r);