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.

CloneCommandTest.java 32KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  1. /*
  2. * Copyright (C) 2011, 2013 Chris Aniszczyk <caniszczyk@gmail.com> and others
  3. *
  4. * This program and the accompanying materials are made available under the
  5. * terms of the Eclipse Distribution License v. 1.0 which is available at
  6. * https://www.eclipse.org/org/documents/edl-v10.php.
  7. *
  8. * SPDX-License-Identifier: BSD-3-Clause
  9. */
  10. package org.eclipse.jgit.api;
  11. import static org.junit.Assert.assertEquals;
  12. import static org.junit.Assert.assertFalse;
  13. import static org.junit.Assert.assertNotNull;
  14. import static org.junit.Assert.assertNull;
  15. import static org.junit.Assert.assertTrue;
  16. import static org.junit.Assert.fail;
  17. import java.io.File;
  18. import java.io.IOException;
  19. import java.net.URISyntaxException;
  20. import java.util.Collections;
  21. import java.util.List;
  22. import java.util.Map;
  23. import org.eclipse.jgit.api.ListBranchCommand.ListMode;
  24. import org.eclipse.jgit.api.errors.GitAPIException;
  25. import org.eclipse.jgit.api.errors.JGitInternalException;
  26. import org.eclipse.jgit.errors.NoWorkTreeException;
  27. import org.eclipse.jgit.junit.RepositoryTestCase;
  28. import org.eclipse.jgit.junit.TestRepository;
  29. import org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode;
  30. import org.eclipse.jgit.lib.ConfigConstants;
  31. import org.eclipse.jgit.lib.Constants;
  32. import org.eclipse.jgit.lib.ObjectId;
  33. import org.eclipse.jgit.lib.Ref;
  34. import org.eclipse.jgit.lib.RefUpdate;
  35. import org.eclipse.jgit.lib.Repository;
  36. import org.eclipse.jgit.lib.StoredConfig;
  37. import org.eclipse.jgit.revwalk.RevBlob;
  38. import org.eclipse.jgit.revwalk.RevCommit;
  39. import org.eclipse.jgit.submodule.SubmoduleStatus;
  40. import org.eclipse.jgit.submodule.SubmoduleStatusType;
  41. import org.eclipse.jgit.submodule.SubmoduleWalk;
  42. import org.eclipse.jgit.transport.RefSpec;
  43. import org.eclipse.jgit.transport.RemoteConfig;
  44. import org.eclipse.jgit.transport.TagOpt;
  45. import org.eclipse.jgit.transport.URIish;
  46. import org.eclipse.jgit.util.SystemReader;
  47. import org.junit.Test;
  48. public class CloneCommandTest extends RepositoryTestCase {
  49. private Git git;
  50. private TestRepository<Repository> tr;
  51. @Override
  52. public void setUp() throws Exception {
  53. super.setUp();
  54. tr = new TestRepository<>(db);
  55. git = new Git(db);
  56. // commit something
  57. writeTrashFile("Test.txt", "Hello world");
  58. git.add().addFilepattern("Test.txt").call();
  59. git.commit().setMessage("Initial commit").call();
  60. Ref head = git.tag().setName("tag-initial").setMessage("Tag initial")
  61. .call();
  62. // create a test branch and switch to it
  63. git.checkout().setCreateBranch(true).setName("test").call();
  64. // create a non-standard ref
  65. RefUpdate ru = db.updateRef("refs/meta/foo/bar");
  66. ru.setNewObjectId(head.getObjectId());
  67. ru.update();
  68. // commit something on the test branch
  69. writeTrashFile("Test.txt", "Some change");
  70. git.add().addFilepattern("Test.txt").call();
  71. git.commit().setMessage("Second commit").call();
  72. RevBlob blob = tr.blob("blob-not-in-master-branch");
  73. git.tag().setName("tag-for-blob").setObjectId(blob).call();
  74. }
  75. @Test
  76. public void testCloneRepository() throws IOException,
  77. JGitInternalException, GitAPIException, URISyntaxException {
  78. File directory = createTempDirectory("testCloneRepository");
  79. CloneCommand command = Git.cloneRepository();
  80. command.setDirectory(directory);
  81. command.setURI(fileUri());
  82. Git git2 = command.call();
  83. addRepoToClose(git2.getRepository());
  84. ObjectId id = git2.getRepository().resolve("tag-for-blob");
  85. assertNotNull(id);
  86. assertEquals(git2.getRepository().getFullBranch(), "refs/heads/test");
  87. assertEquals(
  88. "origin",
  89. git2.getRepository()
  90. .getConfig()
  91. .getString(ConfigConstants.CONFIG_BRANCH_SECTION,
  92. "test", ConfigConstants.CONFIG_KEY_REMOTE));
  93. assertEquals(
  94. "refs/heads/test",
  95. git2.getRepository()
  96. .getConfig()
  97. .getString(ConfigConstants.CONFIG_BRANCH_SECTION,
  98. "test", ConfigConstants.CONFIG_KEY_MERGE));
  99. assertEquals(2, git2.branchList().setListMode(ListMode.REMOTE).call()
  100. .size());
  101. assertEquals(new RefSpec("+refs/heads/*:refs/remotes/origin/*"),
  102. fetchRefSpec(git2.getRepository()));
  103. assertTagOption(git2.getRepository(), TagOpt.AUTO_FOLLOW);
  104. }
  105. @Test
  106. public void testCloneRepositoryExplicitGitDir() throws IOException,
  107. JGitInternalException, GitAPIException {
  108. File directory = createTempDirectory("testCloneRepository");
  109. CloneCommand command = Git.cloneRepository();
  110. command.setDirectory(directory);
  111. command.setGitDir(new File(directory, Constants.DOT_GIT));
  112. command.setURI(fileUri());
  113. Git git2 = command.call();
  114. addRepoToClose(git2.getRepository());
  115. assertEquals(directory, git2.getRepository().getWorkTree());
  116. assertEquals(new File(directory, Constants.DOT_GIT), git2.getRepository()
  117. .getDirectory());
  118. }
  119. @Test
  120. public void testCloneRepositoryDefaultDirectory()
  121. throws URISyntaxException, JGitInternalException {
  122. CloneCommand command = Git.cloneRepository().setURI(fileUri());
  123. command.verifyDirectories(new URIish(fileUri()));
  124. File directory = command.getDirectory();
  125. assertEquals(git.getRepository().getWorkTree().getName(), directory.getName());
  126. }
  127. @Test
  128. public void testCloneBareRepositoryDefaultDirectory()
  129. throws URISyntaxException, JGitInternalException {
  130. CloneCommand command = Git.cloneRepository().setURI(fileUri()).setBare(true);
  131. command.verifyDirectories(new URIish(fileUri()));
  132. File directory = command.getDirectory();
  133. assertEquals(git.getRepository().getWorkTree().getName() + Constants.DOT_GIT_EXT, directory.getName());
  134. }
  135. @Test
  136. public void testCloneRepositoryExplicitGitDirNonStd() throws IOException,
  137. JGitInternalException, GitAPIException {
  138. File directory = createTempDirectory("testCloneRepository");
  139. File gDir = createTempDirectory("testCloneRepository.git");
  140. CloneCommand command = Git.cloneRepository();
  141. command.setDirectory(directory);
  142. command.setGitDir(gDir);
  143. command.setURI(fileUri());
  144. Git git2 = command.call();
  145. addRepoToClose(git2.getRepository());
  146. assertEquals(directory, git2.getRepository().getWorkTree());
  147. assertEquals(gDir, git2.getRepository()
  148. .getDirectory());
  149. assertTrue(new File(directory, Constants.DOT_GIT).isFile());
  150. assertFalse(new File(gDir, Constants.DOT_GIT).exists());
  151. }
  152. @Test
  153. public void testCloneRepositoryExplicitGitDirBare() throws IOException,
  154. JGitInternalException, GitAPIException {
  155. File gDir = createTempDirectory("testCloneRepository.git");
  156. CloneCommand command = Git.cloneRepository();
  157. command.setBare(true);
  158. command.setGitDir(gDir);
  159. command.setURI(fileUri());
  160. Git git2 = command.call();
  161. addRepoToClose(git2.getRepository());
  162. try {
  163. assertNull(null, git2.getRepository().getWorkTree());
  164. fail("Expected NoWorkTreeException");
  165. } catch (NoWorkTreeException e) {
  166. assertEquals(gDir, git2.getRepository().getDirectory());
  167. }
  168. }
  169. @Test
  170. public void testBareCloneRepository() throws IOException,
  171. JGitInternalException, GitAPIException, URISyntaxException {
  172. File directory = createTempDirectory("testCloneRepository_bare");
  173. CloneCommand command = Git.cloneRepository();
  174. command.setBare(true);
  175. command.setDirectory(directory);
  176. command.setURI(fileUri());
  177. Git git2 = command.call();
  178. addRepoToClose(git2.getRepository());
  179. assertEquals(new RefSpec("+refs/heads/*:refs/heads/*"),
  180. fetchRefSpec(git2.getRepository()));
  181. }
  182. @Test
  183. public void testCloneRepositoryCustomRemote() throws Exception {
  184. File directory = createTempDirectory("testCloneRemoteUpstream");
  185. CloneCommand command = Git.cloneRepository();
  186. command.setDirectory(directory);
  187. command.setRemote("upstream");
  188. command.setURI(fileUri());
  189. Git git2 = command.call();
  190. addRepoToClose(git2.getRepository());
  191. assertEquals("+refs/heads/*:refs/remotes/upstream/*",
  192. git2.getRepository()
  193. .getConfig()
  194. .getStringList("remote", "upstream",
  195. "fetch")[0]);
  196. assertEquals("upstream",
  197. git2.getRepository()
  198. .getConfig()
  199. .getString("branch", "test", "remote"));
  200. assertEquals(db.resolve("test"),
  201. git2.getRepository().resolve("upstream/test"));
  202. }
  203. @Test
  204. public void testBareCloneRepositoryCustomRemote() throws Exception {
  205. File directory = createTempDirectory("testCloneRemoteUpstream_bare");
  206. CloneCommand command = Git.cloneRepository();
  207. command.setBare(true);
  208. command.setDirectory(directory);
  209. command.setRemote("upstream");
  210. command.setURI(fileUri());
  211. Git git2 = command.call();
  212. addRepoToClose(git2.getRepository());
  213. assertEquals("+refs/heads/*:refs/heads/*",
  214. git2.getRepository()
  215. .getConfig()
  216. .getStringList("remote", "upstream",
  217. "fetch")[0]);
  218. assertEquals("upstream",
  219. git2.getRepository()
  220. .getConfig()
  221. .getString("branch", "test", "remote"));
  222. assertNull(git2.getRepository().resolve("upstream/test"));
  223. }
  224. @Test
  225. public void testBareCloneRepositoryNullRemote() throws Exception {
  226. File directory = createTempDirectory("testCloneRemoteNull_bare");
  227. CloneCommand command = Git.cloneRepository();
  228. command.setBare(true);
  229. command.setDirectory(directory);
  230. command.setRemote(null);
  231. command.setURI(fileUri());
  232. Git git2 = command.call();
  233. addRepoToClose(git2.getRepository());
  234. assertEquals("+refs/heads/*:refs/heads/*", git2.getRepository()
  235. .getConfig().getStringList("remote", "origin", "fetch")[0]);
  236. assertEquals("origin", git2.getRepository().getConfig()
  237. .getString("branch", "test", "remote"));
  238. }
  239. public static RefSpec fetchRefSpec(Repository r) throws URISyntaxException {
  240. RemoteConfig remoteConfig =
  241. new RemoteConfig(r.getConfig(), Constants.DEFAULT_REMOTE_NAME);
  242. return remoteConfig.getFetchRefSpecs().get(0);
  243. }
  244. @Test
  245. public void testCloneRepositoryWithBranch() throws IOException,
  246. JGitInternalException, GitAPIException {
  247. File directory = createTempDirectory("testCloneRepositoryWithBranch");
  248. CloneCommand command = Git.cloneRepository();
  249. command.setBranch("refs/heads/master");
  250. command.setDirectory(directory);
  251. command.setURI(fileUri());
  252. Git git2 = command.call();
  253. addRepoToClose(git2.getRepository());
  254. assertEquals("refs/heads/master", git2.getRepository().getFullBranch());
  255. assertEquals(
  256. "refs/heads/master, refs/remotes/origin/master, refs/remotes/origin/test",
  257. allRefNames(git2.branchList().setListMode(ListMode.ALL).call()));
  258. // Same thing, but now without checkout
  259. directory = createTempDirectory("testCloneRepositoryWithBranch_bare");
  260. command = Git.cloneRepository();
  261. command.setBranch("refs/heads/master");
  262. command.setDirectory(directory);
  263. command.setURI(fileUri());
  264. command.setNoCheckout(true);
  265. git2 = command.call();
  266. addRepoToClose(git2.getRepository());
  267. assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
  268. assertEquals("refs/remotes/origin/master, refs/remotes/origin/test",
  269. allRefNames(git2.branchList().setListMode(ListMode.ALL).call()));
  270. // Same thing, but now test with bare repo
  271. directory = createTempDirectory("testCloneRepositoryWithBranch_bare");
  272. command = Git.cloneRepository();
  273. command.setBranch("refs/heads/master");
  274. command.setDirectory(directory);
  275. command.setURI(fileUri());
  276. command.setBare(true);
  277. git2 = command.call();
  278. addRepoToClose(git2.getRepository());
  279. assertEquals("refs/heads/master", git2.getRepository().getFullBranch());
  280. assertEquals("refs/heads/master, refs/heads/test", allRefNames(git2
  281. .branchList().setListMode(ListMode.ALL).call()));
  282. }
  283. @Test
  284. public void testCloneRepositoryWithBranchShortName() throws Exception {
  285. File directory = createTempDirectory("testCloneRepositoryWithBranch");
  286. CloneCommand command = Git.cloneRepository();
  287. command.setBranch("test");
  288. command.setDirectory(directory);
  289. command.setURI(fileUri());
  290. Git git2 = command.call();
  291. addRepoToClose(git2.getRepository());
  292. assertEquals("refs/heads/test", git2.getRepository().getFullBranch());
  293. }
  294. @Test
  295. public void testCloneRepositoryWithTagName() throws Exception {
  296. File directory = createTempDirectory("testCloneRepositoryWithBranch");
  297. CloneCommand command = Git.cloneRepository();
  298. command.setBranch("tag-initial");
  299. command.setDirectory(directory);
  300. command.setURI(fileUri());
  301. Git git2 = command.call();
  302. addRepoToClose(git2.getRepository());
  303. ObjectId taggedCommit = db.resolve("tag-initial^{commit}");
  304. assertEquals(taggedCommit.name(), git2
  305. .getRepository().getFullBranch());
  306. }
  307. @Test
  308. public void testCloneRepositoryOnlyOneBranch() throws Exception {
  309. File directory = createTempDirectory("testCloneRepositoryWithBranch");
  310. CloneCommand command = Git.cloneRepository();
  311. command.setBranch("refs/heads/master");
  312. command.setBranchesToClone(Collections
  313. .singletonList("refs/heads/master"));
  314. command.setDirectory(directory);
  315. command.setURI(fileUri());
  316. Git git2 = command.call();
  317. addRepoToClose(git2.getRepository());
  318. assertNull(git2.getRepository().resolve("tag-for-blob"));
  319. assertNotNull(git2.getRepository().resolve("tag-initial"));
  320. assertEquals("refs/heads/master", git2.getRepository().getFullBranch());
  321. assertEquals("refs/remotes/origin/master", allRefNames(git2
  322. .branchList().setListMode(ListMode.REMOTE).call()));
  323. RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
  324. Constants.DEFAULT_REMOTE_NAME);
  325. List<RefSpec> specs = cfg.getFetchRefSpecs();
  326. assertEquals(1, specs.size());
  327. assertEquals(
  328. new RefSpec("+refs/heads/master:refs/remotes/origin/master"),
  329. specs.get(0));
  330. }
  331. @Test
  332. public void testBareCloneRepositoryOnlyOneBranch() throws Exception {
  333. File directory = createTempDirectory(
  334. "testCloneRepositoryWithBranch_bare");
  335. CloneCommand command = Git.cloneRepository();
  336. command.setBranch("refs/heads/master");
  337. command.setBranchesToClone(Collections
  338. .singletonList("refs/heads/master"));
  339. command.setDirectory(directory);
  340. command.setURI(fileUri());
  341. command.setBare(true);
  342. Git git2 = command.call();
  343. addRepoToClose(git2.getRepository());
  344. assertNull(git2.getRepository().resolve("tag-for-blob"));
  345. assertNotNull(git2.getRepository().resolve("tag-initial"));
  346. assertEquals("refs/heads/master", git2.getRepository().getFullBranch());
  347. assertEquals("refs/heads/master", allRefNames(git2.branchList()
  348. .setListMode(ListMode.ALL).call()));
  349. RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
  350. Constants.DEFAULT_REMOTE_NAME);
  351. List<RefSpec> specs = cfg.getFetchRefSpecs();
  352. assertEquals(1, specs.size());
  353. assertEquals(
  354. new RefSpec("+refs/heads/master:refs/heads/master"),
  355. specs.get(0));
  356. }
  357. @Test
  358. public void testBareCloneRepositoryMirror() throws Exception {
  359. File directory = createTempDirectory(
  360. "testCloneRepositoryWithBranch_mirror");
  361. CloneCommand command = Git.cloneRepository();
  362. command.setBranch("refs/heads/master");
  363. command.setMirror(true); // implies bare repository
  364. command.setDirectory(directory);
  365. command.setURI(fileUri());
  366. Git git2 = command.call();
  367. addRepoToClose(git2.getRepository());
  368. assertTrue(git2.getRepository().isBare());
  369. assertNotNull(git2.getRepository().resolve("tag-for-blob"));
  370. assertNotNull(git2.getRepository().resolve("tag-initial"));
  371. assertEquals("refs/heads/master", git2.getRepository().getFullBranch());
  372. assertEquals("refs/heads/master, refs/heads/test", allRefNames(
  373. git2.branchList().setListMode(ListMode.ALL).call()));
  374. assertNotNull(git2.getRepository().exactRef("refs/meta/foo/bar"));
  375. RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
  376. Constants.DEFAULT_REMOTE_NAME);
  377. List<RefSpec> specs = cfg.getFetchRefSpecs();
  378. assertEquals(1, specs.size());
  379. assertEquals(new RefSpec("+refs/*:refs/*"),
  380. specs.get(0));
  381. }
  382. @Test
  383. public void testCloneRepositoryOnlyOneTag() throws Exception {
  384. File directory = createTempDirectory("testCloneRepositoryWithBranch");
  385. CloneCommand command = Git.cloneRepository();
  386. command.setBranch("tag-initial");
  387. command.setBranchesToClone(
  388. Collections.singletonList("refs/tags/tag-initial"));
  389. command.setDirectory(directory);
  390. command.setURI(fileUri());
  391. Git git2 = command.call();
  392. addRepoToClose(git2.getRepository());
  393. assertNull(git2.getRepository().resolve("tag-for-blob"));
  394. assertNull(git2.getRepository().resolve("refs/heads/master"));
  395. assertNotNull(git2.getRepository().resolve("tag-initial"));
  396. ObjectId taggedCommit = db.resolve("tag-initial^{commit}");
  397. assertEquals(taggedCommit.name(), git2.getRepository().getFullBranch());
  398. RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
  399. Constants.DEFAULT_REMOTE_NAME);
  400. List<RefSpec> specs = cfg.getFetchRefSpecs();
  401. assertEquals(1, specs.size());
  402. assertEquals(
  403. new RefSpec("+refs/tags/tag-initial:refs/tags/tag-initial"),
  404. specs.get(0));
  405. }
  406. @Test
  407. public void testCloneRepositoryAllBranchesTakesPreference()
  408. throws Exception {
  409. File directory = createTempDirectory(
  410. "testCloneRepositoryAllBranchesTakesPreference");
  411. CloneCommand command = Git.cloneRepository();
  412. command.setCloneAllBranches(true);
  413. command.setBranchesToClone(
  414. Collections.singletonList("refs/heads/test"));
  415. command.setDirectory(directory);
  416. command.setURI(fileUri());
  417. Git git2 = command.call();
  418. addRepoToClose(git2.getRepository());
  419. assertEquals("refs/heads/test", git2.getRepository().getFullBranch());
  420. // Expect both remote branches to exist; setCloneAllBranches(true)
  421. // should override any setBranchesToClone().
  422. assertNotNull(
  423. git2.getRepository().resolve("refs/remotes/origin/master"));
  424. assertNotNull(git2.getRepository().resolve("refs/remotes/origin/test"));
  425. RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
  426. Constants.DEFAULT_REMOTE_NAME);
  427. List<RefSpec> specs = cfg.getFetchRefSpecs();
  428. assertEquals(1, specs.size());
  429. assertEquals(new RefSpec("+refs/heads/*:refs/remotes/origin/*"),
  430. specs.get(0));
  431. }
  432. @Test
  433. public void testCloneRepositoryAllBranchesIndependent() throws Exception {
  434. File directory = createTempDirectory(
  435. "testCloneRepositoryAllBranchesIndependent");
  436. CloneCommand command = Git.cloneRepository();
  437. command.setCloneAllBranches(true);
  438. command.setBranchesToClone(
  439. Collections.singletonList("refs/heads/test"));
  440. command.setCloneAllBranches(false);
  441. command.setDirectory(directory);
  442. command.setURI(fileUri());
  443. Git git2 = command.call();
  444. addRepoToClose(git2.getRepository());
  445. assertEquals("refs/heads/test", git2.getRepository().getFullBranch());
  446. // Expect only the test branch; allBranches was re-set to false
  447. assertNull(git2.getRepository().resolve("refs/remotes/origin/master"));
  448. assertNotNull(git2.getRepository().resolve("refs/remotes/origin/test"));
  449. RemoteConfig cfg = new RemoteConfig(git2.getRepository().getConfig(),
  450. Constants.DEFAULT_REMOTE_NAME);
  451. List<RefSpec> specs = cfg.getFetchRefSpecs();
  452. assertEquals(1, specs.size());
  453. assertEquals(new RefSpec("+refs/heads/test:refs/remotes/origin/test"),
  454. specs.get(0));
  455. }
  456. public static String allRefNames(List<Ref> refs) {
  457. StringBuilder sb = new StringBuilder();
  458. for (Ref f : refs) {
  459. if (sb.length() > 0)
  460. sb.append(", ");
  461. sb.append(f.getName());
  462. }
  463. return sb.toString();
  464. }
  465. @Test
  466. public void testCloneRepositoryWhenDestinationDirectoryExistsAndIsNotEmpty()
  467. throws IOException, JGitInternalException, GitAPIException {
  468. String dirName = "testCloneTargetDirectoryNotEmpty";
  469. File directory = createTempDirectory(dirName);
  470. CloneCommand command = Git.cloneRepository();
  471. command.setDirectory(directory);
  472. command.setURI(fileUri());
  473. Git git2 = command.call();
  474. addRepoToClose(git2.getRepository());
  475. // clone again
  476. command = Git.cloneRepository();
  477. command.setDirectory(directory);
  478. command.setURI(fileUri());
  479. try {
  480. git2 = command.call();
  481. // we shouldn't get here
  482. fail("destination directory already exists and is not an empty folder, cloning should fail");
  483. } catch (JGitInternalException e) {
  484. assertTrue(e.getMessage().contains("not an empty directory"));
  485. assertTrue(e.getMessage().contains(dirName));
  486. }
  487. }
  488. @Test
  489. public void testCloneRepositoryWithMultipleHeadBranches() throws Exception {
  490. git.checkout().setName(Constants.MASTER).call();
  491. git.branchCreate().setName("a").call();
  492. File directory = createTempDirectory("testCloneRepositoryWithMultipleHeadBranches");
  493. CloneCommand clone = Git.cloneRepository();
  494. clone.setDirectory(directory);
  495. clone.setURI(fileUri());
  496. Git git2 = clone.call();
  497. addRepoToClose(git2.getRepository());
  498. assertEquals(Constants.MASTER, git2.getRepository().getBranch());
  499. }
  500. @Test
  501. public void testCloneRepositoryWithSubmodules() throws Exception {
  502. git.checkout().setName(Constants.MASTER).call();
  503. String file = "file.txt";
  504. writeTrashFile(file, "content");
  505. git.add().addFilepattern(file).call();
  506. RevCommit commit = git.commit().setMessage("create file").call();
  507. SubmoduleAddCommand command = new SubmoduleAddCommand(db);
  508. String path = "sub";
  509. command.setPath(path);
  510. String uri = db.getDirectory().toURI().toString();
  511. command.setURI(uri);
  512. Repository repo = command.call();
  513. assertNotNull(repo);
  514. addRepoToClose(repo);
  515. git.add().addFilepattern(path)
  516. .addFilepattern(Constants.DOT_GIT_MODULES).call();
  517. git.commit().setMessage("adding submodule").call();
  518. try (SubmoduleWalk walk = SubmoduleWalk.forIndex(git.getRepository())) {
  519. assertTrue(walk.next());
  520. Repository subRepo = walk.getRepository();
  521. addRepoToClose(subRepo);
  522. assertNotNull(subRepo);
  523. assertEquals(
  524. new File(git.getRepository().getWorkTree(), walk.getPath()),
  525. subRepo.getWorkTree());
  526. assertEquals(new File(new File(git.getRepository().getDirectory(),
  527. "modules"), walk.getPath()), subRepo.getDirectory());
  528. }
  529. File directory = createTempDirectory("testCloneRepositoryWithSubmodules");
  530. CloneCommand clone = Git.cloneRepository();
  531. clone.setDirectory(directory);
  532. clone.setCloneSubmodules(true);
  533. clone.setURI(fileUri());
  534. Git git2 = clone.call();
  535. addRepoToClose(git2.getRepository());
  536. assertEquals(Constants.MASTER, git2.getRepository().getBranch());
  537. assertTrue(new File(git2.getRepository().getWorkTree(), path
  538. + File.separatorChar + file).exists());
  539. SubmoduleStatusCommand status = new SubmoduleStatusCommand(
  540. git2.getRepository());
  541. Map<String, SubmoduleStatus> statuses = status.call();
  542. SubmoduleStatus pathStatus = statuses.get(path);
  543. assertNotNull(pathStatus);
  544. assertEquals(SubmoduleStatusType.INITIALIZED, pathStatus.getType());
  545. assertEquals(commit, pathStatus.getHeadId());
  546. assertEquals(commit, pathStatus.getIndexId());
  547. try (SubmoduleWalk walk = SubmoduleWalk
  548. .forIndex(git2.getRepository())) {
  549. assertTrue(walk.next());
  550. Repository clonedSub1 = walk.getRepository();
  551. addRepoToClose(clonedSub1);
  552. assertNotNull(clonedSub1);
  553. assertEquals(new File(git2.getRepository().getWorkTree(),
  554. walk.getPath()), clonedSub1.getWorkTree());
  555. assertEquals(
  556. new File(new File(git2.getRepository().getDirectory(),
  557. "modules"), walk.getPath()),
  558. clonedSub1.getDirectory());
  559. }
  560. }
  561. @Test
  562. public void testCloneRepositoryWithNestedSubmodules() throws Exception {
  563. git.checkout().setName(Constants.MASTER).call();
  564. // Create submodule 1
  565. File submodule1 = createTempDirectory("testCloneRepositoryWithNestedSubmodules1");
  566. Git sub1Git = Git.init().setDirectory(submodule1).call();
  567. assertNotNull(sub1Git);
  568. Repository sub1 = sub1Git.getRepository();
  569. assertNotNull(sub1);
  570. addRepoToClose(sub1);
  571. String file = "file.txt";
  572. String path = "sub";
  573. write(new File(sub1.getWorkTree(), file), "content");
  574. sub1Git.add().addFilepattern(file).call();
  575. RevCommit commit = sub1Git.commit().setMessage("create file").call();
  576. assertNotNull(commit);
  577. // Create submodule 2
  578. File submodule2 = createTempDirectory("testCloneRepositoryWithNestedSubmodules2");
  579. Git sub2Git = Git.init().setDirectory(submodule2).call();
  580. assertNotNull(sub2Git);
  581. Repository sub2 = sub2Git.getRepository();
  582. assertNotNull(sub2);
  583. addRepoToClose(sub2);
  584. write(new File(sub2.getWorkTree(), file), "content");
  585. sub2Git.add().addFilepattern(file).call();
  586. RevCommit sub2Head = sub2Git.commit().setMessage("create file").call();
  587. assertNotNull(sub2Head);
  588. // Add submodule 2 to submodule 1
  589. Repository r = sub1Git.submoduleAdd().setPath(path)
  590. .setURI(sub2.getDirectory().toURI().toString()).call();
  591. assertNotNull(r);
  592. addRepoToClose(r);
  593. RevCommit sub1Head = sub1Git.commit().setAll(true)
  594. .setMessage("Adding submodule").call();
  595. assertNotNull(sub1Head);
  596. // Add submodule 1 to default repository
  597. r = git.submoduleAdd().setPath(path)
  598. .setURI(sub1.getDirectory().toURI().toString()).call();
  599. assertNotNull(r);
  600. addRepoToClose(r);
  601. assertNotNull(git.commit().setAll(true).setMessage("Adding submodule")
  602. .call());
  603. // Clone default repository and include submodules
  604. File directory = createTempDirectory("testCloneRepositoryWithNestedSubmodules");
  605. CloneCommand clone = Git.cloneRepository();
  606. clone.setDirectory(directory);
  607. clone.setCloneSubmodules(true);
  608. clone.setURI(git.getRepository().getDirectory().toURI().toString());
  609. Git git2 = clone.call();
  610. addRepoToClose(git2.getRepository());
  611. assertEquals(Constants.MASTER, git2.getRepository().getBranch());
  612. assertTrue(new File(git2.getRepository().getWorkTree(), path
  613. + File.separatorChar + file).exists());
  614. assertTrue(new File(git2.getRepository().getWorkTree(), path
  615. + File.separatorChar + path + File.separatorChar + file)
  616. .exists());
  617. SubmoduleStatusCommand status = new SubmoduleStatusCommand(
  618. git2.getRepository());
  619. Map<String, SubmoduleStatus> statuses = status.call();
  620. SubmoduleStatus pathStatus = statuses.get(path);
  621. assertNotNull(pathStatus);
  622. assertEquals(SubmoduleStatusType.INITIALIZED, pathStatus.getType());
  623. assertEquals(sub1Head, pathStatus.getHeadId());
  624. assertEquals(sub1Head, pathStatus.getIndexId());
  625. try (SubmoduleWalk walk = SubmoduleWalk
  626. .forIndex(git2.getRepository())) {
  627. assertTrue(walk.next());
  628. try (Repository clonedSub1 = walk.getRepository()) {
  629. assertNotNull(clonedSub1);
  630. assertEquals(new File(git2.getRepository().getWorkTree(),
  631. walk.getPath()), clonedSub1.getWorkTree());
  632. assertEquals(
  633. new File(new File(git2.getRepository().getDirectory(),
  634. "modules"), walk.getPath()),
  635. clonedSub1.getDirectory());
  636. status = new SubmoduleStatusCommand(clonedSub1);
  637. statuses = status.call();
  638. }
  639. assertFalse(walk.next());
  640. }
  641. pathStatus = statuses.get(path);
  642. assertNotNull(pathStatus);
  643. assertEquals(SubmoduleStatusType.INITIALIZED, pathStatus.getType());
  644. assertEquals(sub2Head, pathStatus.getHeadId());
  645. assertEquals(sub2Head, pathStatus.getIndexId());
  646. }
  647. @Test
  648. public void testCloneWithAutoSetupRebase() throws Exception {
  649. File directory = createTempDirectory("testCloneRepository1");
  650. CloneCommand command = Git.cloneRepository();
  651. command.setDirectory(directory);
  652. command.setURI(fileUri());
  653. Git git2 = command.call();
  654. addRepoToClose(git2.getRepository());
  655. assertNull(git2.getRepository().getConfig().getEnum(
  656. BranchRebaseMode.values(),
  657. ConfigConstants.CONFIG_BRANCH_SECTION, "test",
  658. ConfigConstants.CONFIG_KEY_REBASE, null));
  659. StoredConfig userConfig = SystemReader.getInstance()
  660. .getUserConfig();
  661. userConfig.setString(ConfigConstants.CONFIG_BRANCH_SECTION, null,
  662. ConfigConstants.CONFIG_KEY_AUTOSETUPREBASE,
  663. ConfigConstants.CONFIG_KEY_ALWAYS);
  664. userConfig.save();
  665. directory = createTempDirectory("testCloneRepository2");
  666. command = Git.cloneRepository();
  667. command.setDirectory(directory);
  668. command.setURI(fileUri());
  669. git2 = command.call();
  670. addRepoToClose(git2.getRepository());
  671. assertEquals(BranchRebaseMode.REBASE,
  672. git2.getRepository().getConfig().getEnum(
  673. BranchRebaseMode.values(),
  674. ConfigConstants.CONFIG_BRANCH_SECTION, "test",
  675. ConfigConstants.CONFIG_KEY_REBASE,
  676. BranchRebaseMode.NONE));
  677. userConfig.setString(ConfigConstants.CONFIG_BRANCH_SECTION, null,
  678. ConfigConstants.CONFIG_KEY_AUTOSETUPREBASE,
  679. ConfigConstants.CONFIG_KEY_REMOTE);
  680. userConfig.save();
  681. directory = createTempDirectory("testCloneRepository2");
  682. command = Git.cloneRepository();
  683. command.setDirectory(directory);
  684. command.setURI(fileUri());
  685. git2 = command.call();
  686. addRepoToClose(git2.getRepository());
  687. assertEquals(BranchRebaseMode.REBASE,
  688. git2.getRepository().getConfig().getEnum(
  689. BranchRebaseMode.values(),
  690. ConfigConstants.CONFIG_BRANCH_SECTION, "test",
  691. ConfigConstants.CONFIG_KEY_REBASE,
  692. BranchRebaseMode.NONE));
  693. }
  694. @Test
  695. public void testCloneWithPullMerge() throws Exception {
  696. File directory = createTempDirectory("testCloneRepository1");
  697. try (Git g = Git.init().setDirectory(directory).setBare(false).call()) {
  698. g.remoteAdd().setName(Constants.DEFAULT_REMOTE_NAME)
  699. .setUri(new URIish(fileUri())).call();
  700. PullResult result = g.pull().setRebase(false).call();
  701. assertTrue(result.isSuccessful());
  702. assertEquals("refs/heads/master",
  703. g.getRepository().getFullBranch());
  704. checkFile(new File(directory, "Test.txt"), "Hello world");
  705. }
  706. }
  707. @Test
  708. public void testCloneWithPullRebase() throws Exception {
  709. File directory = createTempDirectory("testCloneRepository1");
  710. try (Git g = Git.init().setDirectory(directory).setBare(false).call()) {
  711. g.remoteAdd().setName(Constants.DEFAULT_REMOTE_NAME)
  712. .setUri(new URIish(fileUri())).call();
  713. PullResult result = g.pull().setRebase(true).call();
  714. assertTrue(result.isSuccessful());
  715. assertEquals("refs/heads/master",
  716. g.getRepository().getFullBranch());
  717. checkFile(new File(directory, "Test.txt"), "Hello world");
  718. }
  719. }
  720. @Test
  721. public void testCloneNoTags() throws IOException, JGitInternalException,
  722. GitAPIException, URISyntaxException {
  723. File directory = createTempDirectory("testCloneRepository");
  724. CloneCommand command = Git.cloneRepository();
  725. command.setDirectory(directory);
  726. command.setURI(fileUri());
  727. command.setNoTags();
  728. Git git2 = command.call();
  729. addRepoToClose(git2.getRepository());
  730. assertNotNull(git2.getRepository().resolve("refs/heads/test"));
  731. assertNull(git2.getRepository().resolve("tag-initial"));
  732. assertNull(git2.getRepository().resolve("tag-for-blob"));
  733. assertTagOption(git2.getRepository(), TagOpt.NO_TAGS);
  734. }
  735. @Test
  736. public void testCloneFollowTags() throws IOException, JGitInternalException,
  737. GitAPIException, URISyntaxException {
  738. File directory = createTempDirectory("testCloneRepository");
  739. CloneCommand command = Git.cloneRepository();
  740. command.setDirectory(directory);
  741. command.setURI(fileUri());
  742. command.setBranch("refs/heads/master");
  743. command.setBranchesToClone(
  744. Collections.singletonList("refs/heads/master"));
  745. command.setTagOption(TagOpt.FETCH_TAGS);
  746. Git git2 = command.call();
  747. addRepoToClose(git2.getRepository());
  748. assertNull(git2.getRepository().resolve("refs/heads/test"));
  749. assertNotNull(git2.getRepository().resolve("tag-initial"));
  750. assertNotNull(git2.getRepository().resolve("tag-for-blob"));
  751. assertTagOption(git2.getRepository(), TagOpt.FETCH_TAGS);
  752. }
  753. @Test
  754. public void testCloneWithHeadSymRefIsMasterCopy() throws IOException, GitAPIException {
  755. // create a branch with the same head as master and switch to it
  756. git.checkout().setStartPoint("master").setCreateBranch(true).setName("master-copy").call();
  757. // when we clone the HEAD symref->master-copy means we start on master-copy and not master
  758. File directory = createTempDirectory("testCloneRepositorySymRef_master-copy");
  759. CloneCommand command = Git.cloneRepository();
  760. command.setDirectory(directory);
  761. command.setURI(fileUri());
  762. Git git2 = command.call();
  763. addRepoToClose(git2.getRepository());
  764. assertEquals("refs/heads/master-copy", git2.getRepository().getFullBranch());
  765. }
  766. @Test
  767. public void testCloneWithHeadSymRefIsNonMasterCopy() throws IOException, GitAPIException {
  768. // create a branch with the same head as test and switch to it
  769. git.checkout().setStartPoint("test").setCreateBranch(true).setName("test-copy").call();
  770. File directory = createTempDirectory("testCloneRepositorySymRef_test-copy");
  771. CloneCommand command = Git.cloneRepository();
  772. command.setDirectory(directory);
  773. command.setURI(fileUri());
  774. Git git2 = command.call();
  775. addRepoToClose(git2.getRepository());
  776. assertEquals("refs/heads/test-copy", git2.getRepository().getFullBranch());
  777. }
  778. private void assertTagOption(Repository repo, TagOpt expectedTagOption)
  779. throws URISyntaxException {
  780. RemoteConfig remoteConfig = new RemoteConfig(
  781. repo.getConfig(), "origin");
  782. assertEquals(expectedTagOption, remoteConfig.getTagOpt());
  783. }
  784. private String fileUri() {
  785. return "file://" + git.getRepository().getWorkTree().getAbsolutePath();
  786. }
  787. }