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.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844
  1. /*
  2. * Copyright (C) 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.assertFalse;
  46. import static org.junit.Assert.assertNotNull;
  47. import static org.junit.Assert.assertTrue;
  48. import static org.junit.Assert.fail;
  49. import java.io.File;
  50. import java.text.MessageFormat;
  51. import org.eclipse.jgit.api.errors.InvalidRefNameException;
  52. import org.eclipse.jgit.api.errors.JGitInternalException;
  53. import org.eclipse.jgit.api.errors.NoHeadException;
  54. import org.eclipse.jgit.api.errors.StashApplyFailureException;
  55. import org.eclipse.jgit.events.ChangeRecorder;
  56. import org.eclipse.jgit.events.ListenerHandle;
  57. import org.eclipse.jgit.internal.JGitText;
  58. import org.eclipse.jgit.junit.RepositoryTestCase;
  59. import org.eclipse.jgit.lib.ObjectId;
  60. import org.eclipse.jgit.lib.Repository;
  61. import org.eclipse.jgit.revwalk.RevCommit;
  62. import org.eclipse.jgit.util.FileUtils;
  63. import org.junit.After;
  64. import org.junit.Before;
  65. import org.junit.Test;
  66. /**
  67. * Unit tests of {@link StashApplyCommand}
  68. */
  69. public class StashApplyCommandTest extends RepositoryTestCase {
  70. private static final String PATH = "file.txt";
  71. private RevCommit head;
  72. private Git git;
  73. private File committedFile;
  74. private ChangeRecorder recorder;
  75. private ListenerHandle handle;
  76. @Override
  77. @Before
  78. public void setUp() throws Exception {
  79. super.setUp();
  80. git = Git.wrap(db);
  81. recorder = new ChangeRecorder();
  82. handle = db.getListenerList().addWorkingTreeModifiedListener(recorder);
  83. committedFile = writeTrashFile(PATH, "content");
  84. git.add().addFilepattern(PATH).call();
  85. head = git.commit().setMessage("add file").call();
  86. assertNotNull(head);
  87. recorder.assertNoEvent();
  88. }
  89. @Override
  90. @After
  91. public void tearDown() throws Exception {
  92. if (handle != null) {
  93. handle.remove();
  94. }
  95. super.tearDown();
  96. }
  97. @Test
  98. public void workingDirectoryDelete() throws Exception {
  99. deleteTrashFile(PATH);
  100. assertFalse(committedFile.exists());
  101. RevCommit stashed = git.stashCreate().call();
  102. assertNotNull(stashed);
  103. assertEquals("content", read(committedFile));
  104. recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY);
  105. ObjectId unstashed = git.stashApply().call();
  106. assertEquals(stashed, unstashed);
  107. assertFalse(committedFile.exists());
  108. recorder.assertEvent(ChangeRecorder.EMPTY, new String[] { PATH });
  109. Status status = git.status().call();
  110. assertTrue(status.getAdded().isEmpty());
  111. assertTrue(status.getChanged().isEmpty());
  112. assertTrue(status.getConflicting().isEmpty());
  113. assertTrue(status.getModified().isEmpty());
  114. assertTrue(status.getUntracked().isEmpty());
  115. assertTrue(status.getRemoved().isEmpty());
  116. assertEquals(1, status.getMissing().size());
  117. assertTrue(status.getMissing().contains(PATH));
  118. }
  119. @Test
  120. public void indexAdd() throws Exception {
  121. String addedPath = "file2.txt";
  122. File addedFile = writeTrashFile(addedPath, "content2");
  123. git.add().addFilepattern(addedPath).call();
  124. RevCommit stashed = git.stashCreate().call();
  125. assertNotNull(stashed);
  126. assertFalse(addedFile.exists());
  127. recorder.assertEvent(ChangeRecorder.EMPTY, new String[] { addedPath });
  128. ObjectId unstashed = git.stashApply().call();
  129. assertEquals(stashed, unstashed);
  130. assertTrue(addedFile.exists());
  131. assertEquals("content2", read(addedFile));
  132. recorder.assertEvent(new String[] { addedPath }, ChangeRecorder.EMPTY);
  133. Status status = git.status().call();
  134. assertTrue(status.getChanged().isEmpty());
  135. assertTrue(status.getConflicting().isEmpty());
  136. assertTrue(status.getMissing().isEmpty());
  137. assertTrue(status.getModified().isEmpty());
  138. assertTrue(status.getRemoved().isEmpty());
  139. assertTrue(status.getUntracked().isEmpty());
  140. assertEquals(1, status.getAdded().size());
  141. assertTrue(status.getAdded().contains(addedPath));
  142. }
  143. @Test
  144. public void indexDelete() throws Exception {
  145. git.rm().addFilepattern("file.txt").call();
  146. recorder.assertEvent(ChangeRecorder.EMPTY, new String[] { "file.txt" });
  147. RevCommit stashed = git.stashCreate().call();
  148. assertNotNull(stashed);
  149. assertEquals("content", read(committedFile));
  150. recorder.assertEvent(new String[] { "file.txt" }, ChangeRecorder.EMPTY);
  151. ObjectId unstashed = git.stashApply().call();
  152. assertEquals(stashed, unstashed);
  153. assertFalse(committedFile.exists());
  154. recorder.assertEvent(ChangeRecorder.EMPTY, new String[] { "file.txt" });
  155. Status status = git.status().call();
  156. assertTrue(status.getAdded().isEmpty());
  157. assertTrue(status.getChanged().isEmpty());
  158. assertTrue(status.getConflicting().isEmpty());
  159. assertTrue(status.getModified().isEmpty());
  160. assertTrue(status.getMissing().isEmpty());
  161. assertTrue(status.getUntracked().isEmpty());
  162. assertEquals(1, status.getRemoved().size());
  163. assertTrue(status.getRemoved().contains(PATH));
  164. }
  165. @Test
  166. public void workingDirectoryModify() throws Exception {
  167. writeTrashFile("file.txt", "content2");
  168. RevCommit stashed = git.stashCreate().call();
  169. assertNotNull(stashed);
  170. assertEquals("content", read(committedFile));
  171. recorder.assertEvent(new String[] { "file.txt" }, ChangeRecorder.EMPTY);
  172. ObjectId unstashed = git.stashApply().call();
  173. assertEquals(stashed, unstashed);
  174. assertEquals("content2", read(committedFile));
  175. recorder.assertEvent(new String[] { "file.txt" }, ChangeRecorder.EMPTY);
  176. Status status = git.status().call();
  177. assertTrue(status.getAdded().isEmpty());
  178. assertTrue(status.getChanged().isEmpty());
  179. assertTrue(status.getConflicting().isEmpty());
  180. assertTrue(status.getMissing().isEmpty());
  181. assertTrue(status.getRemoved().isEmpty());
  182. assertTrue(status.getUntracked().isEmpty());
  183. assertEquals(1, status.getModified().size());
  184. assertTrue(status.getModified().contains(PATH));
  185. }
  186. @Test
  187. public void workingDirectoryModifyInSubfolder() throws Exception {
  188. String path = "d1/d2/f.txt";
  189. File subfolderFile = writeTrashFile(path, "content");
  190. git.add().addFilepattern(path).call();
  191. head = git.commit().setMessage("add file").call();
  192. recorder.assertNoEvent();
  193. writeTrashFile(path, "content2");
  194. RevCommit stashed = git.stashCreate().call();
  195. assertNotNull(stashed);
  196. assertEquals("content", read(subfolderFile));
  197. recorder.assertEvent(new String[] { "d1/d2/f.txt" },
  198. ChangeRecorder.EMPTY);
  199. ObjectId unstashed = git.stashApply().call();
  200. assertEquals(stashed, unstashed);
  201. assertEquals("content2", read(subfolderFile));
  202. recorder.assertEvent(new String[] { "d1/d2/f.txt", "d1/d2", "d1" },
  203. ChangeRecorder.EMPTY);
  204. Status status = git.status().call();
  205. assertTrue(status.getAdded().isEmpty());
  206. assertTrue(status.getChanged().isEmpty());
  207. assertTrue(status.getConflicting().isEmpty());
  208. assertTrue(status.getMissing().isEmpty());
  209. assertTrue(status.getRemoved().isEmpty());
  210. assertTrue(status.getUntracked().isEmpty());
  211. assertEquals(1, status.getModified().size());
  212. assertTrue(status.getModified().contains(path));
  213. }
  214. @Test
  215. public void workingDirectoryModifyIndexChanged() throws Exception {
  216. writeTrashFile("file.txt", "content2");
  217. git.add().addFilepattern("file.txt").call();
  218. writeTrashFile("file.txt", "content3");
  219. RevCommit stashed = git.stashCreate().call();
  220. assertNotNull(stashed);
  221. assertEquals("content", read(committedFile));
  222. recorder.assertEvent(new String[] { "file.txt" }, ChangeRecorder.EMPTY);
  223. ObjectId unstashed = git.stashApply().call();
  224. assertEquals(stashed, unstashed);
  225. assertEquals("content3", read(committedFile));
  226. recorder.assertEvent(new String[] { "file.txt" }, ChangeRecorder.EMPTY);
  227. Status status = git.status().call();
  228. assertTrue(status.getAdded().isEmpty());
  229. assertTrue(status.getConflicting().isEmpty());
  230. assertTrue(status.getMissing().isEmpty());
  231. assertTrue(status.getRemoved().isEmpty());
  232. assertTrue(status.getUntracked().isEmpty());
  233. assertEquals(1, status.getChanged().size());
  234. assertTrue(status.getChanged().contains(PATH));
  235. assertEquals(1, status.getModified().size());
  236. assertTrue(status.getModified().contains(PATH));
  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.stashCreate().call();
  244. assertNotNull(stashed);
  245. assertEquals("content", read(committedFile));
  246. recorder.assertEvent(new String[] { "file.txt" }, ChangeRecorder.EMPTY);
  247. ObjectId unstashed = git.stashApply().call();
  248. assertEquals(stashed, unstashed);
  249. assertEquals("content2", read(committedFile));
  250. recorder.assertEvent(new String[] { "file.txt" }, ChangeRecorder.EMPTY);
  251. Status status = git.status().call();
  252. assertTrue(status.getAdded().isEmpty());
  253. assertTrue(status.getConflicting().isEmpty());
  254. assertTrue(status.getMissing().isEmpty());
  255. assertTrue(status.getModified().isEmpty());
  256. assertTrue(status.getRemoved().isEmpty());
  257. assertTrue(status.getUntracked().isEmpty());
  258. assertEquals(1, status.getChanged().size());
  259. assertTrue(status.getChanged().contains(PATH));
  260. }
  261. @Test
  262. public void workingDirectoryDeleteIndexAdd() throws Exception {
  263. String path = "file2.txt";
  264. File added = writeTrashFile(path, "content2");
  265. assertTrue(added.exists());
  266. git.add().addFilepattern(path).call();
  267. FileUtils.delete(added);
  268. assertFalse(added.exists());
  269. RevCommit stashed = git.stashCreate().call();
  270. assertNotNull(stashed);
  271. assertFalse(added.exists());
  272. recorder.assertNoEvent();
  273. ObjectId unstashed = git.stashApply().call();
  274. assertEquals(stashed, unstashed);
  275. assertEquals("content2", read(added));
  276. recorder.assertEvent(new String[] { path }, ChangeRecorder.EMPTY);
  277. Status status = git.status().call();
  278. assertTrue(status.getChanged().isEmpty());
  279. assertTrue(status.getConflicting().isEmpty());
  280. assertTrue(status.getMissing().isEmpty());
  281. assertTrue(status.getModified().isEmpty());
  282. assertTrue(status.getRemoved().isEmpty());
  283. assertTrue(status.getUntracked().isEmpty());
  284. assertEquals(1, status.getAdded().size());
  285. assertTrue(status.getAdded().contains(path));
  286. }
  287. @Test
  288. public void workingDirectoryDeleteIndexEdit() throws Exception {
  289. writeTrashFile(PATH, "content2");
  290. git.add().addFilepattern(PATH).call();
  291. FileUtils.delete(committedFile);
  292. assertFalse(committedFile.exists());
  293. RevCommit stashed = git.stashCreate().call();
  294. assertNotNull(stashed);
  295. assertEquals("content", read(committedFile));
  296. recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY);
  297. ObjectId unstashed = git.stashApply().call();
  298. assertEquals(stashed, unstashed);
  299. assertFalse(committedFile.exists());
  300. recorder.assertEvent(ChangeRecorder.EMPTY, new String[] { PATH });
  301. Status status = git.status().call();
  302. assertTrue(status.getAdded().isEmpty());
  303. assertEquals(1, status.getChanged().size());
  304. assertTrue(status.getChanged().contains(PATH));
  305. assertTrue(status.getConflicting().isEmpty());
  306. assertEquals(1, status.getMissing().size());
  307. assertTrue(status.getMissing().contains(PATH));
  308. assertTrue(status.getModified().isEmpty());
  309. assertTrue(status.getUntracked().isEmpty());
  310. assertTrue(status.getRemoved().isEmpty());
  311. }
  312. @Test
  313. public void multipleEdits() throws Exception {
  314. String addedPath = "file2.txt";
  315. git.rm().addFilepattern(PATH).call();
  316. File addedFile = writeTrashFile(addedPath, "content2");
  317. git.add().addFilepattern(addedPath).call();
  318. RevCommit stashed = git.stashCreate().call();
  319. assertNotNull(stashed);
  320. assertTrue(committedFile.exists());
  321. assertFalse(addedFile.exists());
  322. recorder.assertEvent(new String[] { PATH },
  323. new String[] { "file2.txt" });
  324. ObjectId unstashed = git.stashApply().call();
  325. assertEquals(stashed, unstashed);
  326. recorder.assertEvent(new String[] { "file2.txt" },
  327. new String[] { PATH });
  328. Status status = git.status().call();
  329. assertTrue(status.getChanged().isEmpty());
  330. assertTrue(status.getConflicting().isEmpty());
  331. assertTrue(status.getMissing().isEmpty());
  332. assertTrue(status.getModified().isEmpty());
  333. assertTrue(status.getUntracked().isEmpty());
  334. assertEquals(1, status.getRemoved().size());
  335. assertTrue(status.getRemoved().contains(PATH));
  336. assertEquals(1, status.getAdded().size());
  337. assertTrue(status.getAdded().contains(addedPath));
  338. }
  339. @Test
  340. public void workingDirectoryContentConflict() throws Exception {
  341. writeTrashFile(PATH, "content2");
  342. RevCommit stashed = git.stashCreate().call();
  343. assertNotNull(stashed);
  344. assertEquals("content", read(committedFile));
  345. assertTrue(git.status().call().isClean());
  346. recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY);
  347. writeTrashFile(PATH, "content3");
  348. try {
  349. git.stashApply().call();
  350. fail("Exception not thrown");
  351. } catch (StashApplyFailureException e) {
  352. // expected
  353. }
  354. assertEquals("content3", read(PATH));
  355. recorder.assertNoEvent();
  356. }
  357. @Test
  358. public void stashedContentMerge() throws Exception {
  359. writeTrashFile(PATH, "content\nmore content\n");
  360. git.add().addFilepattern(PATH).call();
  361. git.commit().setMessage("more content").call();
  362. writeTrashFile(PATH, "content\nhead change\nmore content\n");
  363. git.add().addFilepattern(PATH).call();
  364. git.commit().setMessage("even content").call();
  365. writeTrashFile(PATH, "content\nstashed change\nmore content\n");
  366. RevCommit stashed = git.stashCreate().call();
  367. assertNotNull(stashed);
  368. assertEquals("content\nhead change\nmore content\n",
  369. read(committedFile));
  370. assertTrue(git.status().call().isClean());
  371. recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY);
  372. writeTrashFile(PATH, "content\nmore content\ncommitted change\n");
  373. git.add().addFilepattern(PATH).call();
  374. git.commit().setMessage("committed change").call();
  375. recorder.assertNoEvent();
  376. try {
  377. git.stashApply().call();
  378. fail("Expected conflict");
  379. } catch (StashApplyFailureException e) {
  380. // expected
  381. }
  382. recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY);
  383. Status status = new StatusCommand(db).call();
  384. assertEquals(1, status.getConflicting().size());
  385. assertEquals(
  386. "content\n<<<<<<< HEAD\n=======\nstashed change\n>>>>>>> stash\nmore content\ncommitted change\n",
  387. read(PATH));
  388. }
  389. @Test
  390. public void stashedApplyOnOtherBranch() throws Exception {
  391. writeTrashFile(PATH, "content\nmore content\n");
  392. git.add().addFilepattern(PATH).call();
  393. git.commit().setMessage("more content").call();
  394. String path2 = "file2.txt";
  395. File file2 = writeTrashFile(path2, "content\nmore content\n");
  396. git.add().addFilepattern(PATH).call();
  397. git.add().addFilepattern(path2).call();
  398. git.commit().setMessage("even content").call();
  399. String otherBranch = "otherBranch";
  400. git.branchCreate().setName(otherBranch).call();
  401. writeTrashFile(PATH, "master content");
  402. git.add().addFilepattern(PATH).call();
  403. git.commit().setMessage("even content").call();
  404. recorder.assertNoEvent();
  405. git.checkout().setName(otherBranch).call();
  406. recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY);
  407. writeTrashFile(PATH, "otherBranch content");
  408. git.add().addFilepattern(PATH).call();
  409. git.commit().setMessage("even more content").call();
  410. recorder.assertNoEvent();
  411. writeTrashFile(path2, "content\nstashed change\nmore content\n");
  412. RevCommit stashed = git.stashCreate().call();
  413. assertNotNull(stashed);
  414. assertEquals("content\nmore content\n", read(file2));
  415. assertEquals("otherBranch content",
  416. read(committedFile));
  417. assertTrue(git.status().call().isClean());
  418. recorder.assertEvent(new String[] { path2 }, ChangeRecorder.EMPTY);
  419. git.checkout().setName("master").call();
  420. recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY);
  421. git.stashApply().call();
  422. assertEquals("content\nstashed change\nmore content\n", read(file2));
  423. assertEquals("master content",
  424. read(committedFile));
  425. recorder.assertEvent(new String[] { path2 }, ChangeRecorder.EMPTY);
  426. }
  427. @Test
  428. public void stashedApplyOnOtherBranchWithStagedChange() throws Exception {
  429. writeTrashFile(PATH, "content\nmore content\n");
  430. git.add().addFilepattern(PATH).call();
  431. git.commit().setMessage("more content").call();
  432. String path2 = "file2.txt";
  433. File file2 = writeTrashFile(path2, "content\nmore content\n");
  434. git.add().addFilepattern(PATH).call();
  435. git.add().addFilepattern(path2).call();
  436. git.commit().setMessage("even content").call();
  437. String otherBranch = "otherBranch";
  438. git.branchCreate().setName(otherBranch).call();
  439. writeTrashFile(PATH, "master content");
  440. git.add().addFilepattern(PATH).call();
  441. git.commit().setMessage("even content").call();
  442. recorder.assertNoEvent();
  443. git.checkout().setName(otherBranch).call();
  444. recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY);
  445. writeTrashFile(PATH, "otherBranch content");
  446. git.add().addFilepattern(PATH).call();
  447. git.commit().setMessage("even more content").call();
  448. recorder.assertNoEvent();
  449. writeTrashFile(path2,
  450. "content\nstashed change in index\nmore content\n");
  451. git.add().addFilepattern(path2).call();
  452. writeTrashFile(path2, "content\nstashed change\nmore content\n");
  453. RevCommit stashed = git.stashCreate().call();
  454. assertNotNull(stashed);
  455. assertEquals("content\nmore content\n", read(file2));
  456. assertEquals("otherBranch content", read(committedFile));
  457. assertTrue(git.status().call().isClean());
  458. recorder.assertEvent(new String[] { path2 }, ChangeRecorder.EMPTY);
  459. git.checkout().setName("master").call();
  460. recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY);
  461. git.stashApply().call();
  462. assertEquals("content\nstashed change\nmore content\n", read(file2));
  463. assertEquals(
  464. "[file.txt, mode:100644, content:master content]"
  465. + "[file2.txt, mode:100644, content:content\nstashed change in index\nmore content\n]",
  466. indexState(CONTENT));
  467. assertEquals("master content", read(committedFile));
  468. recorder.assertEvent(new String[] { path2 }, ChangeRecorder.EMPTY);
  469. }
  470. @Test
  471. public void workingDirectoryContentMerge() throws Exception {
  472. writeTrashFile(PATH, "content\nmore content\n");
  473. git.add().addFilepattern(PATH).call();
  474. git.commit().setMessage("more content").call();
  475. recorder.assertNoEvent();
  476. writeTrashFile(PATH, "content\nstashed change\nmore content\n");
  477. RevCommit stashed = git.stashCreate().call();
  478. assertNotNull(stashed);
  479. assertEquals("content\nmore content\n", read(committedFile));
  480. assertTrue(git.status().call().isClean());
  481. recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY);
  482. writeTrashFile(PATH, "content\nmore content\ncommitted change\n");
  483. git.add().addFilepattern(PATH).call();
  484. git.commit().setMessage("committed change").call();
  485. recorder.assertNoEvent();
  486. git.stashApply().call();
  487. assertEquals(
  488. "content\nstashed change\nmore content\ncommitted change\n",
  489. read(committedFile));
  490. recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY);
  491. }
  492. @Test
  493. public void indexContentConflict() throws Exception {
  494. writeTrashFile(PATH, "content2");
  495. RevCommit stashed = git.stashCreate().call();
  496. assertNotNull(stashed);
  497. assertEquals("content", read(committedFile));
  498. assertTrue(git.status().call().isClean());
  499. recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY);
  500. writeTrashFile(PATH, "content3");
  501. git.add().addFilepattern(PATH).call();
  502. writeTrashFile(PATH, "content2");
  503. try {
  504. git.stashApply().call();
  505. fail("Exception not thrown");
  506. } catch (StashApplyFailureException e) {
  507. // expected
  508. }
  509. recorder.assertNoEvent();
  510. assertEquals("content2", read(PATH));
  511. }
  512. @Test
  513. public void workingDirectoryEditPreCommit() throws Exception {
  514. writeTrashFile(PATH, "content2");
  515. RevCommit stashed = git.stashCreate().call();
  516. assertNotNull(stashed);
  517. assertEquals("content", read(committedFile));
  518. assertTrue(git.status().call().isClean());
  519. recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY);
  520. String path2 = "file2.txt";
  521. writeTrashFile(path2, "content3");
  522. git.add().addFilepattern(path2).call();
  523. assertNotNull(git.commit().setMessage("adding file").call());
  524. ObjectId unstashed = git.stashApply().call();
  525. assertEquals(stashed, unstashed);
  526. recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY);
  527. Status status = git.status().call();
  528. assertTrue(status.getAdded().isEmpty());
  529. assertTrue(status.getChanged().isEmpty());
  530. assertTrue(status.getConflicting().isEmpty());
  531. assertTrue(status.getMissing().isEmpty());
  532. assertTrue(status.getRemoved().isEmpty());
  533. assertTrue(status.getUntracked().isEmpty());
  534. assertEquals(1, status.getModified().size());
  535. assertTrue(status.getModified().contains(PATH));
  536. }
  537. @Test
  538. public void stashChangeInANewSubdirectory() throws Exception {
  539. String subdir = "subdir";
  540. String fname = "file2.txt";
  541. String path = subdir + "/" + fname;
  542. String otherBranch = "otherbranch";
  543. writeTrashFile(subdir, fname, "content2");
  544. git.add().addFilepattern(path).call();
  545. RevCommit stashed = git.stashCreate().call();
  546. assertNotNull(stashed);
  547. assertTrue(git.status().call().isClean());
  548. recorder.assertEvent(ChangeRecorder.EMPTY,
  549. new String[] { subdir, path });
  550. git.branchCreate().setName(otherBranch).call();
  551. git.checkout().setName(otherBranch).call();
  552. ObjectId unstashed = git.stashApply().call();
  553. assertEquals(stashed, unstashed);
  554. recorder.assertEvent(new String[] { path }, ChangeRecorder.EMPTY);
  555. Status status = git.status().call();
  556. assertTrue(status.getChanged().isEmpty());
  557. assertTrue(status.getConflicting().isEmpty());
  558. assertTrue(status.getMissing().isEmpty());
  559. assertTrue(status.getRemoved().isEmpty());
  560. assertTrue(status.getModified().isEmpty());
  561. assertTrue(status.getUntracked().isEmpty());
  562. assertEquals(1, status.getAdded().size());
  563. assertTrue(status.getAdded().contains(path));
  564. }
  565. @Test
  566. public void unstashNonStashCommit() throws Exception {
  567. try {
  568. git.stashApply().setStashRef(head.name()).call();
  569. fail("Exception not thrown");
  570. } catch (JGitInternalException e) {
  571. assertEquals(MessageFormat.format(
  572. JGitText.get().stashCommitIncorrectNumberOfParents,
  573. head.name(), "0"),
  574. e.getMessage());
  575. }
  576. }
  577. @Test
  578. public void unstashNoHead() throws Exception {
  579. Repository repo = createWorkRepository();
  580. try {
  581. Git.wrap(repo).stashApply().call();
  582. fail("Exception not thrown");
  583. } catch (NoHeadException e) {
  584. assertNotNull(e.getMessage());
  585. }
  586. }
  587. @Test
  588. public void noStashedCommits() throws Exception {
  589. try {
  590. git.stashApply().call();
  591. fail("Exception not thrown");
  592. } catch (InvalidRefNameException e) {
  593. assertNotNull(e.getMessage());
  594. }
  595. }
  596. @Test
  597. public void testApplyStashWithDeletedFile() throws Exception {
  598. File file = writeTrashFile("file", "content");
  599. git.add().addFilepattern("file").call();
  600. git.commit().setMessage("x").call();
  601. file.delete();
  602. git.rm().addFilepattern("file").call();
  603. recorder.assertNoEvent();
  604. git.stashCreate().call();
  605. recorder.assertEvent(new String[] { "file" }, ChangeRecorder.EMPTY);
  606. file.delete();
  607. git.stashApply().setStashRef("stash@{0}").call();
  608. assertFalse(file.exists());
  609. recorder.assertEvent(ChangeRecorder.EMPTY, new String[] { "file" });
  610. }
  611. @Test
  612. public void untrackedFileNotIncluded() throws Exception {
  613. String untrackedPath = "untracked.txt";
  614. File untrackedFile = writeTrashFile(untrackedPath, "content");
  615. // at least one modification needed
  616. writeTrashFile(PATH, "content2");
  617. git.add().addFilepattern(PATH).call();
  618. git.stashCreate().call();
  619. assertTrue(untrackedFile.exists());
  620. recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY);
  621. git.stashApply().setStashRef("stash@{0}").call();
  622. assertTrue(untrackedFile.exists());
  623. recorder.assertEvent(new String[] { PATH }, ChangeRecorder.EMPTY);
  624. Status status = git.status().call();
  625. assertEquals(1, status.getUntracked().size());
  626. assertTrue(status.getUntracked().contains(untrackedPath));
  627. assertEquals(1, status.getChanged().size());
  628. assertTrue(status.getChanged().contains(PATH));
  629. assertTrue(status.getAdded().isEmpty());
  630. assertTrue(status.getConflicting().isEmpty());
  631. assertTrue(status.getMissing().isEmpty());
  632. assertTrue(status.getRemoved().isEmpty());
  633. assertTrue(status.getModified().isEmpty());
  634. }
  635. @Test
  636. public void untrackedFileIncluded() throws Exception {
  637. String path = "a/b/untracked.txt";
  638. File untrackedFile = writeTrashFile(path, "content");
  639. RevCommit stashedCommit = git.stashCreate().setIncludeUntracked(true)
  640. .call();
  641. assertNotNull(stashedCommit);
  642. assertFalse(untrackedFile.exists());
  643. recorder.assertEvent(ChangeRecorder.EMPTY, new String[] { path });
  644. deleteTrashFile("a/b"); // checkout should create parent dirs
  645. git.stashApply().setStashRef("stash@{0}").call();
  646. assertTrue(untrackedFile.exists());
  647. assertEquals("content", read(path));
  648. recorder.assertEvent(new String[] { path }, ChangeRecorder.EMPTY);
  649. Status status = git.status().call();
  650. assertEquals(1, status.getUntracked().size());
  651. assertTrue(status.getAdded().isEmpty());
  652. assertTrue(status.getChanged().isEmpty());
  653. assertTrue(status.getConflicting().isEmpty());
  654. assertTrue(status.getMissing().isEmpty());
  655. assertTrue(status.getRemoved().isEmpty());
  656. assertTrue(status.getModified().isEmpty());
  657. assertTrue(status.getUntracked().contains(path));
  658. }
  659. @Test
  660. public void untrackedFileConflictsWithCommit() throws Exception {
  661. String path = "untracked.txt";
  662. writeTrashFile(path, "untracked");
  663. git.stashCreate().setIncludeUntracked(true).call();
  664. recorder.assertEvent(ChangeRecorder.EMPTY, new String[] { path });
  665. writeTrashFile(path, "committed");
  666. head = git.commit().setMessage("add file").call();
  667. git.add().addFilepattern(path).call();
  668. git.commit().setMessage("conflicting commit").call();
  669. try {
  670. git.stashApply().setStashRef("stash@{0}").call();
  671. fail("StashApplyFailureException should be thrown.");
  672. } catch (StashApplyFailureException e) {
  673. assertEquals(e.getMessage(), JGitText.get().stashApplyConflict);
  674. }
  675. assertEquals("committed", read(path));
  676. recorder.assertNoEvent();
  677. }
  678. @Test
  679. public void untrackedFileConflictsWithWorkingDirectory()
  680. throws Exception {
  681. String path = "untracked.txt";
  682. writeTrashFile(path, "untracked");
  683. git.stashCreate().setIncludeUntracked(true).call();
  684. recorder.assertEvent(ChangeRecorder.EMPTY, new String[] { path });
  685. writeTrashFile(path, "working-directory");
  686. try {
  687. git.stashApply().setStashRef("stash@{0}").call();
  688. fail("StashApplyFailureException should be thrown.");
  689. } catch (StashApplyFailureException e) {
  690. assertEquals(e.getMessage(), JGitText.get().stashApplyConflict);
  691. }
  692. assertEquals("working-directory", read(path));
  693. recorder.assertNoEvent();
  694. }
  695. @Test
  696. public void untrackedAndTrackedChanges() throws Exception {
  697. writeTrashFile(PATH, "changed");
  698. String path = "untracked.txt";
  699. writeTrashFile(path, "untracked");
  700. git.stashCreate().setIncludeUntracked(true).call();
  701. assertTrue(PATH + " should exist", check(PATH));
  702. assertEquals(PATH + " should have been reset", "content", read(PATH));
  703. assertFalse(path + " should not exist", check(path));
  704. recorder.assertEvent(new String[] { PATH }, new String[] { path });
  705. git.stashApply().setStashRef("stash@{0}").call();
  706. assertTrue(PATH + " should exist", check(PATH));
  707. assertEquals(PATH + " should have new content", "changed", read(PATH));
  708. assertTrue(path + " should exist", check(path));
  709. assertEquals(path + " should have new content", "untracked",
  710. read(path));
  711. recorder.assertEvent(new String[] { PATH, path }, ChangeRecorder.EMPTY);
  712. }
  713. }