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.

StashCreateCommandTest.java 15KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. /*
  2. * Copyright (C) 2012, GitHub Inc. 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 java.io.File;
  17. import java.io.IOException;
  18. import java.util.List;
  19. import org.eclipse.jgit.api.errors.UnmergedPathsException;
  20. import org.eclipse.jgit.diff.DiffEntry;
  21. import org.eclipse.jgit.junit.RepositoryTestCase;
  22. import org.eclipse.jgit.lib.Constants;
  23. import org.eclipse.jgit.lib.ObjectId;
  24. import org.eclipse.jgit.lib.PersonIdent;
  25. import org.eclipse.jgit.lib.Ref;
  26. import org.eclipse.jgit.lib.ReflogEntry;
  27. import org.eclipse.jgit.lib.ReflogReader;
  28. import org.eclipse.jgit.revwalk.RevCommit;
  29. import org.eclipse.jgit.revwalk.RevWalk;
  30. import org.eclipse.jgit.treewalk.TreeWalk;
  31. import org.eclipse.jgit.treewalk.filter.TreeFilter;
  32. import org.eclipse.jgit.util.FileUtils;
  33. import org.junit.Before;
  34. import org.junit.Test;
  35. /**
  36. * Unit tests of {@link StashCreateCommand}
  37. */
  38. public class StashCreateCommandTest extends RepositoryTestCase {
  39. private RevCommit head;
  40. private Git git;
  41. private File committedFile;
  42. private File untrackedFile;
  43. @Override
  44. @Before
  45. public void setUp() throws Exception {
  46. super.setUp();
  47. git = Git.wrap(db);
  48. committedFile = writeTrashFile("file.txt", "content");
  49. git.add().addFilepattern("file.txt").call();
  50. head = git.commit().setMessage("add file").call();
  51. assertNotNull(head);
  52. untrackedFile = writeTrashFile("untracked.txt", "content");
  53. }
  54. private void validateStashedCommit(RevCommit commit)
  55. throws IOException {
  56. validateStashedCommit(commit, 2);
  57. }
  58. /**
  59. * Core validation to be performed on all stashed commits
  60. *
  61. * @param commit
  62. * @param parentCount
  63. * number of parent commits required
  64. * @throws IOException
  65. */
  66. private void validateStashedCommit(final RevCommit commit,
  67. int parentCount)
  68. throws IOException {
  69. assertNotNull(commit);
  70. Ref stashRef = db.exactRef(Constants.R_STASH);
  71. assertNotNull(stashRef);
  72. assertEquals(commit, stashRef.getObjectId());
  73. assertNotNull(commit.getAuthorIdent());
  74. assertEquals(commit.getAuthorIdent(), commit.getCommitterIdent());
  75. assertEquals(parentCount, commit.getParentCount());
  76. // Load parents
  77. try (RevWalk walk = new RevWalk(db)) {
  78. for (RevCommit parent : commit.getParents())
  79. walk.parseBody(parent);
  80. }
  81. assertEquals(1, commit.getParent(1).getParentCount());
  82. assertEquals(head, commit.getParent(1).getParent(0));
  83. assertFalse("Head tree matches stashed commit tree", commit.getTree()
  84. .equals(head.getTree()));
  85. assertEquals(head, commit.getParent(0));
  86. assertFalse(commit.getFullMessage().equals(
  87. commit.getParent(1).getFullMessage()));
  88. }
  89. private TreeWalk createTreeWalk() {
  90. TreeWalk walk = new TreeWalk(db);
  91. walk.setRecursive(true);
  92. walk.setFilter(TreeFilter.ANY_DIFF);
  93. return walk;
  94. }
  95. private List<DiffEntry> diffWorkingAgainstHead(RevCommit commit)
  96. throws IOException {
  97. try (TreeWalk walk = createTreeWalk()) {
  98. walk.addTree(commit.getParent(0).getTree());
  99. walk.addTree(commit.getTree());
  100. return DiffEntry.scan(walk);
  101. }
  102. }
  103. private List<DiffEntry> diffIndexAgainstHead(RevCommit commit)
  104. throws IOException {
  105. try (TreeWalk walk = createTreeWalk()) {
  106. walk.addTree(commit.getParent(0).getTree());
  107. walk.addTree(commit.getParent(1).getTree());
  108. return DiffEntry.scan(walk);
  109. }
  110. }
  111. private List<DiffEntry> diffIndexAgainstWorking(RevCommit commit)
  112. throws IOException {
  113. try (TreeWalk walk = createTreeWalk()) {
  114. walk.addTree(commit.getParent(1).getTree());
  115. walk.addTree(commit.getTree());
  116. return DiffEntry.scan(walk);
  117. }
  118. }
  119. @Test
  120. public void noLocalChanges() throws Exception {
  121. assertNull(git.stashCreate().call());
  122. }
  123. @Test
  124. public void workingDirectoryDelete() throws Exception {
  125. deleteTrashFile("file.txt");
  126. RevCommit stashed = git.stashCreate().call();
  127. assertNotNull(stashed);
  128. assertEquals("content", read(committedFile));
  129. validateStashedCommit(stashed);
  130. assertEquals(head.getTree(), stashed.getParent(1).getTree());
  131. List<DiffEntry> diffs = diffWorkingAgainstHead(stashed);
  132. assertEquals(1, diffs.size());
  133. assertEquals(DiffEntry.ChangeType.DELETE, diffs.get(0).getChangeType());
  134. assertEquals("file.txt", diffs.get(0).getOldPath());
  135. }
  136. @Test
  137. public void indexAdd() throws Exception {
  138. File addedFile = writeTrashFile("file2.txt", "content2");
  139. git.add().addFilepattern("file2.txt").call();
  140. RevCommit stashed = Git.wrap(db).stashCreate().call();
  141. assertNotNull(stashed);
  142. assertFalse(addedFile.exists());
  143. validateStashedCommit(stashed);
  144. assertEquals(stashed.getTree(), stashed.getParent(1).getTree());
  145. List<DiffEntry> diffs = diffWorkingAgainstHead(stashed);
  146. assertEquals(1, diffs.size());
  147. assertEquals(DiffEntry.ChangeType.ADD, diffs.get(0).getChangeType());
  148. assertEquals("file2.txt", diffs.get(0).getNewPath());
  149. }
  150. @Test
  151. public void newFileInIndexThenModifiedInWorkTree() throws Exception {
  152. writeTrashFile("file", "content");
  153. git.add().addFilepattern("file").call();
  154. writeTrashFile("file", "content2");
  155. RevCommit stashedWorkTree = Git.wrap(db).stashCreate().call();
  156. validateStashedCommit(stashedWorkTree);
  157. try (RevWalk walk = new RevWalk(db)) {
  158. RevCommit stashedIndex = stashedWorkTree.getParent(1);
  159. walk.parseBody(stashedIndex);
  160. walk.parseBody(stashedIndex.getTree());
  161. walk.parseBody(stashedIndex.getParent(0));
  162. }
  163. List<DiffEntry> workTreeStashAgainstWorkTree = diffWorkingAgainstHead(stashedWorkTree);
  164. assertEquals(1, workTreeStashAgainstWorkTree.size());
  165. List<DiffEntry> workIndexAgainstWorkTree = diffIndexAgainstHead(stashedWorkTree);
  166. assertEquals(1, workIndexAgainstWorkTree.size());
  167. List<DiffEntry> indexStashAgainstWorkTree = diffIndexAgainstWorking(stashedWorkTree);
  168. assertEquals(1, indexStashAgainstWorkTree.size());
  169. }
  170. @Test
  171. public void indexDelete() throws Exception {
  172. git.rm().addFilepattern("file.txt").call();
  173. RevCommit stashed = Git.wrap(db).stashCreate().call();
  174. assertNotNull(stashed);
  175. assertEquals("content", read(committedFile));
  176. validateStashedCommit(stashed);
  177. assertEquals(stashed.getTree(), stashed.getParent(1).getTree());
  178. List<DiffEntry> diffs = diffWorkingAgainstHead(stashed);
  179. assertEquals(1, diffs.size());
  180. assertEquals(DiffEntry.ChangeType.DELETE, diffs.get(0).getChangeType());
  181. assertEquals("file.txt", diffs.get(0).getOldPath());
  182. }
  183. @Test
  184. public void workingDirectoryModify() throws Exception {
  185. writeTrashFile("file.txt", "content2");
  186. RevCommit stashed = Git.wrap(db).stashCreate().call();
  187. assertNotNull(stashed);
  188. assertEquals("content", read(committedFile));
  189. validateStashedCommit(stashed);
  190. assertEquals(head.getTree(), stashed.getParent(1).getTree());
  191. List<DiffEntry> diffs = diffWorkingAgainstHead(stashed);
  192. assertEquals(1, diffs.size());
  193. assertEquals(DiffEntry.ChangeType.MODIFY, diffs.get(0).getChangeType());
  194. assertEquals("file.txt", diffs.get(0).getNewPath());
  195. }
  196. @Test
  197. public void workingDirectoryModifyInSubfolder() throws Exception {
  198. String path = "d1/d2/f.txt";
  199. File subfolderFile = writeTrashFile(path, "content");
  200. git.add().addFilepattern(path).call();
  201. head = git.commit().setMessage("add file").call();
  202. writeTrashFile(path, "content2");
  203. RevCommit stashed = Git.wrap(db).stashCreate().call();
  204. assertNotNull(stashed);
  205. assertEquals("content", read(subfolderFile));
  206. validateStashedCommit(stashed);
  207. assertEquals(head.getTree(), stashed.getParent(1).getTree());
  208. List<DiffEntry> diffs = diffWorkingAgainstHead(stashed);
  209. assertEquals(1, diffs.size());
  210. assertEquals(DiffEntry.ChangeType.MODIFY, diffs.get(0).getChangeType());
  211. assertEquals(path, diffs.get(0).getNewPath());
  212. }
  213. @Test
  214. public void workingDirectoryModifyIndexChanged() throws Exception {
  215. writeTrashFile("file.txt", "content2");
  216. git.add().addFilepattern("file.txt").call();
  217. writeTrashFile("file.txt", "content3");
  218. RevCommit stashed = Git.wrap(db).stashCreate().call();
  219. assertNotNull(stashed);
  220. assertEquals("content", read(committedFile));
  221. validateStashedCommit(stashed);
  222. assertFalse(stashed.getTree().equals(stashed.getParent(1).getTree()));
  223. List<DiffEntry> workingDiffs = diffWorkingAgainstHead(stashed);
  224. assertEquals(1, workingDiffs.size());
  225. assertEquals(DiffEntry.ChangeType.MODIFY, workingDiffs.get(0)
  226. .getChangeType());
  227. assertEquals("file.txt", workingDiffs.get(0).getNewPath());
  228. List<DiffEntry> indexDiffs = diffIndexAgainstHead(stashed);
  229. assertEquals(1, indexDiffs.size());
  230. assertEquals(DiffEntry.ChangeType.MODIFY, indexDiffs.get(0)
  231. .getChangeType());
  232. assertEquals("file.txt", indexDiffs.get(0).getNewPath());
  233. assertEquals(workingDiffs.get(0).getOldId(), indexDiffs.get(0)
  234. .getOldId());
  235. assertFalse(workingDiffs.get(0).getNewId()
  236. .equals(indexDiffs.get(0).getNewId()));
  237. }
  238. @Test
  239. public void workingDirectoryCleanIndexModify() throws Exception {
  240. writeTrashFile("file.txt", "content2");
  241. git.add().addFilepattern("file.txt").call();
  242. writeTrashFile("file.txt", "content");
  243. RevCommit stashed = Git.wrap(db).stashCreate().call();
  244. assertNotNull(stashed);
  245. assertEquals("content", read(committedFile));
  246. validateStashedCommit(stashed);
  247. assertEquals(stashed.getParent(1).getTree(), stashed.getTree());
  248. List<DiffEntry> workingDiffs = diffWorkingAgainstHead(stashed);
  249. assertEquals(1, workingDiffs.size());
  250. assertEquals(DiffEntry.ChangeType.MODIFY, workingDiffs.get(0)
  251. .getChangeType());
  252. assertEquals("file.txt", workingDiffs.get(0).getNewPath());
  253. List<DiffEntry> indexDiffs = diffIndexAgainstHead(stashed);
  254. assertEquals(1, indexDiffs.size());
  255. assertEquals(DiffEntry.ChangeType.MODIFY, indexDiffs.get(0)
  256. .getChangeType());
  257. assertEquals("file.txt", indexDiffs.get(0).getNewPath());
  258. assertEquals(workingDiffs.get(0).getOldId(), indexDiffs.get(0)
  259. .getOldId());
  260. assertTrue(workingDiffs.get(0).getNewId()
  261. .equals(indexDiffs.get(0).getNewId()));
  262. }
  263. @Test
  264. public void workingDirectoryDeleteIndexAdd() throws Exception {
  265. String path = "file2.txt";
  266. File added = writeTrashFile(path, "content2");
  267. assertTrue(added.exists());
  268. git.add().addFilepattern(path).call();
  269. FileUtils.delete(added);
  270. assertFalse(added.exists());
  271. RevCommit stashed = Git.wrap(db).stashCreate().call();
  272. assertNotNull(stashed);
  273. assertFalse(added.exists());
  274. validateStashedCommit(stashed);
  275. assertEquals(stashed.getParent(1).getTree(), stashed.getTree());
  276. List<DiffEntry> workingDiffs = diffWorkingAgainstHead(stashed);
  277. assertEquals(1, workingDiffs.size());
  278. assertEquals(DiffEntry.ChangeType.ADD, workingDiffs.get(0)
  279. .getChangeType());
  280. assertEquals(path, workingDiffs.get(0).getNewPath());
  281. List<DiffEntry> indexDiffs = diffIndexAgainstHead(stashed);
  282. assertEquals(1, indexDiffs.size());
  283. assertEquals(DiffEntry.ChangeType.ADD, indexDiffs.get(0)
  284. .getChangeType());
  285. assertEquals(path, indexDiffs.get(0).getNewPath());
  286. assertEquals(workingDiffs.get(0).getOldId(), indexDiffs.get(0)
  287. .getOldId());
  288. assertTrue(workingDiffs.get(0).getNewId()
  289. .equals(indexDiffs.get(0).getNewId()));
  290. }
  291. @Test
  292. public void workingDirectoryDeleteIndexEdit() throws Exception {
  293. File edited = writeTrashFile("file.txt", "content2");
  294. git.add().addFilepattern("file.txt").call();
  295. FileUtils.delete(edited);
  296. assertFalse(edited.exists());
  297. RevCommit stashed = Git.wrap(db).stashCreate().call();
  298. assertNotNull(stashed);
  299. assertEquals("content", read(committedFile));
  300. validateStashedCommit(stashed);
  301. assertFalse(stashed.getTree().equals(stashed.getParent(1).getTree()));
  302. List<DiffEntry> workingDiffs = diffWorkingAgainstHead(stashed);
  303. assertEquals(1, workingDiffs.size());
  304. assertEquals(DiffEntry.ChangeType.DELETE, workingDiffs.get(0)
  305. .getChangeType());
  306. assertEquals("file.txt", workingDiffs.get(0).getOldPath());
  307. List<DiffEntry> indexDiffs = diffIndexAgainstHead(stashed);
  308. assertEquals(1, indexDiffs.size());
  309. assertEquals(DiffEntry.ChangeType.MODIFY, indexDiffs.get(0)
  310. .getChangeType());
  311. assertEquals("file.txt", indexDiffs.get(0).getNewPath());
  312. assertEquals(workingDiffs.get(0).getOldId(), indexDiffs.get(0)
  313. .getOldId());
  314. assertFalse(workingDiffs.get(0).getNewId()
  315. .equals(indexDiffs.get(0).getNewId()));
  316. }
  317. @Test
  318. public void multipleEdits() throws Exception {
  319. git.rm().addFilepattern("file.txt").call();
  320. File addedFile = writeTrashFile("file2.txt", "content2");
  321. git.add().addFilepattern("file2.txt").call();
  322. RevCommit stashed = Git.wrap(db).stashCreate().call();
  323. assertNotNull(stashed);
  324. assertFalse(addedFile.exists());
  325. validateStashedCommit(stashed);
  326. assertEquals(stashed.getTree(), stashed.getParent(1).getTree());
  327. List<DiffEntry> diffs = diffWorkingAgainstHead(stashed);
  328. assertEquals(2, diffs.size());
  329. assertEquals(DiffEntry.ChangeType.DELETE, diffs.get(0).getChangeType());
  330. assertEquals("file.txt", diffs.get(0).getOldPath());
  331. assertEquals(DiffEntry.ChangeType.ADD, diffs.get(1).getChangeType());
  332. assertEquals("file2.txt", diffs.get(1).getNewPath());
  333. }
  334. @Test
  335. public void refLogIncludesCommitMessage() throws Exception {
  336. PersonIdent who = new PersonIdent("user", "user@email.com");
  337. deleteTrashFile("file.txt");
  338. RevCommit stashed = git.stashCreate().setPerson(who).call();
  339. assertNotNull(stashed);
  340. assertEquals("content", read(committedFile));
  341. validateStashedCommit(stashed);
  342. ReflogReader reader = git.getRepository().getReflogReader(
  343. Constants.R_STASH);
  344. ReflogEntry entry = reader.getLastEntry();
  345. assertNotNull(entry);
  346. assertEquals(ObjectId.zeroId(), entry.getOldId());
  347. assertEquals(stashed, entry.getNewId());
  348. assertEquals(who, entry.getWho());
  349. assertEquals(stashed.getFullMessage(), entry.getComment());
  350. }
  351. @Test(expected = UnmergedPathsException.class)
  352. public void unmergedPathsShouldCauseException() throws Exception {
  353. commitFile("file.txt", "master", "base");
  354. RevCommit side = commitFile("file.txt", "side", "side");
  355. commitFile("file.txt", "master", "master");
  356. git.merge().include(side).call();
  357. git.stashCreate().call();
  358. }
  359. @Test
  360. public void untrackedFileIncluded() throws Exception {
  361. String trackedPath = "tracked.txt";
  362. writeTrashFile(trackedPath, "content2");
  363. git.add().addFilepattern(trackedPath).call();
  364. RevCommit stashed = git.stashCreate()
  365. .setIncludeUntracked(true).call();
  366. validateStashedCommit(stashed, 3);
  367. assertEquals(
  368. "Expected commits for workingDir,stashedIndex and untrackedFiles.",
  369. 3, stashed.getParentCount());
  370. assertFalse("untracked file should be deleted.", untrackedFile.exists());
  371. }
  372. @Test
  373. public void untrackedFileNotIncluded() throws Exception {
  374. String trackedPath = "tracked.txt";
  375. // at least one modification needed
  376. writeTrashFile(trackedPath, "content2");
  377. git.add().addFilepattern(trackedPath).call();
  378. RevCommit stashed = git.stashCreate().call();
  379. validateStashedCommit(stashed);
  380. assertTrue("untracked file should be left untouched.",
  381. untrackedFile.exists());
  382. assertEquals("content", read(untrackedFile));
  383. }
  384. }