You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FetchCommandTest.java 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410
  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. import static org.junit.Assert.assertEquals;
  45. import static org.junit.Assert.assertNotEquals;
  46. import static org.junit.Assert.assertNotNull;
  47. import static org.junit.Assert.assertNull;
  48. import static org.junit.Assert.assertTrue;
  49. import java.io.File;
  50. import java.util.ArrayList;
  51. import java.util.Collection;
  52. import java.util.List;
  53. import org.eclipse.jgit.junit.JGitTestUtil;
  54. import org.eclipse.jgit.junit.RepositoryTestCase;
  55. import org.eclipse.jgit.lib.Constants;
  56. import org.eclipse.jgit.lib.ObjectId;
  57. import org.eclipse.jgit.lib.Ref;
  58. import org.eclipse.jgit.lib.RefUpdate;
  59. import org.eclipse.jgit.lib.Repository;
  60. import org.eclipse.jgit.lib.StoredConfig;
  61. import org.eclipse.jgit.revwalk.RevCommit;
  62. import org.eclipse.jgit.transport.FetchResult;
  63. import org.eclipse.jgit.transport.RefSpec;
  64. import org.eclipse.jgit.transport.RemoteConfig;
  65. import org.eclipse.jgit.transport.TagOpt;
  66. import org.eclipse.jgit.transport.TrackingRefUpdate;
  67. import org.eclipse.jgit.transport.URIish;
  68. import org.junit.Before;
  69. import org.junit.Test;
  70. public class FetchCommandTest extends RepositoryTestCase {
  71. private Git git;
  72. private Git remoteGit;
  73. @Before
  74. public void setupRemoteRepository() throws Exception {
  75. git = new Git(db);
  76. // create other repository
  77. Repository remoteRepository = createWorkRepository();
  78. remoteGit = new Git(remoteRepository);
  79. // setup the first repository to fetch from the second repository
  80. final StoredConfig config = db.getConfig();
  81. RemoteConfig remoteConfig = new RemoteConfig(config, "test");
  82. URIish uri = new URIish(remoteRepository.getDirectory().toURI().toURL());
  83. remoteConfig.addURI(uri);
  84. remoteConfig.update(config);
  85. config.save();
  86. }
  87. @Test
  88. public void testFetch() throws Exception {
  89. // create some refs via commits and tag
  90. RevCommit commit = remoteGit.commit().setMessage("initial commit").call();
  91. Ref tagRef = remoteGit.tag().setName("tag").call();
  92. git.fetch().setRemote("test")
  93. .setRefSpecs("refs/heads/master:refs/heads/x").call();
  94. assertEquals(commit.getId(),
  95. db.resolve(commit.getId().getName() + "^{commit}"));
  96. assertEquals(tagRef.getObjectId(),
  97. db.resolve(tagRef.getObjectId().getName()));
  98. }
  99. @Test
  100. public void testForcedFetch() throws Exception {
  101. remoteGit.commit().setMessage("commit").call();
  102. remoteGit.commit().setMessage("commit2").call();
  103. git.fetch().setRemote("test")
  104. .setRefSpecs("refs/heads/master:refs/heads/master").call();
  105. remoteGit.commit().setAmend(true).setMessage("amended").call();
  106. FetchResult res = git.fetch().setRemote("test")
  107. .setRefSpecs("refs/heads/master:refs/heads/master").call();
  108. assertEquals(RefUpdate.Result.REJECTED,
  109. res.getTrackingRefUpdate("refs/heads/master").getResult());
  110. res = git.fetch().setRemote("test")
  111. .setRefSpecs("refs/heads/master:refs/heads/master")
  112. .setForceUpdate(true).call();
  113. assertEquals(RefUpdate.Result.FORCED,
  114. res.getTrackingRefUpdate("refs/heads/master").getResult());
  115. }
  116. @Test
  117. public void fetchAddsBranches() throws Exception {
  118. final String branch1 = "b1";
  119. final String branch2 = "b2";
  120. final String remoteBranch1 = "test/" + branch1;
  121. final String remoteBranch2 = "test/" + branch2;
  122. remoteGit.commit().setMessage("commit").call();
  123. Ref branchRef1 = remoteGit.branchCreate().setName(branch1).call();
  124. remoteGit.commit().setMessage("commit").call();
  125. Ref branchRef2 = remoteGit.branchCreate().setName(branch2).call();
  126. String spec = "refs/heads/*:refs/remotes/test/*";
  127. git.fetch().setRemote("test").setRefSpecs(spec).call();
  128. assertEquals(branchRef1.getObjectId(), db.resolve(remoteBranch1));
  129. assertEquals(branchRef2.getObjectId(), db.resolve(remoteBranch2));
  130. }
  131. @Test
  132. public void fetchDoesntDeleteBranches() throws Exception {
  133. final String branch1 = "b1";
  134. final String branch2 = "b2";
  135. final String remoteBranch1 = "test/" + branch1;
  136. final String remoteBranch2 = "test/" + branch2;
  137. remoteGit.commit().setMessage("commit").call();
  138. Ref branchRef1 = remoteGit.branchCreate().setName(branch1).call();
  139. remoteGit.commit().setMessage("commit").call();
  140. Ref branchRef2 = remoteGit.branchCreate().setName(branch2).call();
  141. String spec = "refs/heads/*:refs/remotes/test/*";
  142. git.fetch().setRemote("test").setRefSpecs(spec).call();
  143. assertEquals(branchRef1.getObjectId(), db.resolve(remoteBranch1));
  144. assertEquals(branchRef2.getObjectId(), db.resolve(remoteBranch2));
  145. remoteGit.branchDelete().setBranchNames(branch1).call();
  146. git.fetch().setRemote("test").setRefSpecs(spec).call();
  147. assertEquals(branchRef1.getObjectId(), db.resolve(remoteBranch1));
  148. assertEquals(branchRef2.getObjectId(), db.resolve(remoteBranch2));
  149. }
  150. @Test
  151. public void fetchUpdatesBranches() throws Exception {
  152. final String branch1 = "b1";
  153. final String branch2 = "b2";
  154. final String remoteBranch1 = "test/" + branch1;
  155. final String remoteBranch2 = "test/" + branch2;
  156. remoteGit.commit().setMessage("commit").call();
  157. Ref branchRef1 = remoteGit.branchCreate().setName(branch1).call();
  158. remoteGit.commit().setMessage("commit").call();
  159. Ref branchRef2 = remoteGit.branchCreate().setName(branch2).call();
  160. String spec = "refs/heads/*:refs/remotes/test/*";
  161. git.fetch().setRemote("test").setRefSpecs(spec).call();
  162. assertEquals(branchRef1.getObjectId(), db.resolve(remoteBranch1));
  163. assertEquals(branchRef2.getObjectId(), db.resolve(remoteBranch2));
  164. remoteGit.commit().setMessage("commit").call();
  165. branchRef2 = remoteGit.branchCreate().setName(branch2).setForce(true).call();
  166. git.fetch().setRemote("test").setRefSpecs(spec).call();
  167. assertEquals(branchRef1.getObjectId(), db.resolve(remoteBranch1));
  168. assertEquals(branchRef2.getObjectId(), db.resolve(remoteBranch2));
  169. }
  170. @Test
  171. public void fetchPrunesBranches() throws Exception {
  172. final String branch1 = "b1";
  173. final String branch2 = "b2";
  174. final String remoteBranch1 = "test/" + branch1;
  175. final String remoteBranch2 = "test/" + branch2;
  176. remoteGit.commit().setMessage("commit").call();
  177. Ref branchRef1 = remoteGit.branchCreate().setName(branch1).call();
  178. remoteGit.commit().setMessage("commit").call();
  179. Ref branchRef2 = remoteGit.branchCreate().setName(branch2).call();
  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. remoteGit.branchDelete().setBranchNames(branch1).call();
  185. git.fetch().setRemote("test").setRefSpecs(spec)
  186. .setRemoveDeletedRefs(true).call();
  187. assertNull(db.resolve(remoteBranch1));
  188. assertEquals(branchRef2.getObjectId(), db.resolve(remoteBranch2));
  189. }
  190. @Test
  191. public void fetchShouldAutoFollowTag() throws Exception {
  192. remoteGit.commit().setMessage("commit").call();
  193. Ref tagRef = remoteGit.tag().setName("foo").call();
  194. git.fetch().setRemote("test")
  195. .setRefSpecs("refs/heads/*:refs/remotes/origin/*")
  196. .setTagOpt(TagOpt.AUTO_FOLLOW).call();
  197. assertEquals(tagRef.getObjectId(), db.resolve("foo"));
  198. }
  199. @Test
  200. public void fetchShouldAutoFollowTagForFetchedObjects() throws Exception {
  201. remoteGit.commit().setMessage("commit").call();
  202. Ref tagRef = remoteGit.tag().setName("foo").call();
  203. remoteGit.commit().setMessage("commit2").call();
  204. git.fetch().setRemote("test")
  205. .setRefSpecs("refs/heads/*:refs/remotes/origin/*")
  206. .setTagOpt(TagOpt.AUTO_FOLLOW).call();
  207. assertEquals(tagRef.getObjectId(), db.resolve("foo"));
  208. }
  209. @Test
  210. public void fetchShouldNotFetchTagsFromOtherBranches() throws Exception {
  211. remoteGit.commit().setMessage("commit").call();
  212. remoteGit.checkout().setName("other").setCreateBranch(true).call();
  213. remoteGit.commit().setMessage("commit2").call();
  214. remoteGit.tag().setName("foo").call();
  215. git.fetch().setRemote("test")
  216. .setRefSpecs("refs/heads/master:refs/remotes/origin/master")
  217. .setTagOpt(TagOpt.AUTO_FOLLOW).call();
  218. assertNull(db.resolve("foo"));
  219. }
  220. @Test
  221. public void fetchWithUpdatedTagShouldNotTryToUpdateLocal() throws Exception {
  222. final String tagName = "foo";
  223. remoteGit.commit().setMessage("commit").call();
  224. Ref tagRef = remoteGit.tag().setName(tagName).call();
  225. ObjectId originalId = tagRef.getObjectId();
  226. String spec = "refs/heads/*:refs/remotes/origin/*";
  227. git.fetch().setRemote("test").setRefSpecs(spec)
  228. .setTagOpt(TagOpt.AUTO_FOLLOW).call();
  229. assertEquals(originalId, db.resolve(tagName));
  230. remoteGit.commit().setMessage("commit 2").call();
  231. remoteGit.tag().setName(tagName).setForceUpdate(true).call();
  232. FetchResult result = git.fetch().setRemote("test").setRefSpecs(spec)
  233. .setTagOpt(TagOpt.AUTO_FOLLOW).call();
  234. Collection<TrackingRefUpdate> refUpdates = result
  235. .getTrackingRefUpdates();
  236. assertEquals(1, refUpdates.size());
  237. TrackingRefUpdate update = refUpdates.iterator().next();
  238. assertEquals("refs/heads/master", update.getRemoteName());
  239. assertEquals(originalId, db.resolve(tagName));
  240. }
  241. @Test
  242. public void fetchWithExplicitTagsShouldUpdateLocal() throws Exception {
  243. final String tagName = "foo";
  244. remoteGit.commit().setMessage("commit").call();
  245. Ref tagRef1 = remoteGit.tag().setName(tagName).call();
  246. String spec = "refs/heads/*:refs/remotes/origin/*";
  247. git.fetch().setRemote("test").setRefSpecs(spec)
  248. .setTagOpt(TagOpt.AUTO_FOLLOW).call();
  249. assertEquals(tagRef1.getObjectId(), db.resolve(tagName));
  250. remoteGit.commit().setMessage("commit 2").call();
  251. Ref tagRef2 = remoteGit.tag().setName(tagName).setForceUpdate(true)
  252. .call();
  253. FetchResult result = git.fetch().setRemote("test").setRefSpecs(spec)
  254. .setTagOpt(TagOpt.FETCH_TAGS).call();
  255. TrackingRefUpdate update = result.getTrackingRefUpdate(Constants.R_TAGS
  256. + tagName);
  257. assertEquals(RefUpdate.Result.FORCED, update.getResult());
  258. assertEquals(tagRef2.getObjectId(), db.resolve(tagName));
  259. }
  260. @Test
  261. public void testFetchWithPruneShouldKeepOriginHead() throws Exception {
  262. // Create a commit in the test repo.
  263. commitFile("foo", "foo", "master");
  264. // Produce a real clone of the git repo
  265. Git cloned = Git.cloneRepository()
  266. .setDirectory(createTempDirectory("testCloneRepository"))
  267. .setURI("file://"
  268. + git.getRepository().getWorkTree().getAbsolutePath())
  269. .call();
  270. assertNotNull(cloned);
  271. Repository clonedRepo = cloned.getRepository();
  272. addRepoToClose(clonedRepo);
  273. ObjectId originMasterId = clonedRepo
  274. .resolve("refs/remotes/origin/master");
  275. assertNotNull("Should have origin/master", originMasterId);
  276. assertNotEquals("origin/master should not be zero ID",
  277. ObjectId.zeroId(), originMasterId);
  278. // Canonical git creates origin/HEAD; JGit (for now) doesn't. Let's
  279. // pretend we did the clone via command-line git.
  280. ObjectId originHeadId = clonedRepo.resolve("refs/remotes/origin/HEAD");
  281. if (originHeadId == null) {
  282. JGitTestUtil.write(
  283. new File(clonedRepo.getDirectory(),
  284. "refs/remotes/origin/HEAD"),
  285. "ref: refs/remotes/origin/master\n");
  286. originHeadId = clonedRepo.resolve("refs/remotes/origin/HEAD");
  287. }
  288. assertEquals("Should have origin/HEAD", originMasterId, originHeadId);
  289. FetchResult result = cloned.fetch().setRemote("origin")
  290. .setRemoveDeletedRefs(true).call();
  291. assertTrue("Fetch after clone should be up-to-date",
  292. result.getTrackingRefUpdates().isEmpty());
  293. assertEquals("origin/master should still exist", originMasterId,
  294. clonedRepo.resolve("refs/remotes/origin/master"));
  295. assertEquals("origin/HEAD should be unchanged", originHeadId,
  296. clonedRepo.resolve("refs/remotes/origin/HEAD"));
  297. }
  298. @Test
  299. public void fetchAddRefsWithDuplicateRefspec() throws Exception {
  300. final String branchName = "branch";
  301. final String remoteBranchName = "test/" + branchName;
  302. remoteGit.commit().setMessage("commit").call();
  303. Ref branchRef = remoteGit.branchCreate().setName(branchName).call();
  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. git.fetch().setRemote("test").setRefSpecs(spec1).call();
  312. assertEquals(branchRef.getObjectId(), db.resolve(remoteBranchName));
  313. }
  314. @Test
  315. public void fetchPruneRefsWithDuplicateRefspec()
  316. throws Exception {
  317. final String branchName = "branch";
  318. final String remoteBranchName = "test/" + branchName;
  319. remoteGit.commit().setMessage("commit").call();
  320. Ref branchRef = remoteGit.branchCreate().setName(branchName).call();
  321. final String spec1 = "+refs/heads/*:refs/remotes/test/*";
  322. final String spec2 = "refs/heads/*:refs/remotes/test/*";
  323. final StoredConfig config = db.getConfig();
  324. RemoteConfig remoteConfig = new RemoteConfig(config, "test");
  325. remoteConfig.addFetchRefSpec(new RefSpec(spec1));
  326. remoteConfig.addFetchRefSpec(new RefSpec(spec2));
  327. remoteConfig.update(config);
  328. git.fetch().setRemote("test").setRefSpecs(spec1).call();
  329. assertEquals(branchRef.getObjectId(), db.resolve(remoteBranchName));
  330. remoteGit.branchDelete().setBranchNames(branchName).call();
  331. git.fetch().setRemote("test").setRefSpecs(spec1)
  332. .setRemoveDeletedRefs(true).call();
  333. assertNull(db.resolve(remoteBranchName));
  334. }
  335. @Test
  336. public void fetchUpdateRefsWithDuplicateRefspec() throws Exception {
  337. final String tagName = "foo";
  338. remoteGit.commit().setMessage("commit").call();
  339. Ref tagRef1 = remoteGit.tag().setName(tagName).call();
  340. List<RefSpec> refSpecs = new ArrayList<>();
  341. refSpecs.add(new RefSpec("+refs/heads/*:refs/remotes/origin/*"));
  342. refSpecs.add(new RefSpec("+refs/tags/*:refs/tags/*"));
  343. // Updating tags via the RefSpecs and setting TagOpt.FETCH_TAGS (or
  344. // AUTO_FOLLOW) will result internally in *two* updates for the same
  345. // ref.
  346. git.fetch().setRemote("test").setRefSpecs(refSpecs)
  347. .setTagOpt(TagOpt.AUTO_FOLLOW).call();
  348. assertEquals(tagRef1.getObjectId(), db.resolve(tagName));
  349. remoteGit.commit().setMessage("commit 2").call();
  350. Ref tagRef2 = remoteGit.tag().setName(tagName).setForceUpdate(true)
  351. .call();
  352. FetchResult result = git.fetch().setRemote("test").setRefSpecs(refSpecs)
  353. .setTagOpt(TagOpt.FETCH_TAGS).call();
  354. assertEquals(2, result.getTrackingRefUpdates().size());
  355. TrackingRefUpdate update = result
  356. .getTrackingRefUpdate(Constants.R_TAGS + tagName);
  357. assertEquals(RefUpdate.Result.FORCED, update.getResult());
  358. assertEquals(tagRef2.getObjectId(), db.resolve(tagName));
  359. }
  360. }