您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

CloneCommandTest.java 19KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. /*
  2. * Copyright (C) 2011, 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.assertFalse;
  46. import static org.junit.Assert.assertNotNull;
  47. import static org.junit.Assert.assertTrue;
  48. import static org.junit.Assert.fail;
  49. import java.io.File;
  50. import java.io.IOException;
  51. import java.net.URISyntaxException;
  52. import java.util.Collections;
  53. import java.util.List;
  54. import java.util.Map;
  55. import org.eclipse.jgit.api.ListBranchCommand.ListMode;
  56. import org.eclipse.jgit.api.errors.GitAPIException;
  57. import org.eclipse.jgit.api.errors.JGitInternalException;
  58. import org.eclipse.jgit.junit.RepositoryTestCase;
  59. import org.eclipse.jgit.junit.TestRepository;
  60. import org.eclipse.jgit.lib.ConfigConstants;
  61. import org.eclipse.jgit.lib.Constants;
  62. import org.eclipse.jgit.lib.ObjectId;
  63. import org.eclipse.jgit.lib.Ref;
  64. import org.eclipse.jgit.lib.Repository;
  65. import org.eclipse.jgit.revwalk.RevBlob;
  66. import org.eclipse.jgit.revwalk.RevCommit;
  67. import org.eclipse.jgit.storage.file.FileBasedConfig;
  68. import org.eclipse.jgit.submodule.SubmoduleStatus;
  69. import org.eclipse.jgit.submodule.SubmoduleStatusType;
  70. import org.eclipse.jgit.submodule.SubmoduleWalk;
  71. import org.eclipse.jgit.transport.RefSpec;
  72. import org.eclipse.jgit.transport.RemoteConfig;
  73. import org.eclipse.jgit.util.SystemReader;
  74. import org.junit.Test;
  75. public class CloneCommandTest extends RepositoryTestCase {
  76. private Git git;
  77. private TestRepository<Repository> tr;
  78. public void setUp() throws Exception {
  79. super.setUp();
  80. tr = new TestRepository<Repository>(db);
  81. git = new Git(db);
  82. // commit something
  83. writeTrashFile("Test.txt", "Hello world");
  84. git.add().addFilepattern("Test.txt").call();
  85. git.commit().setMessage("Initial commit").call();
  86. git.tag().setName("tag-initial").setMessage("Tag initial").call();
  87. // create a test branch and switch to it
  88. git.checkout().setCreateBranch(true).setName("test").call();
  89. // commit something on the test branch
  90. writeTrashFile("Test.txt", "Some change");
  91. git.add().addFilepattern("Test.txt").call();
  92. git.commit().setMessage("Second commit").call();
  93. RevBlob blob = tr.blob("blob-not-in-master-branch");
  94. git.tag().setName("tag-for-blob").setObjectId(blob).call();
  95. }
  96. @Test
  97. public void testCloneRepository() throws IOException,
  98. JGitInternalException, GitAPIException, URISyntaxException {
  99. File directory = createTempDirectory("testCloneRepository");
  100. CloneCommand command = Git.cloneRepository();
  101. command.setDirectory(directory);
  102. command.setURI("file://" + git.getRepository().getWorkTree().getPath());
  103. Git git2 = command.call();
  104. addRepoToClose(git2.getRepository());
  105. assertNotNull(git2);
  106. ObjectId id = git2.getRepository().resolve("tag-for-blob");
  107. assertNotNull(id);
  108. assertEquals(git2.getRepository().getFullBranch(), "refs/heads/test");
  109. assertEquals(
  110. "origin",
  111. git2.getRepository()
  112. .getConfig()
  113. .getString(ConfigConstants.CONFIG_BRANCH_SECTION,
  114. "test", ConfigConstants.CONFIG_KEY_REMOTE));
  115. assertEquals(
  116. "refs/heads/test",
  117. git2.getRepository()
  118. .getConfig()
  119. .getString(ConfigConstants.CONFIG_BRANCH_SECTION,
  120. "test", ConfigConstants.CONFIG_KEY_MERGE));
  121. assertEquals(2, git2.branchList().setListMode(ListMode.REMOTE).call()
  122. .size());
  123. assertEquals(new RefSpec("+refs/heads/*:refs/remotes/origin/*"),
  124. fetchRefSpec(git2.getRepository()));
  125. }
  126. @Test
  127. public void testBareCloneRepository() throws IOException,
  128. JGitInternalException, GitAPIException, URISyntaxException {
  129. File directory = createTempDirectory("testCloneRepository_bare");
  130. CloneCommand command = Git.cloneRepository();
  131. command.setBare(true);
  132. command.setDirectory(directory);
  133. command.setURI("file://" + git.getRepository().getWorkTree().getPath());
  134. Git git2 = command.call();
  135. addRepoToClose(git2.getRepository());
  136. assertEquals(new RefSpec("+refs/heads/*:refs/heads/*"),
  137. fetchRefSpec(git2.getRepository()));
  138. }
  139. public static RefSpec fetchRefSpec(Repository r) throws URISyntaxException {
  140. RemoteConfig remoteConfig =
  141. new RemoteConfig(r.getConfig(), Constants.DEFAULT_REMOTE_NAME);
  142. return remoteConfig.getFetchRefSpecs().get(0);
  143. }
  144. @Test
  145. public void testCloneRepositoryWithBranch() throws IOException,
  146. JGitInternalException, GitAPIException {
  147. File directory = createTempDirectory("testCloneRepositoryWithBranch");
  148. CloneCommand command = Git.cloneRepository();
  149. command.setBranch("refs/heads/master");
  150. command.setDirectory(directory);
  151. command.setURI("file://" + git.getRepository().getWorkTree().getPath());
  152. Git git2 = command.call();
  153. addRepoToClose(git2.getRepository());
  154. assertNotNull(git2);
  155. assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
  156. assertEquals(
  157. "refs/heads/master, refs/remotes/origin/master, refs/remotes/origin/test",
  158. allRefNames(git2.branchList().setListMode(ListMode.ALL).call()));
  159. // Same thing, but now without checkout
  160. directory = createTempDirectory("testCloneRepositoryWithBranch_bare");
  161. command = Git.cloneRepository();
  162. command.setBranch("refs/heads/master");
  163. command.setDirectory(directory);
  164. command.setURI("file://" + git.getRepository().getWorkTree().getPath());
  165. command.setNoCheckout(true);
  166. git2 = command.call();
  167. addRepoToClose(git2.getRepository());
  168. assertNotNull(git2);
  169. assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
  170. assertEquals("refs/remotes/origin/master, refs/remotes/origin/test",
  171. allRefNames(git2.branchList().setListMode(ListMode.ALL).call()));
  172. // Same thing, but now test with bare repo
  173. directory = createTempDirectory("testCloneRepositoryWithBranch_bare");
  174. command = Git.cloneRepository();
  175. command.setBranch("refs/heads/master");
  176. command.setDirectory(directory);
  177. command.setURI("file://" + git.getRepository().getWorkTree().getPath());
  178. command.setBare(true);
  179. git2 = command.call();
  180. addRepoToClose(git2.getRepository());
  181. assertNotNull(git2);
  182. assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
  183. assertEquals("refs/heads/master, refs/heads/test", allRefNames(git2
  184. .branchList().setListMode(ListMode.ALL).call()));
  185. }
  186. @Test
  187. public void testCloneRepositoryWithBranchShortName() throws Exception {
  188. File directory = createTempDirectory("testCloneRepositoryWithBranch");
  189. CloneCommand command = Git.cloneRepository();
  190. command.setBranch("test");
  191. command.setDirectory(directory);
  192. command.setURI("file://" + git.getRepository().getWorkTree().getPath());
  193. Git git2 = command.call();
  194. addRepoToClose(git2.getRepository());
  195. assertNotNull(git2);
  196. assertEquals("refs/heads/test", git2.getRepository().getFullBranch());
  197. }
  198. @Test
  199. public void testCloneRepositoryWithTagName() throws Exception {
  200. File directory = createTempDirectory("testCloneRepositoryWithBranch");
  201. CloneCommand command = Git.cloneRepository();
  202. command.setBranch("tag-initial");
  203. command.setDirectory(directory);
  204. command.setURI("file://" + git.getRepository().getWorkTree().getPath());
  205. Git git2 = command.call();
  206. addRepoToClose(git2.getRepository());
  207. assertNotNull(git2);
  208. ObjectId taggedCommit = db.resolve("tag-initial^{commit}");
  209. assertEquals(taggedCommit.name(), git2
  210. .getRepository().getFullBranch());
  211. }
  212. @Test
  213. public void testCloneRepositoryOnlyOneBranch() throws IOException,
  214. JGitInternalException, GitAPIException {
  215. File directory = createTempDirectory("testCloneRepositoryWithBranch");
  216. CloneCommand command = Git.cloneRepository();
  217. command.setBranch("refs/heads/master");
  218. command.setBranchesToClone(Collections
  219. .singletonList("refs/heads/master"));
  220. command.setDirectory(directory);
  221. command.setURI("file://" + git.getRepository().getWorkTree().getPath());
  222. Git git2 = command.call();
  223. addRepoToClose(git2.getRepository());
  224. assertNotNull(git2);
  225. assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
  226. assertEquals("refs/remotes/origin/master", allRefNames(git2
  227. .branchList().setListMode(ListMode.REMOTE).call()));
  228. // Same thing, but now test with bare repo
  229. directory = createTempDirectory("testCloneRepositoryWithBranch_bare");
  230. command = Git.cloneRepository();
  231. command.setBranch("refs/heads/master");
  232. command.setBranchesToClone(Collections
  233. .singletonList("refs/heads/master"));
  234. command.setDirectory(directory);
  235. command.setURI("file://" + git.getRepository().getWorkTree().getPath());
  236. command.setBare(true);
  237. git2 = command.call();
  238. addRepoToClose(git2.getRepository());
  239. assertNotNull(git2);
  240. assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
  241. assertEquals("refs/heads/master", allRefNames(git2.branchList()
  242. .setListMode(ListMode.ALL).call()));
  243. }
  244. public static String allRefNames(List<Ref> refs) {
  245. StringBuilder sb = new StringBuilder();
  246. for (Ref f : refs) {
  247. if (sb.length() > 0)
  248. sb.append(", ");
  249. sb.append(f.getName());
  250. }
  251. return sb.toString();
  252. }
  253. @Test
  254. public void testCloneRepositoryWhenDestinationDirectoryExistsAndIsNotEmpty()
  255. throws IOException, JGitInternalException, GitAPIException {
  256. String dirName = "testCloneTargetDirectoryNotEmpty";
  257. File directory = createTempDirectory(dirName);
  258. CloneCommand command = Git.cloneRepository();
  259. command.setDirectory(directory);
  260. command.setURI("file://" + git.getRepository().getWorkTree().getPath());
  261. Git git2 = command.call();
  262. addRepoToClose(git2.getRepository());
  263. assertNotNull(git2);
  264. // clone again
  265. command = Git.cloneRepository();
  266. command.setDirectory(directory);
  267. command.setURI("file://" + git.getRepository().getWorkTree().getPath());
  268. try {
  269. git2 = command.call();
  270. // we shouldn't get here
  271. fail("destination directory already exists and is not an empty folder, cloning should fail");
  272. } catch (JGitInternalException e) {
  273. assertTrue(e.getMessage().contains("not an empty directory"));
  274. assertTrue(e.getMessage().contains(dirName));
  275. }
  276. }
  277. @Test
  278. public void testCloneRepositoryWithMultipleHeadBranches() throws Exception {
  279. git.checkout().setName(Constants.MASTER).call();
  280. git.branchCreate().setName("a").call();
  281. File directory = createTempDirectory("testCloneRepositoryWithMultipleHeadBranches");
  282. CloneCommand clone = Git.cloneRepository();
  283. clone.setDirectory(directory);
  284. clone.setURI("file://" + git.getRepository().getWorkTree().getPath());
  285. Git git2 = clone.call();
  286. addRepoToClose(git2.getRepository());
  287. assertNotNull(git2);
  288. assertEquals(Constants.MASTER, git2.getRepository().getBranch());
  289. }
  290. @Test
  291. public void testCloneRepositoryWithSubmodules() throws Exception {
  292. git.checkout().setName(Constants.MASTER).call();
  293. String file = "file.txt";
  294. writeTrashFile(file, "content");
  295. git.add().addFilepattern(file).call();
  296. RevCommit commit = git.commit().setMessage("create file").call();
  297. SubmoduleAddCommand command = new SubmoduleAddCommand(db);
  298. String path = "sub";
  299. command.setPath(path);
  300. String uri = db.getDirectory().toURI().toString();
  301. command.setURI(uri);
  302. Repository repo = command.call();
  303. assertNotNull(repo);
  304. addRepoToClose(repo);
  305. git.add().addFilepattern(path)
  306. .addFilepattern(Constants.DOT_GIT_MODULES).call();
  307. git.commit().setMessage("adding submodule").call();
  308. File directory = createTempDirectory("testCloneRepositoryWithSubmodules");
  309. CloneCommand clone = Git.cloneRepository();
  310. clone.setDirectory(directory);
  311. clone.setCloneSubmodules(true);
  312. clone.setURI("file://" + git.getRepository().getWorkTree().getPath());
  313. Git git2 = clone.call();
  314. addRepoToClose(git2.getRepository());
  315. assertNotNull(git2);
  316. assertEquals(Constants.MASTER, git2.getRepository().getBranch());
  317. assertTrue(new File(git2.getRepository().getWorkTree(), path
  318. + File.separatorChar + file).exists());
  319. SubmoduleStatusCommand status = new SubmoduleStatusCommand(
  320. git2.getRepository());
  321. Map<String, SubmoduleStatus> statuses = status.call();
  322. SubmoduleStatus pathStatus = statuses.get(path);
  323. assertNotNull(pathStatus);
  324. assertEquals(SubmoduleStatusType.INITIALIZED, pathStatus.getType());
  325. assertEquals(commit, pathStatus.getHeadId());
  326. assertEquals(commit, pathStatus.getIndexId());
  327. }
  328. @Test
  329. public void testCloneRepositoryWithNestedSubmodules() throws Exception {
  330. git.checkout().setName(Constants.MASTER).call();
  331. // Create submodule 1
  332. File submodule1 = createTempDirectory("testCloneRepositoryWithNestedSubmodules1");
  333. Git sub1Git = Git.init().setDirectory(submodule1).call();
  334. assertNotNull(sub1Git);
  335. Repository sub1 = sub1Git.getRepository();
  336. assertNotNull(sub1);
  337. addRepoToClose(sub1);
  338. String file = "file.txt";
  339. String path = "sub";
  340. write(new File(sub1.getWorkTree(), file), "content");
  341. sub1Git.add().addFilepattern(file).call();
  342. RevCommit commit = sub1Git.commit().setMessage("create file").call();
  343. assertNotNull(commit);
  344. // Create submodule 2
  345. File submodule2 = createTempDirectory("testCloneRepositoryWithNestedSubmodules2");
  346. Git sub2Git = Git.init().setDirectory(submodule2).call();
  347. assertNotNull(sub2Git);
  348. Repository sub2 = sub2Git.getRepository();
  349. assertNotNull(sub2);
  350. addRepoToClose(sub2);
  351. write(new File(sub2.getWorkTree(), file), "content");
  352. sub2Git.add().addFilepattern(file).call();
  353. RevCommit sub2Head = sub2Git.commit().setMessage("create file").call();
  354. assertNotNull(sub2Head);
  355. // Add submodule 2 to submodule 1
  356. Repository r = sub1Git.submoduleAdd().setPath(path)
  357. .setURI(sub2.getDirectory().toURI().toString()).call();
  358. assertNotNull(r);
  359. addRepoToClose(r);
  360. RevCommit sub1Head = sub1Git.commit().setAll(true)
  361. .setMessage("Adding submodule").call();
  362. assertNotNull(sub1Head);
  363. // Add submodule 1 to default repository
  364. r = git.submoduleAdd().setPath(path)
  365. .setURI(sub1.getDirectory().toURI().toString()).call();
  366. assertNotNull(r);
  367. addRepoToClose(r);
  368. assertNotNull(git.commit().setAll(true).setMessage("Adding submodule")
  369. .call());
  370. // Clone default repository and include submodules
  371. File directory = createTempDirectory("testCloneRepositoryWithNestedSubmodules");
  372. CloneCommand clone = Git.cloneRepository();
  373. clone.setDirectory(directory);
  374. clone.setCloneSubmodules(true);
  375. clone.setURI(git.getRepository().getDirectory().toURI().toString());
  376. Git git2 = clone.call();
  377. addRepoToClose(git2.getRepository());
  378. assertNotNull(git2);
  379. assertEquals(Constants.MASTER, git2.getRepository().getBranch());
  380. assertTrue(new File(git2.getRepository().getWorkTree(), path
  381. + File.separatorChar + file).exists());
  382. assertTrue(new File(git2.getRepository().getWorkTree(), path
  383. + File.separatorChar + path + File.separatorChar + file)
  384. .exists());
  385. SubmoduleStatusCommand status = new SubmoduleStatusCommand(
  386. git2.getRepository());
  387. Map<String, SubmoduleStatus> statuses = status.call();
  388. SubmoduleStatus pathStatus = statuses.get(path);
  389. assertNotNull(pathStatus);
  390. assertEquals(SubmoduleStatusType.INITIALIZED, pathStatus.getType());
  391. assertEquals(sub1Head, pathStatus.getHeadId());
  392. assertEquals(sub1Head, pathStatus.getIndexId());
  393. SubmoduleWalk walk = SubmoduleWalk.forIndex(git2.getRepository());
  394. assertTrue(walk.next());
  395. Repository clonedSub1 = walk.getRepository();
  396. addRepoToClose(clonedSub1);
  397. assertNotNull(clonedSub1);
  398. status = new SubmoduleStatusCommand(clonedSub1);
  399. statuses = status.call();
  400. pathStatus = statuses.get(path);
  401. assertNotNull(pathStatus);
  402. assertEquals(SubmoduleStatusType.INITIALIZED, pathStatus.getType());
  403. assertEquals(sub2Head, pathStatus.getHeadId());
  404. assertEquals(sub2Head, pathStatus.getIndexId());
  405. assertFalse(walk.next());
  406. }
  407. @Test
  408. public void testCloneWithAutoSetupRebase() throws Exception {
  409. File directory = createTempDirectory("testCloneRepository1");
  410. CloneCommand command = Git.cloneRepository();
  411. command.setDirectory(directory);
  412. command.setURI("file://" + git.getRepository().getWorkTree().getPath());
  413. Git git2 = command.call();
  414. addRepoToClose(git2.getRepository());
  415. assertFalse(git2
  416. .getRepository()
  417. .getConfig()
  418. .getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION, "test",
  419. ConfigConstants.CONFIG_KEY_REBASE, false));
  420. FileBasedConfig userConfig = SystemReader.getInstance().openUserConfig(
  421. null, git.getRepository().getFS());
  422. userConfig.setString(ConfigConstants.CONFIG_BRANCH_SECTION, null,
  423. ConfigConstants.CONFIG_KEY_AUTOSETUPREBASE,
  424. ConfigConstants.CONFIG_KEY_ALWAYS);
  425. userConfig.save();
  426. directory = createTempDirectory("testCloneRepository2");
  427. command = Git.cloneRepository();
  428. command.setDirectory(directory);
  429. command.setURI("file://" + git.getRepository().getWorkTree().getPath());
  430. git2 = command.call();
  431. addRepoToClose(git2.getRepository());
  432. assertTrue(git2
  433. .getRepository()
  434. .getConfig()
  435. .getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION, "test",
  436. ConfigConstants.CONFIG_KEY_REBASE, false));
  437. userConfig.setString(ConfigConstants.CONFIG_BRANCH_SECTION, null,
  438. ConfigConstants.CONFIG_KEY_AUTOSETUPREBASE,
  439. ConfigConstants.CONFIG_KEY_REMOTE);
  440. userConfig.save();
  441. directory = createTempDirectory("testCloneRepository2");
  442. command = Git.cloneRepository();
  443. command.setDirectory(directory);
  444. command.setURI("file://" + git.getRepository().getWorkTree().getPath());
  445. git2 = command.call();
  446. addRepoToClose(git2.getRepository());
  447. assertTrue(git2
  448. .getRepository()
  449. .getConfig()
  450. .getBoolean(ConfigConstants.CONFIG_BRANCH_SECTION, "test",
  451. ConfigConstants.CONFIG_KEY_REBASE, false));
  452. }
  453. }