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