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 24KB

Fix corrupted CloneCommand bare-repo fetch-refspec (#402031) CloneCommand has been creating fetch refspecs like this on bare clones: [remote "origin"] url = ssh://example.com/my-repo.git fetch = +refs/heads/*:refs/heads//* As you can see, the destination ref pattern has a superfluous slash. It looks like this behaviour has always been the case for CloneCommand, at least since cc2197ed when code catering to bare-clone fetch refspecs was added. That was released with JGit v1.0 almost 2 years ago, so there will probably be some bare repos in the wild which will have been cloned with JGit and have these corrupted refspecs. The effect of the corrupted fetch refspec is quite interesting. Up to and including JGit 2.0, the corrupt refspec was tolerated and fetches would work as intended with no indication to the user that anything was amiss. With JGit 2.1, a change was introduced which made JGit less tolerant, and fetches now attempt to update the non-existing ref "refs/heads//master". No exception is raised, but the real ref - "refs/heads/master" - is not updated. This behaviour was noticed by a user of Agit (which does bare clones by default and recently updated from JGit v2.0 to v2.2), reported here: https://github.com/rtyley/agit/issues/92 If you run C-Git fetch on a bare-repo cloned by JGit, it flat-out rejects the refspec (checked against v1.7.10.4): fatal: Invalid refspec '+refs/heads/*:refs/heads//*' Incidentally, C-Git does not create an explicit fetch refspec at all when performing a bare clone - the full remote config generated by C-Git looks like this: [remote "origin"] url = ssh://example.com/my-repo.git Using JGit on such a repository works fine, so omitting the fetch refspec entirely is also an option. Change-Id: I14b0d359dc69b8908f68e02cea7a756ac34bf881
11 years ago
Fix corrupted CloneCommand bare-repo fetch-refspec (#402031) CloneCommand has been creating fetch refspecs like this on bare clones: [remote "origin"] url = ssh://example.com/my-repo.git fetch = +refs/heads/*:refs/heads//* As you can see, the destination ref pattern has a superfluous slash. It looks like this behaviour has always been the case for CloneCommand, at least since cc2197ed when code catering to bare-clone fetch refspecs was added. That was released with JGit v1.0 almost 2 years ago, so there will probably be some bare repos in the wild which will have been cloned with JGit and have these corrupted refspecs. The effect of the corrupted fetch refspec is quite interesting. Up to and including JGit 2.0, the corrupt refspec was tolerated and fetches would work as intended with no indication to the user that anything was amiss. With JGit 2.1, a change was introduced which made JGit less tolerant, and fetches now attempt to update the non-existing ref "refs/heads//master". No exception is raised, but the real ref - "refs/heads/master" - is not updated. This behaviour was noticed by a user of Agit (which does bare clones by default and recently updated from JGit v2.0 to v2.2), reported here: https://github.com/rtyley/agit/issues/92 If you run C-Git fetch on a bare-repo cloned by JGit, it flat-out rejects the refspec (checked against v1.7.10.4): fatal: Invalid refspec '+refs/heads/*:refs/heads//*' Incidentally, C-Git does not create an explicit fetch refspec at all when performing a bare clone - the full remote config generated by C-Git looks like this: [remote "origin"] url = ssh://example.com/my-repo.git Using JGit on such a repository works fine, so omitting the fetch refspec entirely is also an option. Change-Id: I14b0d359dc69b8908f68e02cea7a756ac34bf881
11 years ago
Fix corrupted CloneCommand bare-repo fetch-refspec (#402031) CloneCommand has been creating fetch refspecs like this on bare clones: [remote "origin"] url = ssh://example.com/my-repo.git fetch = +refs/heads/*:refs/heads//* As you can see, the destination ref pattern has a superfluous slash. It looks like this behaviour has always been the case for CloneCommand, at least since cc2197ed when code catering to bare-clone fetch refspecs was added. That was released with JGit v1.0 almost 2 years ago, so there will probably be some bare repos in the wild which will have been cloned with JGit and have these corrupted refspecs. The effect of the corrupted fetch refspec is quite interesting. Up to and including JGit 2.0, the corrupt refspec was tolerated and fetches would work as intended with no indication to the user that anything was amiss. With JGit 2.1, a change was introduced which made JGit less tolerant, and fetches now attempt to update the non-existing ref "refs/heads//master". No exception is raised, but the real ref - "refs/heads/master" - is not updated. This behaviour was noticed by a user of Agit (which does bare clones by default and recently updated from JGit v2.0 to v2.2), reported here: https://github.com/rtyley/agit/issues/92 If you run C-Git fetch on a bare-repo cloned by JGit, it flat-out rejects the refspec (checked against v1.7.10.4): fatal: Invalid refspec '+refs/heads/*:refs/heads//*' Incidentally, C-Git does not create an explicit fetch refspec at all when performing a bare clone - the full remote config generated by C-Git looks like this: [remote "origin"] url = ssh://example.com/my-repo.git Using JGit on such a repository works fine, so omitting the fetch refspec entirely is also an option. Change-Id: I14b0d359dc69b8908f68e02cea7a756ac34bf881
11 years ago
Fix corrupted CloneCommand bare-repo fetch-refspec (#402031) CloneCommand has been creating fetch refspecs like this on bare clones: [remote "origin"] url = ssh://example.com/my-repo.git fetch = +refs/heads/*:refs/heads//* As you can see, the destination ref pattern has a superfluous slash. It looks like this behaviour has always been the case for CloneCommand, at least since cc2197ed when code catering to bare-clone fetch refspecs was added. That was released with JGit v1.0 almost 2 years ago, so there will probably be some bare repos in the wild which will have been cloned with JGit and have these corrupted refspecs. The effect of the corrupted fetch refspec is quite interesting. Up to and including JGit 2.0, the corrupt refspec was tolerated and fetches would work as intended with no indication to the user that anything was amiss. With JGit 2.1, a change was introduced which made JGit less tolerant, and fetches now attempt to update the non-existing ref "refs/heads//master". No exception is raised, but the real ref - "refs/heads/master" - is not updated. This behaviour was noticed by a user of Agit (which does bare clones by default and recently updated from JGit v2.0 to v2.2), reported here: https://github.com/rtyley/agit/issues/92 If you run C-Git fetch on a bare-repo cloned by JGit, it flat-out rejects the refspec (checked against v1.7.10.4): fatal: Invalid refspec '+refs/heads/*:refs/heads//*' Incidentally, C-Git does not create an explicit fetch refspec at all when performing a bare clone - the full remote config generated by C-Git looks like this: [remote "origin"] url = ssh://example.com/my-repo.git Using JGit on such a repository works fine, so omitting the fetch refspec entirely is also an option. Change-Id: I14b0d359dc69b8908f68e02cea7a756ac34bf881
11 years ago
Fix corrupted CloneCommand bare-repo fetch-refspec (#402031) CloneCommand has been creating fetch refspecs like this on bare clones: [remote "origin"] url = ssh://example.com/my-repo.git fetch = +refs/heads/*:refs/heads//* As you can see, the destination ref pattern has a superfluous slash. It looks like this behaviour has always been the case for CloneCommand, at least since cc2197ed when code catering to bare-clone fetch refspecs was added. That was released with JGit v1.0 almost 2 years ago, so there will probably be some bare repos in the wild which will have been cloned with JGit and have these corrupted refspecs. The effect of the corrupted fetch refspec is quite interesting. Up to and including JGit 2.0, the corrupt refspec was tolerated and fetches would work as intended with no indication to the user that anything was amiss. With JGit 2.1, a change was introduced which made JGit less tolerant, and fetches now attempt to update the non-existing ref "refs/heads//master". No exception is raised, but the real ref - "refs/heads/master" - is not updated. This behaviour was noticed by a user of Agit (which does bare clones by default and recently updated from JGit v2.0 to v2.2), reported here: https://github.com/rtyley/agit/issues/92 If you run C-Git fetch on a bare-repo cloned by JGit, it flat-out rejects the refspec (checked against v1.7.10.4): fatal: Invalid refspec '+refs/heads/*:refs/heads//*' Incidentally, C-Git does not create an explicit fetch refspec at all when performing a bare clone - the full remote config generated by C-Git looks like this: [remote "origin"] url = ssh://example.com/my-repo.git Using JGit on such a repository works fine, so omitting the fetch refspec entirely is also an option. Change-Id: I14b0d359dc69b8908f68e02cea7a756ac34bf881
11 years ago
Fix corrupted CloneCommand bare-repo fetch-refspec (#402031) CloneCommand has been creating fetch refspecs like this on bare clones: [remote "origin"] url = ssh://example.com/my-repo.git fetch = +refs/heads/*:refs/heads//* As you can see, the destination ref pattern has a superfluous slash. It looks like this behaviour has always been the case for CloneCommand, at least since cc2197ed when code catering to bare-clone fetch refspecs was added. That was released with JGit v1.0 almost 2 years ago, so there will probably be some bare repos in the wild which will have been cloned with JGit and have these corrupted refspecs. The effect of the corrupted fetch refspec is quite interesting. Up to and including JGit 2.0, the corrupt refspec was tolerated and fetches would work as intended with no indication to the user that anything was amiss. With JGit 2.1, a change was introduced which made JGit less tolerant, and fetches now attempt to update the non-existing ref "refs/heads//master". No exception is raised, but the real ref - "refs/heads/master" - is not updated. This behaviour was noticed by a user of Agit (which does bare clones by default and recently updated from JGit v2.0 to v2.2), reported here: https://github.com/rtyley/agit/issues/92 If you run C-Git fetch on a bare-repo cloned by JGit, it flat-out rejects the refspec (checked against v1.7.10.4): fatal: Invalid refspec '+refs/heads/*:refs/heads//*' Incidentally, C-Git does not create an explicit fetch refspec at all when performing a bare clone - the full remote config generated by C-Git looks like this: [remote "origin"] url = ssh://example.com/my-repo.git Using JGit on such a repository works fine, so omitting the fetch refspec entirely is also an option. Change-Id: I14b0d359dc69b8908f68e02cea7a756ac34bf881
11 years ago
Fix corrupted CloneCommand bare-repo fetch-refspec (#402031) CloneCommand has been creating fetch refspecs like this on bare clones: [remote "origin"] url = ssh://example.com/my-repo.git fetch = +refs/heads/*:refs/heads//* As you can see, the destination ref pattern has a superfluous slash. It looks like this behaviour has always been the case for CloneCommand, at least since cc2197ed when code catering to bare-clone fetch refspecs was added. That was released with JGit v1.0 almost 2 years ago, so there will probably be some bare repos in the wild which will have been cloned with JGit and have these corrupted refspecs. The effect of the corrupted fetch refspec is quite interesting. Up to and including JGit 2.0, the corrupt refspec was tolerated and fetches would work as intended with no indication to the user that anything was amiss. With JGit 2.1, a change was introduced which made JGit less tolerant, and fetches now attempt to update the non-existing ref "refs/heads//master". No exception is raised, but the real ref - "refs/heads/master" - is not updated. This behaviour was noticed by a user of Agit (which does bare clones by default and recently updated from JGit v2.0 to v2.2), reported here: https://github.com/rtyley/agit/issues/92 If you run C-Git fetch on a bare-repo cloned by JGit, it flat-out rejects the refspec (checked against v1.7.10.4): fatal: Invalid refspec '+refs/heads/*:refs/heads//*' Incidentally, C-Git does not create an explicit fetch refspec at all when performing a bare clone - the full remote config generated by C-Git looks like this: [remote "origin"] url = ssh://example.com/my-repo.git Using JGit on such a repository works fine, so omitting the fetch refspec entirely is also an option. Change-Id: I14b0d359dc69b8908f68e02cea7a756ac34bf881
11 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677
  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.assertNull;
  48. import static org.junit.Assert.assertTrue;
  49. import static org.junit.Assert.fail;
  50. import java.io.File;
  51. import java.io.IOException;
  52. import java.net.URISyntaxException;
  53. import java.util.Collections;
  54. import java.util.List;
  55. import java.util.Map;
  56. import org.eclipse.jgit.api.ListBranchCommand.ListMode;
  57. import org.eclipse.jgit.api.errors.GitAPIException;
  58. import org.eclipse.jgit.api.errors.JGitInternalException;
  59. import org.eclipse.jgit.errors.NoWorkTreeException;
  60. import org.eclipse.jgit.junit.RepositoryTestCase;
  61. import org.eclipse.jgit.junit.TestRepository;
  62. import org.eclipse.jgit.lib.BranchConfig.BranchRebaseMode;
  63. import org.eclipse.jgit.lib.ConfigConstants;
  64. import org.eclipse.jgit.lib.Constants;
  65. import org.eclipse.jgit.lib.ObjectId;
  66. import org.eclipse.jgit.lib.Ref;
  67. import org.eclipse.jgit.lib.Repository;
  68. import org.eclipse.jgit.lib.StoredConfig;
  69. import org.eclipse.jgit.revwalk.RevBlob;
  70. import org.eclipse.jgit.revwalk.RevCommit;
  71. import org.eclipse.jgit.submodule.SubmoduleStatus;
  72. import org.eclipse.jgit.submodule.SubmoduleStatusType;
  73. import org.eclipse.jgit.submodule.SubmoduleWalk;
  74. import org.eclipse.jgit.transport.RefSpec;
  75. import org.eclipse.jgit.transport.RemoteConfig;
  76. import org.eclipse.jgit.transport.URIish;
  77. import org.eclipse.jgit.util.SystemReader;
  78. import org.junit.Test;
  79. public class CloneCommandTest extends RepositoryTestCase {
  80. private Git git;
  81. private TestRepository<Repository> tr;
  82. @Override
  83. public void setUp() throws Exception {
  84. super.setUp();
  85. tr = new TestRepository<>(db);
  86. git = new Git(db);
  87. // commit something
  88. writeTrashFile("Test.txt", "Hello world");
  89. git.add().addFilepattern("Test.txt").call();
  90. git.commit().setMessage("Initial commit").call();
  91. git.tag().setName("tag-initial").setMessage("Tag initial").call();
  92. // create a test branch and switch to it
  93. git.checkout().setCreateBranch(true).setName("test").call();
  94. // commit something on the test branch
  95. writeTrashFile("Test.txt", "Some change");
  96. git.add().addFilepattern("Test.txt").call();
  97. git.commit().setMessage("Second commit").call();
  98. RevBlob blob = tr.blob("blob-not-in-master-branch");
  99. git.tag().setName("tag-for-blob").setObjectId(blob).call();
  100. }
  101. @Test
  102. public void testCloneRepository() throws IOException,
  103. JGitInternalException, GitAPIException, URISyntaxException {
  104. File directory = createTempDirectory("testCloneRepository");
  105. CloneCommand command = Git.cloneRepository();
  106. command.setDirectory(directory);
  107. command.setURI(fileUri());
  108. Git git2 = command.call();
  109. addRepoToClose(git2.getRepository());
  110. assertNotNull(git2);
  111. ObjectId id = git2.getRepository().resolve("tag-for-blob");
  112. assertNotNull(id);
  113. assertEquals(git2.getRepository().getFullBranch(), "refs/heads/test");
  114. assertEquals(
  115. "origin",
  116. git2.getRepository()
  117. .getConfig()
  118. .getString(ConfigConstants.CONFIG_BRANCH_SECTION,
  119. "test", ConfigConstants.CONFIG_KEY_REMOTE));
  120. assertEquals(
  121. "refs/heads/test",
  122. git2.getRepository()
  123. .getConfig()
  124. .getString(ConfigConstants.CONFIG_BRANCH_SECTION,
  125. "test", ConfigConstants.CONFIG_KEY_MERGE));
  126. assertEquals(2, git2.branchList().setListMode(ListMode.REMOTE).call()
  127. .size());
  128. assertEquals(new RefSpec("+refs/heads/*:refs/remotes/origin/*"),
  129. fetchRefSpec(git2.getRepository()));
  130. }
  131. @Test
  132. public void testCloneRepositoryExplicitGitDir() throws IOException,
  133. JGitInternalException, GitAPIException {
  134. File directory = createTempDirectory("testCloneRepository");
  135. CloneCommand command = Git.cloneRepository();
  136. command.setDirectory(directory);
  137. command.setGitDir(new File(directory, Constants.DOT_GIT));
  138. command.setURI(fileUri());
  139. Git git2 = command.call();
  140. addRepoToClose(git2.getRepository());
  141. assertEquals(directory, git2.getRepository().getWorkTree());
  142. assertEquals(new File(directory, Constants.DOT_GIT), git2.getRepository()
  143. .getDirectory());
  144. }
  145. @Test
  146. public void testCloneRepositoryDefaultDirectory()
  147. throws URISyntaxException, JGitInternalException {
  148. CloneCommand command = Git.cloneRepository().setURI(fileUri());
  149. command.verifyDirectories(new URIish(fileUri()));
  150. File directory = command.getDirectory();
  151. assertEquals(git.getRepository().getWorkTree().getName(), directory.getName());
  152. }
  153. @Test
  154. public void testCloneBareRepositoryDefaultDirectory()
  155. throws URISyntaxException, JGitInternalException {
  156. CloneCommand command = Git.cloneRepository().setURI(fileUri()).setBare(true);
  157. command.verifyDirectories(new URIish(fileUri()));
  158. File directory = command.getDirectory();
  159. assertEquals(git.getRepository().getWorkTree().getName() + Constants.DOT_GIT_EXT, directory.getName());
  160. }
  161. @Test
  162. public void testCloneRepositoryExplicitGitDirNonStd() throws IOException,
  163. JGitInternalException, GitAPIException {
  164. File directory = createTempDirectory("testCloneRepository");
  165. File gDir = createTempDirectory("testCloneRepository.git");
  166. CloneCommand command = Git.cloneRepository();
  167. command.setDirectory(directory);
  168. command.setGitDir(gDir);
  169. command.setURI(fileUri());
  170. Git git2 = command.call();
  171. addRepoToClose(git2.getRepository());
  172. assertEquals(directory, git2.getRepository().getWorkTree());
  173. assertEquals(gDir, git2.getRepository()
  174. .getDirectory());
  175. assertTrue(new File(directory, Constants.DOT_GIT).isFile());
  176. assertFalse(new File(gDir, Constants.DOT_GIT).exists());
  177. }
  178. @Test
  179. public void testCloneRepositoryExplicitGitDirBare() throws IOException,
  180. JGitInternalException, GitAPIException {
  181. File gDir = createTempDirectory("testCloneRepository.git");
  182. CloneCommand command = Git.cloneRepository();
  183. command.setBare(true);
  184. command.setGitDir(gDir);
  185. command.setURI(fileUri());
  186. Git git2 = command.call();
  187. addRepoToClose(git2.getRepository());
  188. try {
  189. assertNull(null, git2.getRepository().getWorkTree());
  190. fail("Expected NoWorkTreeException");
  191. } catch (NoWorkTreeException e) {
  192. assertEquals(gDir, git2.getRepository().getDirectory());
  193. }
  194. }
  195. @Test
  196. public void testBareCloneRepository() throws IOException,
  197. JGitInternalException, GitAPIException, URISyntaxException {
  198. File directory = createTempDirectory("testCloneRepository_bare");
  199. CloneCommand command = Git.cloneRepository();
  200. command.setBare(true);
  201. command.setDirectory(directory);
  202. command.setURI(fileUri());
  203. Git git2 = command.call();
  204. addRepoToClose(git2.getRepository());
  205. assertEquals(new RefSpec("+refs/heads/*:refs/heads/*"),
  206. fetchRefSpec(git2.getRepository()));
  207. }
  208. @Test
  209. public void testCloneRepositoryCustomRemote() throws Exception {
  210. File directory = createTempDirectory("testCloneRemoteUpstream");
  211. CloneCommand command = Git.cloneRepository();
  212. command.setDirectory(directory);
  213. command.setRemote("upstream");
  214. command.setURI(fileUri());
  215. Git git2 = command.call();
  216. addRepoToClose(git2.getRepository());
  217. assertEquals("+refs/heads/*:refs/remotes/upstream/*",
  218. git2.getRepository()
  219. .getConfig()
  220. .getStringList("remote", "upstream",
  221. "fetch")[0]);
  222. assertEquals("upstream",
  223. git2.getRepository()
  224. .getConfig()
  225. .getString("branch", "test", "remote"));
  226. assertEquals(db.resolve("test"),
  227. git2.getRepository().resolve("upstream/test"));
  228. }
  229. @Test
  230. public void testBareCloneRepositoryCustomRemote() throws Exception {
  231. File directory = createTempDirectory("testCloneRemoteUpstream_bare");
  232. CloneCommand command = Git.cloneRepository();
  233. command.setBare(true);
  234. command.setDirectory(directory);
  235. command.setRemote("upstream");
  236. command.setURI(fileUri());
  237. Git git2 = command.call();
  238. addRepoToClose(git2.getRepository());
  239. assertEquals("+refs/heads/*:refs/heads/*",
  240. git2.getRepository()
  241. .getConfig()
  242. .getStringList("remote", "upstream",
  243. "fetch")[0]);
  244. assertEquals("upstream",
  245. git2.getRepository()
  246. .getConfig()
  247. .getString("branch", "test", "remote"));
  248. assertNull(git2.getRepository().resolve("upstream/test"));
  249. }
  250. @Test
  251. public void testBareCloneRepositoryNullRemote() throws Exception {
  252. File directory = createTempDirectory("testCloneRemoteNull_bare");
  253. CloneCommand command = Git.cloneRepository();
  254. command.setBare(true);
  255. command.setDirectory(directory);
  256. command.setRemote(null);
  257. command.setURI(fileUri());
  258. Git git2 = command.call();
  259. addRepoToClose(git2.getRepository());
  260. assertEquals("+refs/heads/*:refs/heads/*", git2.getRepository()
  261. .getConfig().getStringList("remote", "origin", "fetch")[0]);
  262. assertEquals("origin", git2.getRepository().getConfig()
  263. .getString("branch", "test", "remote"));
  264. }
  265. public static RefSpec fetchRefSpec(Repository r) throws URISyntaxException {
  266. RemoteConfig remoteConfig =
  267. new RemoteConfig(r.getConfig(), Constants.DEFAULT_REMOTE_NAME);
  268. return remoteConfig.getFetchRefSpecs().get(0);
  269. }
  270. @Test
  271. public void testCloneRepositoryWithBranch() throws IOException,
  272. JGitInternalException, GitAPIException {
  273. File directory = createTempDirectory("testCloneRepositoryWithBranch");
  274. CloneCommand command = Git.cloneRepository();
  275. command.setBranch("refs/heads/master");
  276. command.setDirectory(directory);
  277. command.setURI(fileUri());
  278. Git git2 = command.call();
  279. addRepoToClose(git2.getRepository());
  280. assertNotNull(git2);
  281. assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
  282. assertEquals(
  283. "refs/heads/master, refs/remotes/origin/master, refs/remotes/origin/test",
  284. allRefNames(git2.branchList().setListMode(ListMode.ALL).call()));
  285. // Same thing, but now without checkout
  286. directory = createTempDirectory("testCloneRepositoryWithBranch_bare");
  287. command = Git.cloneRepository();
  288. command.setBranch("refs/heads/master");
  289. command.setDirectory(directory);
  290. command.setURI(fileUri());
  291. command.setNoCheckout(true);
  292. git2 = command.call();
  293. addRepoToClose(git2.getRepository());
  294. assertNotNull(git2);
  295. assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
  296. assertEquals("refs/remotes/origin/master, refs/remotes/origin/test",
  297. allRefNames(git2.branchList().setListMode(ListMode.ALL).call()));
  298. // Same thing, but now test with bare repo
  299. directory = createTempDirectory("testCloneRepositoryWithBranch_bare");
  300. command = Git.cloneRepository();
  301. command.setBranch("refs/heads/master");
  302. command.setDirectory(directory);
  303. command.setURI(fileUri());
  304. command.setBare(true);
  305. git2 = command.call();
  306. addRepoToClose(git2.getRepository());
  307. assertNotNull(git2);
  308. assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
  309. assertEquals("refs/heads/master, refs/heads/test", allRefNames(git2
  310. .branchList().setListMode(ListMode.ALL).call()));
  311. }
  312. @Test
  313. public void testCloneRepositoryWithBranchShortName() throws Exception {
  314. File directory = createTempDirectory("testCloneRepositoryWithBranch");
  315. CloneCommand command = Git.cloneRepository();
  316. command.setBranch("test");
  317. command.setDirectory(directory);
  318. command.setURI(fileUri());
  319. Git git2 = command.call();
  320. addRepoToClose(git2.getRepository());
  321. assertNotNull(git2);
  322. assertEquals("refs/heads/test", git2.getRepository().getFullBranch());
  323. }
  324. @Test
  325. public void testCloneRepositoryWithTagName() throws Exception {
  326. File directory = createTempDirectory("testCloneRepositoryWithBranch");
  327. CloneCommand command = Git.cloneRepository();
  328. command.setBranch("tag-initial");
  329. command.setDirectory(directory);
  330. command.setURI(fileUri());
  331. Git git2 = command.call();
  332. addRepoToClose(git2.getRepository());
  333. assertNotNull(git2);
  334. ObjectId taggedCommit = db.resolve("tag-initial^{commit}");
  335. assertEquals(taggedCommit.name(), git2
  336. .getRepository().getFullBranch());
  337. }
  338. @Test
  339. public void testCloneRepositoryOnlyOneBranch() throws IOException,
  340. JGitInternalException, GitAPIException {
  341. File directory = createTempDirectory("testCloneRepositoryWithBranch");
  342. CloneCommand command = Git.cloneRepository();
  343. command.setBranch("refs/heads/master");
  344. command.setBranchesToClone(Collections
  345. .singletonList("refs/heads/master"));
  346. command.setDirectory(directory);
  347. command.setURI(fileUri());
  348. Git git2 = command.call();
  349. addRepoToClose(git2.getRepository());
  350. assertNotNull(git2);
  351. assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
  352. assertEquals("refs/remotes/origin/master", allRefNames(git2
  353. .branchList().setListMode(ListMode.REMOTE).call()));
  354. // Same thing, but now test with bare repo
  355. directory = createTempDirectory("testCloneRepositoryWithBranch_bare");
  356. command = Git.cloneRepository();
  357. command.setBranch("refs/heads/master");
  358. command.setBranchesToClone(Collections
  359. .singletonList("refs/heads/master"));
  360. command.setDirectory(directory);
  361. command.setURI(fileUri());
  362. command.setBare(true);
  363. git2 = command.call();
  364. addRepoToClose(git2.getRepository());
  365. assertNotNull(git2);
  366. assertEquals(git2.getRepository().getFullBranch(), "refs/heads/master");
  367. assertEquals("refs/heads/master", allRefNames(git2.branchList()
  368. .setListMode(ListMode.ALL).call()));
  369. }
  370. public static String allRefNames(List<Ref> refs) {
  371. StringBuilder sb = new StringBuilder();
  372. for (Ref f : refs) {
  373. if (sb.length() > 0)
  374. sb.append(", ");
  375. sb.append(f.getName());
  376. }
  377. return sb.toString();
  378. }
  379. @Test
  380. public void testCloneRepositoryWhenDestinationDirectoryExistsAndIsNotEmpty()
  381. throws IOException, JGitInternalException, GitAPIException {
  382. String dirName = "testCloneTargetDirectoryNotEmpty";
  383. File directory = createTempDirectory(dirName);
  384. CloneCommand command = Git.cloneRepository();
  385. command.setDirectory(directory);
  386. command.setURI(fileUri());
  387. Git git2 = command.call();
  388. addRepoToClose(git2.getRepository());
  389. assertNotNull(git2);
  390. // clone again
  391. command = Git.cloneRepository();
  392. command.setDirectory(directory);
  393. command.setURI(fileUri());
  394. try {
  395. git2 = command.call();
  396. // we shouldn't get here
  397. fail("destination directory already exists and is not an empty folder, cloning should fail");
  398. } catch (JGitInternalException e) {
  399. assertTrue(e.getMessage().contains("not an empty directory"));
  400. assertTrue(e.getMessage().contains(dirName));
  401. }
  402. }
  403. @Test
  404. public void testCloneRepositoryWithMultipleHeadBranches() throws Exception {
  405. git.checkout().setName(Constants.MASTER).call();
  406. git.branchCreate().setName("a").call();
  407. File directory = createTempDirectory("testCloneRepositoryWithMultipleHeadBranches");
  408. CloneCommand clone = Git.cloneRepository();
  409. clone.setDirectory(directory);
  410. clone.setURI(fileUri());
  411. Git git2 = clone.call();
  412. addRepoToClose(git2.getRepository());
  413. assertNotNull(git2);
  414. assertEquals(Constants.MASTER, git2.getRepository().getBranch());
  415. }
  416. @Test
  417. public void testCloneRepositoryWithSubmodules() throws Exception {
  418. git.checkout().setName(Constants.MASTER).call();
  419. String file = "file.txt";
  420. writeTrashFile(file, "content");
  421. git.add().addFilepattern(file).call();
  422. RevCommit commit = git.commit().setMessage("create file").call();
  423. SubmoduleAddCommand command = new SubmoduleAddCommand(db);
  424. String path = "sub";
  425. command.setPath(path);
  426. String uri = db.getDirectory().toURI().toString();
  427. command.setURI(uri);
  428. Repository repo = command.call();
  429. assertNotNull(repo);
  430. addRepoToClose(repo);
  431. git.add().addFilepattern(path)
  432. .addFilepattern(Constants.DOT_GIT_MODULES).call();
  433. git.commit().setMessage("adding submodule").call();
  434. try (SubmoduleWalk walk = SubmoduleWalk.forIndex(git.getRepository())) {
  435. assertTrue(walk.next());
  436. Repository subRepo = walk.getRepository();
  437. addRepoToClose(subRepo);
  438. assertNotNull(subRepo);
  439. assertEquals(
  440. new File(git.getRepository().getWorkTree(), walk.getPath()),
  441. subRepo.getWorkTree());
  442. assertEquals(new File(new File(git.getRepository().getDirectory(),
  443. "modules"), walk.getPath()), subRepo.getDirectory());
  444. }
  445. File directory = createTempDirectory("testCloneRepositoryWithSubmodules");
  446. CloneCommand clone = Git.cloneRepository();
  447. clone.setDirectory(directory);
  448. clone.setCloneSubmodules(true);
  449. clone.setURI(fileUri());
  450. Git git2 = clone.call();
  451. addRepoToClose(git2.getRepository());
  452. assertNotNull(git2);
  453. assertEquals(Constants.MASTER, git2.getRepository().getBranch());
  454. assertTrue(new File(git2.getRepository().getWorkTree(), path
  455. + File.separatorChar + file).exists());
  456. SubmoduleStatusCommand status = new SubmoduleStatusCommand(
  457. git2.getRepository());
  458. Map<String, SubmoduleStatus> statuses = status.call();
  459. SubmoduleStatus pathStatus = statuses.get(path);
  460. assertNotNull(pathStatus);
  461. assertEquals(SubmoduleStatusType.INITIALIZED, pathStatus.getType());
  462. assertEquals(commit, pathStatus.getHeadId());
  463. assertEquals(commit, pathStatus.getIndexId());
  464. try (SubmoduleWalk walk = SubmoduleWalk
  465. .forIndex(git2.getRepository())) {
  466. assertTrue(walk.next());
  467. Repository clonedSub1 = walk.getRepository();
  468. addRepoToClose(clonedSub1);
  469. assertNotNull(clonedSub1);
  470. assertEquals(new File(git2.getRepository().getWorkTree(),
  471. walk.getPath()), clonedSub1.getWorkTree());
  472. assertEquals(
  473. new File(new File(git2.getRepository().getDirectory(),
  474. "modules"), walk.getPath()),
  475. clonedSub1.getDirectory());
  476. }
  477. }
  478. @Test
  479. public void testCloneRepositoryWithNestedSubmodules() throws Exception {
  480. git.checkout().setName(Constants.MASTER).call();
  481. // Create submodule 1
  482. File submodule1 = createTempDirectory("testCloneRepositoryWithNestedSubmodules1");
  483. Git sub1Git = Git.init().setDirectory(submodule1).call();
  484. assertNotNull(sub1Git);
  485. Repository sub1 = sub1Git.getRepository();
  486. assertNotNull(sub1);
  487. addRepoToClose(sub1);
  488. String file = "file.txt";
  489. String path = "sub";
  490. write(new File(sub1.getWorkTree(), file), "content");
  491. sub1Git.add().addFilepattern(file).call();
  492. RevCommit commit = sub1Git.commit().setMessage("create file").call();
  493. assertNotNull(commit);
  494. // Create submodule 2
  495. File submodule2 = createTempDirectory("testCloneRepositoryWithNestedSubmodules2");
  496. Git sub2Git = Git.init().setDirectory(submodule2).call();
  497. assertNotNull(sub2Git);
  498. Repository sub2 = sub2Git.getRepository();
  499. assertNotNull(sub2);
  500. addRepoToClose(sub2);
  501. write(new File(sub2.getWorkTree(), file), "content");
  502. sub2Git.add().addFilepattern(file).call();
  503. RevCommit sub2Head = sub2Git.commit().setMessage("create file").call();
  504. assertNotNull(sub2Head);
  505. // Add submodule 2 to submodule 1
  506. Repository r = sub1Git.submoduleAdd().setPath(path)
  507. .setURI(sub2.getDirectory().toURI().toString()).call();
  508. assertNotNull(r);
  509. addRepoToClose(r);
  510. RevCommit sub1Head = sub1Git.commit().setAll(true)
  511. .setMessage("Adding submodule").call();
  512. assertNotNull(sub1Head);
  513. // Add submodule 1 to default repository
  514. r = git.submoduleAdd().setPath(path)
  515. .setURI(sub1.getDirectory().toURI().toString()).call();
  516. assertNotNull(r);
  517. addRepoToClose(r);
  518. assertNotNull(git.commit().setAll(true).setMessage("Adding submodule")
  519. .call());
  520. // Clone default repository and include submodules
  521. File directory = createTempDirectory("testCloneRepositoryWithNestedSubmodules");
  522. CloneCommand clone = Git.cloneRepository();
  523. clone.setDirectory(directory);
  524. clone.setCloneSubmodules(true);
  525. clone.setURI(git.getRepository().getDirectory().toURI().toString());
  526. Git git2 = clone.call();
  527. addRepoToClose(git2.getRepository());
  528. assertNotNull(git2);
  529. assertEquals(Constants.MASTER, git2.getRepository().getBranch());
  530. assertTrue(new File(git2.getRepository().getWorkTree(), path
  531. + File.separatorChar + file).exists());
  532. assertTrue(new File(git2.getRepository().getWorkTree(), path
  533. + File.separatorChar + path + File.separatorChar + file)
  534. .exists());
  535. SubmoduleStatusCommand status = new SubmoduleStatusCommand(
  536. git2.getRepository());
  537. Map<String, SubmoduleStatus> statuses = status.call();
  538. SubmoduleStatus pathStatus = statuses.get(path);
  539. assertNotNull(pathStatus);
  540. assertEquals(SubmoduleStatusType.INITIALIZED, pathStatus.getType());
  541. assertEquals(sub1Head, pathStatus.getHeadId());
  542. assertEquals(sub1Head, pathStatus.getIndexId());
  543. SubmoduleWalk walk = SubmoduleWalk.forIndex(git2.getRepository());
  544. assertTrue(walk.next());
  545. try (Repository clonedSub1 = walk.getRepository()) {
  546. assertNotNull(clonedSub1);
  547. assertEquals(new File(git2.getRepository().getWorkTree(),
  548. walk.getPath()), clonedSub1.getWorkTree());
  549. assertEquals(
  550. new File(new File(git2.getRepository().getDirectory(),
  551. "modules"), walk.getPath()),
  552. clonedSub1.getDirectory());
  553. status = new SubmoduleStatusCommand(clonedSub1);
  554. statuses = status.call();
  555. }
  556. pathStatus = statuses.get(path);
  557. assertNotNull(pathStatus);
  558. assertEquals(SubmoduleStatusType.INITIALIZED, pathStatus.getType());
  559. assertEquals(sub2Head, pathStatus.getHeadId());
  560. assertEquals(sub2Head, pathStatus.getIndexId());
  561. assertFalse(walk.next());
  562. }
  563. @Test
  564. public void testCloneWithAutoSetupRebase() throws Exception {
  565. File directory = createTempDirectory("testCloneRepository1");
  566. CloneCommand command = Git.cloneRepository();
  567. command.setDirectory(directory);
  568. command.setURI(fileUri());
  569. Git git2 = command.call();
  570. addRepoToClose(git2.getRepository());
  571. assertNull(git2.getRepository().getConfig().getEnum(
  572. BranchRebaseMode.values(),
  573. ConfigConstants.CONFIG_BRANCH_SECTION, "test",
  574. ConfigConstants.CONFIG_KEY_REBASE, null));
  575. StoredConfig userConfig = SystemReader.getInstance()
  576. .getUserConfig();
  577. userConfig.setString(ConfigConstants.CONFIG_BRANCH_SECTION, null,
  578. ConfigConstants.CONFIG_KEY_AUTOSETUPREBASE,
  579. ConfigConstants.CONFIG_KEY_ALWAYS);
  580. userConfig.save();
  581. directory = createTempDirectory("testCloneRepository2");
  582. command = Git.cloneRepository();
  583. command.setDirectory(directory);
  584. command.setURI(fileUri());
  585. git2 = command.call();
  586. addRepoToClose(git2.getRepository());
  587. assertEquals(BranchRebaseMode.REBASE,
  588. git2.getRepository().getConfig().getEnum(
  589. BranchRebaseMode.values(),
  590. ConfigConstants.CONFIG_BRANCH_SECTION, "test",
  591. ConfigConstants.CONFIG_KEY_REBASE,
  592. BranchRebaseMode.NONE));
  593. userConfig.setString(ConfigConstants.CONFIG_BRANCH_SECTION, null,
  594. ConfigConstants.CONFIG_KEY_AUTOSETUPREBASE,
  595. ConfigConstants.CONFIG_KEY_REMOTE);
  596. userConfig.save();
  597. directory = createTempDirectory("testCloneRepository2");
  598. command = Git.cloneRepository();
  599. command.setDirectory(directory);
  600. command.setURI(fileUri());
  601. git2 = command.call();
  602. addRepoToClose(git2.getRepository());
  603. assertEquals(BranchRebaseMode.REBASE,
  604. git2.getRepository().getConfig().getEnum(
  605. BranchRebaseMode.values(),
  606. ConfigConstants.CONFIG_BRANCH_SECTION, "test",
  607. ConfigConstants.CONFIG_KEY_REBASE,
  608. BranchRebaseMode.NONE));
  609. }
  610. private String fileUri() {
  611. return "file://" + git.getRepository().getWorkTree().getAbsolutePath();
  612. }
  613. }