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.

CommitCommandTest.java 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407
  1. /*
  2. * Copyright (C) 2011-2012, GitHub Inc.
  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.assertNotNull;
  46. import static org.junit.Assert.assertNull;
  47. import static org.junit.Assert.assertTrue;
  48. import java.io.File;
  49. import java.util.List;
  50. import org.eclipse.jgit.diff.DiffEntry;
  51. import org.eclipse.jgit.dircache.DirCache;
  52. import org.eclipse.jgit.lib.ConfigConstants;
  53. import org.eclipse.jgit.lib.Constants;
  54. import org.eclipse.jgit.lib.FileMode;
  55. import org.eclipse.jgit.lib.ObjectId;
  56. import org.eclipse.jgit.lib.RefUpdate;
  57. import org.eclipse.jgit.lib.RefUpdate.Result;
  58. import org.eclipse.jgit.lib.Repository;
  59. import org.eclipse.jgit.lib.RepositoryTestCase;
  60. import org.eclipse.jgit.lib.StoredConfig;
  61. import org.eclipse.jgit.revwalk.RevCommit;
  62. import org.eclipse.jgit.submodule.SubmoduleWalk;
  63. import org.eclipse.jgit.treewalk.TreeWalk;
  64. import org.eclipse.jgit.treewalk.filter.TreeFilter;
  65. import org.eclipse.jgit.util.FS;
  66. import org.junit.Test;
  67. /**
  68. * Unit tests of {@link CommitCommand}.
  69. */
  70. public class CommitCommandTest extends RepositoryTestCase {
  71. @Test
  72. public void testExecutableRetention() throws Exception {
  73. StoredConfig config = db.getConfig();
  74. config.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
  75. ConfigConstants.CONFIG_KEY_FILEMODE, true);
  76. config.save();
  77. FS executableFs = new FS() {
  78. public boolean supportsExecute() {
  79. return true;
  80. }
  81. public boolean setExecute(File f, boolean canExec) {
  82. return true;
  83. }
  84. public ProcessBuilder runInShell(String cmd, String[] args) {
  85. return null;
  86. }
  87. public boolean retryFailedLockFileCommit() {
  88. return false;
  89. }
  90. public FS newInstance() {
  91. return this;
  92. }
  93. protected File discoverGitPrefix() {
  94. return null;
  95. }
  96. public boolean canExecute(File f) {
  97. return true;
  98. }
  99. };
  100. Git git = Git.open(db.getDirectory(), executableFs);
  101. String path = "a.txt";
  102. writeTrashFile(path, "content");
  103. git.add().addFilepattern(path).call();
  104. RevCommit commit1 = git.commit().setMessage("commit").call();
  105. TreeWalk walk = TreeWalk.forPath(db, path, commit1.getTree());
  106. assertNotNull(walk);
  107. assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0));
  108. FS nonExecutableFs = new FS() {
  109. public boolean supportsExecute() {
  110. return false;
  111. }
  112. public boolean setExecute(File f, boolean canExec) {
  113. return false;
  114. }
  115. public ProcessBuilder runInShell(String cmd, String[] args) {
  116. return null;
  117. }
  118. public boolean retryFailedLockFileCommit() {
  119. return false;
  120. }
  121. public FS newInstance() {
  122. return this;
  123. }
  124. protected File discoverGitPrefix() {
  125. return null;
  126. }
  127. public boolean canExecute(File f) {
  128. return false;
  129. }
  130. };
  131. config = db.getConfig();
  132. config.setBoolean(ConfigConstants.CONFIG_CORE_SECTION, null,
  133. ConfigConstants.CONFIG_KEY_FILEMODE, false);
  134. config.save();
  135. Git git2 = Git.open(db.getDirectory(), nonExecutableFs);
  136. writeTrashFile(path, "content2");
  137. RevCommit commit2 = git2.commit().setOnly(path).setMessage("commit2")
  138. .call();
  139. walk = TreeWalk.forPath(db, path, commit2.getTree());
  140. assertNotNull(walk);
  141. assertEquals(FileMode.EXECUTABLE_FILE, walk.getFileMode(0));
  142. }
  143. @Test
  144. public void commitNewSubmodule() throws Exception {
  145. Git git = new Git(db);
  146. writeTrashFile("file.txt", "content");
  147. git.add().addFilepattern("file.txt").call();
  148. RevCommit commit = git.commit().setMessage("create file").call();
  149. SubmoduleAddCommand command = new SubmoduleAddCommand(db);
  150. String path = "sub";
  151. command.setPath(path);
  152. String uri = db.getDirectory().toURI().toString();
  153. command.setURI(uri);
  154. Repository repo = command.call();
  155. assertNotNull(repo);
  156. SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
  157. assertTrue(generator.next());
  158. assertEquals(path, generator.getPath());
  159. assertEquals(commit, generator.getObjectId());
  160. assertEquals(uri, generator.getModulesUrl());
  161. assertEquals(path, generator.getModulesPath());
  162. assertEquals(uri, generator.getConfigUrl());
  163. assertNotNull(generator.getRepository());
  164. assertEquals(commit, repo.resolve(Constants.HEAD));
  165. RevCommit submoduleCommit = git.commit().setMessage("submodule add")
  166. .setOnly(path).call();
  167. assertNotNull(submoduleCommit);
  168. TreeWalk walk = new TreeWalk(db);
  169. walk.addTree(commit.getTree());
  170. walk.addTree(submoduleCommit.getTree());
  171. walk.setFilter(TreeFilter.ANY_DIFF);
  172. List<DiffEntry> diffs = DiffEntry.scan(walk);
  173. assertEquals(1, diffs.size());
  174. DiffEntry subDiff = diffs.get(0);
  175. assertEquals(FileMode.MISSING, subDiff.getOldMode());
  176. assertEquals(FileMode.GITLINK, subDiff.getNewMode());
  177. assertEquals(ObjectId.zeroId(), subDiff.getOldId().toObjectId());
  178. assertEquals(commit, subDiff.getNewId().toObjectId());
  179. assertEquals(path, subDiff.getNewPath());
  180. }
  181. @Test
  182. public void commitSubmoduleUpdate() throws Exception {
  183. Git git = new Git(db);
  184. writeTrashFile("file.txt", "content");
  185. git.add().addFilepattern("file.txt").call();
  186. RevCommit commit = git.commit().setMessage("create file").call();
  187. writeTrashFile("file.txt", "content2");
  188. git.add().addFilepattern("file.txt").call();
  189. RevCommit commit2 = git.commit().setMessage("edit file").call();
  190. SubmoduleAddCommand command = new SubmoduleAddCommand(db);
  191. String path = "sub";
  192. command.setPath(path);
  193. String uri = db.getDirectory().toURI().toString();
  194. command.setURI(uri);
  195. Repository repo = command.call();
  196. assertNotNull(repo);
  197. SubmoduleWalk generator = SubmoduleWalk.forIndex(db);
  198. assertTrue(generator.next());
  199. assertEquals(path, generator.getPath());
  200. assertEquals(commit2, generator.getObjectId());
  201. assertEquals(uri, generator.getModulesUrl());
  202. assertEquals(path, generator.getModulesPath());
  203. assertEquals(uri, generator.getConfigUrl());
  204. assertNotNull(generator.getRepository());
  205. assertEquals(commit2, repo.resolve(Constants.HEAD));
  206. RevCommit submoduleAddCommit = git.commit().setMessage("submodule add")
  207. .setOnly(path).call();
  208. assertNotNull(submoduleAddCommit);
  209. RefUpdate update = repo.updateRef(Constants.HEAD);
  210. update.setNewObjectId(commit);
  211. assertEquals(Result.FORCED, update.forceUpdate());
  212. RevCommit submoduleEditCommit = git.commit()
  213. .setMessage("submodule add").setOnly(path).call();
  214. assertNotNull(submoduleEditCommit);
  215. TreeWalk walk = new TreeWalk(db);
  216. walk.addTree(submoduleAddCommit.getTree());
  217. walk.addTree(submoduleEditCommit.getTree());
  218. walk.setFilter(TreeFilter.ANY_DIFF);
  219. List<DiffEntry> diffs = DiffEntry.scan(walk);
  220. assertEquals(1, diffs.size());
  221. DiffEntry subDiff = diffs.get(0);
  222. assertEquals(FileMode.GITLINK, subDiff.getOldMode());
  223. assertEquals(FileMode.GITLINK, subDiff.getNewMode());
  224. assertEquals(commit2, subDiff.getOldId().toObjectId());
  225. assertEquals(commit, subDiff.getNewId().toObjectId());
  226. assertEquals(path, subDiff.getNewPath());
  227. assertEquals(path, subDiff.getOldPath());
  228. }
  229. @Test
  230. public void commitUpdatesSmudgedEntries() throws Exception {
  231. Git git = new Git(db);
  232. File file1 = writeTrashFile("file1.txt", "content1");
  233. assertTrue(file1.setLastModified(file1.lastModified() - 5000));
  234. File file2 = writeTrashFile("file2.txt", "content2");
  235. assertTrue(file2.setLastModified(file2.lastModified() - 5000));
  236. File file3 = writeTrashFile("file3.txt", "content3");
  237. assertTrue(file3.setLastModified(file3.lastModified() - 5000));
  238. assertNotNull(git.add().addFilepattern("file1.txt")
  239. .addFilepattern("file2.txt").addFilepattern("file3.txt").call());
  240. RevCommit commit = git.commit().setMessage("add files").call();
  241. assertNotNull(commit);
  242. DirCache cache = DirCache.read(db.getIndexFile(), db.getFS());
  243. int file1Size = cache.getEntry("file1.txt").getLength();
  244. int file2Size = cache.getEntry("file2.txt").getLength();
  245. int file3Size = cache.getEntry("file3.txt").getLength();
  246. ObjectId file2Id = cache.getEntry("file2.txt").getObjectId();
  247. ObjectId file3Id = cache.getEntry("file3.txt").getObjectId();
  248. assertTrue(file1Size > 0);
  249. assertTrue(file2Size > 0);
  250. assertTrue(file3Size > 0);
  251. // Smudge entries
  252. cache = DirCache.lock(db.getIndexFile(), db.getFS());
  253. cache.getEntry("file1.txt").setLength(0);
  254. cache.getEntry("file2.txt").setLength(0);
  255. cache.getEntry("file3.txt").setLength(0);
  256. cache.write();
  257. assertTrue(cache.commit());
  258. // Verify entries smudged
  259. cache = DirCache.read(db.getIndexFile(), db.getFS());
  260. assertEquals(0, cache.getEntry("file1.txt").getLength());
  261. assertEquals(0, cache.getEntry("file2.txt").getLength());
  262. assertEquals(0, cache.getEntry("file3.txt").getLength());
  263. long indexTime = db.getIndexFile().lastModified();
  264. db.getIndexFile().setLastModified(indexTime - 5000);
  265. write(file1, "content4");
  266. assertTrue(file1.setLastModified(file1.lastModified() + 1000));
  267. assertNotNull(git.commit().setMessage("edit file").setOnly("file1.txt")
  268. .call());
  269. cache = db.readDirCache();
  270. assertEquals(file1Size, cache.getEntry("file1.txt").getLength());
  271. assertEquals(file2Size, cache.getEntry("file2.txt").getLength());
  272. assertEquals(file3Size, cache.getEntry("file3.txt").getLength());
  273. assertEquals(file2Id, cache.getEntry("file2.txt").getObjectId());
  274. assertEquals(file3Id, cache.getEntry("file3.txt").getObjectId());
  275. }
  276. @Test
  277. public void commitIgnoresSmudgedEntryWithDifferentId() throws Exception {
  278. Git git = new Git(db);
  279. File file1 = writeTrashFile("file1.txt", "content1");
  280. assertTrue(file1.setLastModified(file1.lastModified() - 5000));
  281. File file2 = writeTrashFile("file2.txt", "content2");
  282. assertTrue(file2.setLastModified(file2.lastModified() - 5000));
  283. assertNotNull(git.add().addFilepattern("file1.txt")
  284. .addFilepattern("file2.txt").call());
  285. RevCommit commit = git.commit().setMessage("add files").call();
  286. assertNotNull(commit);
  287. DirCache cache = DirCache.read(db.getIndexFile(), db.getFS());
  288. int file1Size = cache.getEntry("file1.txt").getLength();
  289. int file2Size = cache.getEntry("file2.txt").getLength();
  290. assertTrue(file1Size > 0);
  291. assertTrue(file2Size > 0);
  292. writeTrashFile("file2.txt", "content3");
  293. assertNotNull(git.add().addFilepattern("file2.txt").call());
  294. writeTrashFile("file2.txt", "content4");
  295. // Smudge entries
  296. cache = DirCache.lock(db.getIndexFile(), db.getFS());
  297. cache.getEntry("file1.txt").setLength(0);
  298. cache.getEntry("file2.txt").setLength(0);
  299. cache.write();
  300. assertTrue(cache.commit());
  301. // Verify entries smudged
  302. cache = db.readDirCache();
  303. assertEquals(0, cache.getEntry("file1.txt").getLength());
  304. assertEquals(0, cache.getEntry("file2.txt").getLength());
  305. long indexTime = db.getIndexFile().lastModified();
  306. db.getIndexFile().setLastModified(indexTime - 5000);
  307. write(file1, "content5");
  308. assertTrue(file1.setLastModified(file1.lastModified() + 1000));
  309. assertNotNull(git.commit().setMessage("edit file").setOnly("file1.txt")
  310. .call());
  311. cache = db.readDirCache();
  312. assertEquals(file1Size, cache.getEntry("file1.txt").getLength());
  313. assertEquals(0, cache.getEntry("file2.txt").getLength());
  314. }
  315. @Test
  316. public void commitAfterSquashMerge() throws Exception {
  317. Git git = new Git(db);
  318. writeTrashFile("file1", "file1");
  319. git.add().addFilepattern("file1").call();
  320. RevCommit first = git.commit().setMessage("initial commit").call();
  321. assertTrue(new File(db.getWorkTree(), "file1").exists());
  322. createBranch(first, "refs/heads/branch1");
  323. checkoutBranch("refs/heads/branch1");
  324. writeTrashFile("file2", "file2");
  325. git.add().addFilepattern("file2").call();
  326. git.commit().setMessage("second commit").call();
  327. assertTrue(new File(db.getWorkTree(), "file2").exists());
  328. checkoutBranch("refs/heads/master");
  329. MergeResult result = git.merge().include(db.getRef("branch1"))
  330. .setSquash(true).call();
  331. assertTrue(new File(db.getWorkTree(), "file1").exists());
  332. assertTrue(new File(db.getWorkTree(), "file2").exists());
  333. assertEquals(MergeResult.MergeStatus.FAST_FORWARD_SQUASHED,
  334. result.getMergeStatus());
  335. // comment not set, should be inferred from SQUASH_MSG
  336. RevCommit squashedCommit = git.commit().call();
  337. assertEquals(1, squashedCommit.getParentCount());
  338. assertNull(db.readSquashCommitMsg());
  339. assertEquals("commit: Squashed commit of the following:", db
  340. .getReflogReader(Constants.HEAD).getLastEntry().getComment());
  341. assertEquals("commit: Squashed commit of the following:", db
  342. .getReflogReader(db.getBranch()).getLastEntry().getComment());
  343. }
  344. }