/* * Copyright (C) 2010, 2013 Chris Aniszczyk and others * * This program and the accompanying materials are made available under the * terms of the Eclipse Distribution License v. 1.0 which is available at * https://www.eclipse.org/org/documents/edl-v10.php. * * SPDX-License-Identifier: BSD-3-Clause */ 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.ArrayList; import java.util.Collection; import java.util.List; import org.eclipse.jgit.junit.JGitTestUtil; import org.eclipse.jgit.junit.RepositoryTestCase; import org.eclipse.jgit.lib.Constants; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Ref; import org.eclipse.jgit.lib.RefUpdate; 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 { private Git git; private Git remoteGit; @Before public void setupRemoteRepository() throws Exception { git = new Git(db); // create other repository 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(remoteRepository.getDirectory().toURI().toURL()); remoteConfig.addURI(uri); remoteConfig.update(config); config.save(); } @Test public void testFetch() throws Exception { // create some refs via commits and tag RevCommit commit = remoteGit.commit().setMessage("initial commit").call(); Ref tagRef = remoteGit.tag().setName("tag").call(); git.fetch().setRemote("test") .setRefSpecs("refs/heads/master:refs/heads/x").call(); assertEquals(commit.getId(), db.resolve(commit.getId().getName() + "^{commit}")); assertEquals(tagRef.getObjectId(), db.resolve(tagRef.getObjectId().getName())); } @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 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(); git.fetch().setRemote("test") .setRefSpecs("refs/heads/master:refs/heads/master").call(); remoteGit.commit().setAmend(true).setMessage("amended").call(); FetchResult res = git.fetch().setRemote("test") .setRefSpecs("refs/heads/master:refs/heads/master").call(); assertEquals(RefUpdate.Result.REJECTED, res.getTrackingRefUpdate("refs/heads/master").getResult()); res = git.fetch().setRemote("test") .setRefSpecs("refs/heads/master:refs/heads/master") .setForceUpdate(true).call(); assertEquals(RefUpdate.Result.FORCED, res.getTrackingRefUpdate("refs/heads/master").getResult()); } @Test public void testFetchSimpleNegativeRefSpec() throws Exception { remoteGit.commit().setMessage("commit").call(); FetchResult res = git.fetch().setRemote("test") .setRefSpecs("refs/heads/master:refs/heads/test", "^:refs/heads/test") .call(); assertNull(res.getTrackingRefUpdate("refs/heads/test")); res = git.fetch().setRemote("test") .setRefSpecs("refs/heads/master:refs/heads/test", "^refs/heads/master") .call(); assertNull(res.getTrackingRefUpdate("refs/heads/test")); } @Test public void negativeRefSpecFilterBySource() throws Exception { remoteGit.commit().setMessage("commit").call(); remoteGit.branchCreate().setName("test").call(); remoteGit.commit().setMessage("commit1").call(); remoteGit.branchCreate().setName("dev").call(); FetchResult res = git.fetch().setRemote("test") .setRefSpecs("refs/*:refs/origins/*", "^refs/*/test") .call(); assertNotNull(res.getTrackingRefUpdate("refs/origins/heads/master")); assertNull(res.getTrackingRefUpdate("refs/origins/heads/test")); assertNotNull(res.getTrackingRefUpdate("refs/origins/heads/dev")); } @Test public void negativeRefSpecFilterByDestination() throws Exception { remoteGit.commit().setMessage("commit").call(); remoteGit.branchCreate().setName("meta").call(); remoteGit.commit().setMessage("commit1").call(); remoteGit.branchCreate().setName("data").call(); FetchResult res = git.fetch().setRemote("test") .setRefSpecs("refs/*:refs/secret/*", "^:refs/secret/*/meta") .call(); assertNotNull(res.getTrackingRefUpdate("refs/secret/heads/master")); assertNull(res.getTrackingRefUpdate("refs/secret/heads/meta")); assertNotNull(res.getTrackingRefUpdate("refs/secret/heads/data")); } @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(); Ref tagRef = remoteGit.tag().setName("foo").call(); git.fetch().setRemote("test") .setRefSpecs("refs/heads/*:refs/remotes/origin/*") .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(); git.fetch().setRemote("test") .setRefSpecs("refs/heads/*:refs/remotes/origin/*") .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(); git.fetch().setRemote("test") .setRefSpecs("refs/heads/master:refs/remotes/origin/master") .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(); String spec = "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)); } @Test public void fetchWithExplicitTagsShouldUpdateLocal() throws Exception { final String tagName = "foo"; remoteGit.commit().setMessage("commit").call(); Ref tagRef1 = remoteGit.tag().setName(tagName).call(); String spec = "refs/heads/*:refs/remotes/origin/*"; git.fetch().setRemote("test").setRefSpecs(spec) .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(spec) .setTagOpt(TagOpt.FETCH_TAGS).call(); TrackingRefUpdate update = result.getTrackingRefUpdate(Constants.R_TAGS + tagName); 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")); } @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)); } }