View Javadoc
1   /*
2    * Copyright (C) 2010, 2013 Chris Aniszczyk <caniszczyk@gmail.com>
3    * and other copyright owners as documented in the project's IP log.
4    *
5    * This program and the accompanying materials are made available
6    * under the terms of the Eclipse Distribution License v1.0 which
7    * accompanies this distribution, is reproduced below, and is
8    * available at http://www.eclipse.org/org/documents/edl-v10.php
9    *
10   * All rights reserved.
11   *
12   * Redistribution and use in source and binary forms, with or
13   * without modification, are permitted provided that the following
14   * conditions are met:
15   *
16   * - Redistributions of source code must retain the above copyright
17   *   notice, this list of conditions and the following disclaimer.
18   *
19   * - Redistributions in binary form must reproduce the above
20   *   copyright notice, this list of conditions and the following
21   *   disclaimer in the documentation and/or other materials provided
22   *   with the distribution.
23   *
24   * - Neither the name of the Eclipse Foundation, Inc. nor the
25   *   names of its contributors may be used to endorse or promote
26   *   products derived from this software without specific prior
27   *   written permission.
28   *
29   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
30   * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
31   * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
34   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
35   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
36   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
37   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
38   * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
40   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
41   * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
42   */
43  package org.eclipse.jgit.api;
44  
45  import static org.junit.Assert.assertEquals;
46  import static org.junit.Assert.assertNull;
47  
48  import java.util.ArrayList;
49  import java.util.Collection;
50  import java.util.List;
51  
52  import org.eclipse.jgit.junit.RepositoryTestCase;
53  import org.eclipse.jgit.lib.Constants;
54  import org.eclipse.jgit.lib.ObjectId;
55  import org.eclipse.jgit.lib.Ref;
56  import org.eclipse.jgit.lib.RefUpdate;
57  import org.eclipse.jgit.lib.Repository;
58  import org.eclipse.jgit.lib.StoredConfig;
59  import org.eclipse.jgit.revwalk.RevCommit;
60  import org.eclipse.jgit.transport.FetchResult;
61  import org.eclipse.jgit.transport.RefSpec;
62  import org.eclipse.jgit.transport.RemoteConfig;
63  import org.eclipse.jgit.transport.TagOpt;
64  import org.eclipse.jgit.transport.TrackingRefUpdate;
65  import org.eclipse.jgit.transport.URIish;
66  import org.junit.Before;
67  import org.junit.Test;
68  
69  public class FetchCommandTest extends RepositoryTestCase {
70  
71  	private Git git;
72  	private Git remoteGit;
73  
74  	@Before
75  	public void setupRemoteRepository() throws Exception {
76  		git = new Git(db);
77  
78  		// create other repository
79  		Repository remoteRepository = createWorkRepository();
80  		remoteGit = new Git(remoteRepository);
81  
82  		// setup the first repository to fetch from the second repository
83  		final StoredConfig config = db.getConfig();
84  		RemoteConfig remoteConfig = new RemoteConfig(config, "test");
85  		URIish uri = new URIish(remoteRepository.getDirectory().toURI().toURL());
86  		remoteConfig.addURI(uri);
87  		remoteConfig.update(config);
88  		config.save();
89  	}
90  
91  	@Test
92  	public void testFetch() throws Exception {
93  
94  		// create some refs via commits and tag
95  		RevCommit commit = remoteGit.commit().setMessage("initial commit").call();
96  		Ref tagRef = remoteGit.tag().setName("tag").call();
97  
98  		git.fetch().setRemote("test")
99  				.setRefSpecs("refs/heads/master:refs/heads/x").call();
100 
101 		assertEquals(commit.getId(),
102 				db.resolve(commit.getId().getName() + "^{commit}"));
103 		assertEquals(tagRef.getObjectId(),
104 				db.resolve(tagRef.getObjectId().getName()));
105 	}
106 
107 	@Test
108 	public void fetchAddsBranches() throws Exception {
109 		final String branch1 = "b1";
110 		final String branch2 = "b2";
111 		final String remoteBranch1 = "test/" + branch1;
112 		final String remoteBranch2 = "test/" + branch2;
113 		remoteGit.commit().setMessage("commit").call();
114 		Ref branchRef1 = remoteGit.branchCreate().setName(branch1).call();
115 		remoteGit.commit().setMessage("commit").call();
116 		Ref branchRef2 = remoteGit.branchCreate().setName(branch2).call();
117 
118 		String spec = "refs/heads/*:refs/remotes/test/*";
119 		git.fetch().setRemote("test").setRefSpecs(spec).call();
120 		assertEquals(branchRef1.getObjectId(), db.resolve(remoteBranch1));
121 		assertEquals(branchRef2.getObjectId(), db.resolve(remoteBranch2));
122 	}
123 
124 	@Test
125 	public void fetchDoesntDeleteBranches() throws Exception {
126 		final String branch1 = "b1";
127 		final String branch2 = "b2";
128 		final String remoteBranch1 = "test/" + branch1;
129 		final String remoteBranch2 = "test/" + branch2;
130 		remoteGit.commit().setMessage("commit").call();
131 		Ref branchRef1 = remoteGit.branchCreate().setName(branch1).call();
132 		remoteGit.commit().setMessage("commit").call();
133 		Ref branchRef2 = remoteGit.branchCreate().setName(branch2).call();
134 
135 		String spec = "refs/heads/*:refs/remotes/test/*";
136 		git.fetch().setRemote("test").setRefSpecs(spec).call();
137 		assertEquals(branchRef1.getObjectId(), db.resolve(remoteBranch1));
138 		assertEquals(branchRef2.getObjectId(), db.resolve(remoteBranch2));
139 
140 		remoteGit.branchDelete().setBranchNames(branch1).call();
141 		git.fetch().setRemote("test").setRefSpecs(spec).call();
142 		assertEquals(branchRef1.getObjectId(), db.resolve(remoteBranch1));
143 		assertEquals(branchRef2.getObjectId(), db.resolve(remoteBranch2));
144 	}
145 
146 	@Test
147 	public void fetchUpdatesBranches() throws Exception {
148 		final String branch1 = "b1";
149 		final String branch2 = "b2";
150 		final String remoteBranch1 = "test/" + branch1;
151 		final String remoteBranch2 = "test/" + branch2;
152 		remoteGit.commit().setMessage("commit").call();
153 		Ref branchRef1 = remoteGit.branchCreate().setName(branch1).call();
154 		remoteGit.commit().setMessage("commit").call();
155 		Ref branchRef2 = remoteGit.branchCreate().setName(branch2).call();
156 
157 		String spec = "refs/heads/*:refs/remotes/test/*";
158 		git.fetch().setRemote("test").setRefSpecs(spec).call();
159 		assertEquals(branchRef1.getObjectId(), db.resolve(remoteBranch1));
160 		assertEquals(branchRef2.getObjectId(), db.resolve(remoteBranch2));
161 
162 		remoteGit.commit().setMessage("commit").call();
163 		branchRef2 = remoteGit.branchCreate().setName(branch2).setForce(true).call();
164 		git.fetch().setRemote("test").setRefSpecs(spec).call();
165 		assertEquals(branchRef1.getObjectId(), db.resolve(remoteBranch1));
166 		assertEquals(branchRef2.getObjectId(), db.resolve(remoteBranch2));
167 	}
168 
169 	@Test
170 	public void fetchPrunesBranches() throws Exception {
171 		final String branch1 = "b1";
172 		final String branch2 = "b2";
173 		final String remoteBranch1 = "test/" + branch1;
174 		final String remoteBranch2 = "test/" + branch2;
175 		remoteGit.commit().setMessage("commit").call();
176 		Ref branchRef1 = remoteGit.branchCreate().setName(branch1).call();
177 		remoteGit.commit().setMessage("commit").call();
178 		Ref branchRef2 = remoteGit.branchCreate().setName(branch2).call();
179 
180 		String spec = "refs/heads/*:refs/remotes/test/*";
181 		git.fetch().setRemote("test").setRefSpecs(spec).call();
182 		assertEquals(branchRef1.getObjectId(), db.resolve(remoteBranch1));
183 		assertEquals(branchRef2.getObjectId(), db.resolve(remoteBranch2));
184 
185 		remoteGit.branchDelete().setBranchNames(branch1).call();
186 		git.fetch().setRemote("test").setRefSpecs(spec)
187 				.setRemoveDeletedRefs(true).call();
188 		assertNull(db.resolve(remoteBranch1));
189 		assertEquals(branchRef2.getObjectId(), db.resolve(remoteBranch2));
190 	}
191 
192 	@Test
193 	public void fetchShouldAutoFollowTag() throws Exception {
194 		remoteGit.commit().setMessage("commit").call();
195 		Ref tagRef = remoteGit.tag().setName("foo").call();
196 
197 		git.fetch().setRemote("test")
198 				.setRefSpecs("refs/heads/*:refs/remotes/origin/*")
199 				.setTagOpt(TagOpt.AUTO_FOLLOW).call();
200 
201 		assertEquals(tagRef.getObjectId(), db.resolve("foo"));
202 	}
203 
204 	@Test
205 	public void fetchShouldAutoFollowTagForFetchedObjects() throws Exception {
206 		remoteGit.commit().setMessage("commit").call();
207 		Ref tagRef = remoteGit.tag().setName("foo").call();
208 		remoteGit.commit().setMessage("commit2").call();
209 		git.fetch().setRemote("test")
210 				.setRefSpecs("refs/heads/*:refs/remotes/origin/*")
211 				.setTagOpt(TagOpt.AUTO_FOLLOW).call();
212 		assertEquals(tagRef.getObjectId(), db.resolve("foo"));
213 	}
214 
215 	@Test
216 	public void fetchShouldNotFetchTagsFromOtherBranches() throws Exception {
217 		remoteGit.commit().setMessage("commit").call();
218 		remoteGit.checkout().setName("other").setCreateBranch(true).call();
219 		remoteGit.commit().setMessage("commit2").call();
220 		remoteGit.tag().setName("foo").call();
221 		git.fetch().setRemote("test")
222 				.setRefSpecs("refs/heads/master:refs/remotes/origin/master")
223 				.setTagOpt(TagOpt.AUTO_FOLLOW).call();
224 		assertNull(db.resolve("foo"));
225 	}
226 
227 	@Test
228 	public void fetchWithUpdatedTagShouldNotTryToUpdateLocal() throws Exception {
229 		final String tagName = "foo";
230 		remoteGit.commit().setMessage("commit").call();
231 		Ref tagRef = remoteGit.tag().setName(tagName).call();
232 		ObjectId originalId = tagRef.getObjectId();
233 
234 		String spec = "refs/heads/*:refs/remotes/origin/*";
235 		git.fetch().setRemote("test").setRefSpecs(spec)
236 				.setTagOpt(TagOpt.AUTO_FOLLOW).call();
237 		assertEquals(originalId, db.resolve(tagName));
238 
239 		remoteGit.commit().setMessage("commit 2").call();
240 		remoteGit.tag().setName(tagName).setForceUpdate(true).call();
241 
242 		FetchResult result = git.fetch().setRemote("test").setRefSpecs(spec)
243 				.setTagOpt(TagOpt.AUTO_FOLLOW).call();
244 
245 		Collection<TrackingRefUpdate> refUpdates = result
246 				.getTrackingRefUpdates();
247 		assertEquals(1, refUpdates.size());
248 		TrackingRefUpdate update = refUpdates.iterator().next();
249 		assertEquals("refs/heads/master", update.getRemoteName());
250 
251 		assertEquals(originalId, db.resolve(tagName));
252 	}
253 
254 	@Test
255 	public void fetchWithExplicitTagsShouldUpdateLocal() throws Exception {
256 		final String tagName = "foo";
257 		remoteGit.commit().setMessage("commit").call();
258 		Ref tagRef1 = remoteGit.tag().setName(tagName).call();
259 
260 		String spec = "refs/heads/*:refs/remotes/origin/*";
261 		git.fetch().setRemote("test").setRefSpecs(spec)
262 				.setTagOpt(TagOpt.AUTO_FOLLOW).call();
263 		assertEquals(tagRef1.getObjectId(), db.resolve(tagName));
264 
265 		remoteGit.commit().setMessage("commit 2").call();
266 		Ref tagRef2 = remoteGit.tag().setName(tagName).setForceUpdate(true)
267 				.call();
268 
269 		FetchResult result = git.fetch().setRemote("test").setRefSpecs(spec)
270 				.setTagOpt(TagOpt.FETCH_TAGS).call();
271 		TrackingRefUpdate update = result.getTrackingRefUpdate(Constants.R_TAGS
272 				+ tagName);
273 		assertEquals(RefUpdate.Result.FORCED, update.getResult());
274 		assertEquals(tagRef2.getObjectId(), db.resolve(tagName));
275 	}
276 
277 	@Test
278 	public void fetchAddRefsWithDuplicateRefspec() throws Exception {
279 		final String branchName = "branch";
280 		final String remoteBranchName = "test/" + branchName;
281 		remoteGit.commit().setMessage("commit").call();
282 		Ref branchRef = remoteGit.branchCreate().setName(branchName).call();
283 
284 		final String spec1 = "+refs/heads/*:refs/remotes/test/*";
285 		final String spec2 = "refs/heads/*:refs/remotes/test/*";
286 		final StoredConfig config = db.getConfig();
287 		RemoteConfig remoteConfig = new RemoteConfig(config, "test");
288 		remoteConfig.addFetchRefSpec(new RefSpec(spec1));
289 		remoteConfig.addFetchRefSpec(new RefSpec(spec2));
290 		remoteConfig.update(config);
291 
292 		git.fetch().setRemote("test").setRefSpecs(spec1).call();
293 		assertEquals(branchRef.getObjectId(), db.resolve(remoteBranchName));
294 	}
295 
296 	@Test
297 	public void fetchPruneRefsWithDuplicateRefspec()
298 			throws Exception {
299 		final String branchName = "branch";
300 		final String remoteBranchName = "test/" + branchName;
301 		remoteGit.commit().setMessage("commit").call();
302 		Ref branchRef = remoteGit.branchCreate().setName(branchName).call();
303 
304 		final String spec1 = "+refs/heads/*:refs/remotes/test/*";
305 		final String spec2 = "refs/heads/*:refs/remotes/test/*";
306 		final StoredConfig config = db.getConfig();
307 		RemoteConfig remoteConfig = new RemoteConfig(config, "test");
308 		remoteConfig.addFetchRefSpec(new RefSpec(spec1));
309 		remoteConfig.addFetchRefSpec(new RefSpec(spec2));
310 		remoteConfig.update(config);
311 
312 		git.fetch().setRemote("test").setRefSpecs(spec1).call();
313 		assertEquals(branchRef.getObjectId(), db.resolve(remoteBranchName));
314 
315 		remoteGit.branchDelete().setBranchNames(branchName).call();
316 		git.fetch().setRemote("test").setRefSpecs(spec1)
317 				.setRemoveDeletedRefs(true).call();
318 		assertNull(db.resolve(remoteBranchName));
319 	}
320 
321 	@Test
322 	public void fetchUpdateRefsWithDuplicateRefspec() throws Exception {
323 		final String tagName = "foo";
324 		remoteGit.commit().setMessage("commit").call();
325 		Ref tagRef1 = remoteGit.tag().setName(tagName).call();
326 		List<RefSpec> refSpecs = new ArrayList<>();
327 		refSpecs.add(new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
328 		refSpecs.add(new RefSpec("+refs/tags/*:refs/tags/*"));
329 		// Updating tags via the RefSpecs and setting TagOpt.FETCH_TAGS (or
330 		// AUTO_FOLLOW) will result internally in *two* updates for the same
331 		// ref.
332 		git.fetch().setRemote("test").setRefSpecs(refSpecs)
333 				.setTagOpt(TagOpt.AUTO_FOLLOW).call();
334 		assertEquals(tagRef1.getObjectId(), db.resolve(tagName));
335 
336 		remoteGit.commit().setMessage("commit 2").call();
337 		Ref tagRef2 = remoteGit.tag().setName(tagName).setForceUpdate(true)
338 				.call();
339 		FetchResult result = git.fetch().setRemote("test").setRefSpecs(refSpecs)
340 				.setTagOpt(TagOpt.FETCH_TAGS).call();
341 		assertEquals(2, result.getTrackingRefUpdates().size());
342 		TrackingRefUpdate update = result
343 				.getTrackingRefUpdate(Constants.R_TAGS + tagName);
344 		assertEquals(RefUpdate.Result.FORCED, update.getResult());
345 		assertEquals(tagRef2.getObjectId(), db.resolve(tagName));
346 	}
347 }