View Javadoc
1   /*
2    * Copyright (C) 2012, IBM Corporation
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.pgm;
44  
45  import static org.junit.Assert.assertArrayEquals;
46  import static org.junit.Assert.assertEquals;
47  import static org.junit.Assert.assertFalse;
48  import static org.junit.Assert.assertNotNull;
49  import static org.junit.Assert.assertTrue;
50  import static org.junit.Assert.fail;
51  
52  import java.io.File;
53  import java.nio.file.Files;
54  import java.nio.file.Path;
55  import java.util.Arrays;
56  import java.util.List;
57  
58  import org.eclipse.jgit.api.Git;
59  import org.eclipse.jgit.api.errors.CheckoutConflictException;
60  import org.eclipse.jgit.diff.DiffEntry;
61  import org.eclipse.jgit.junit.LocalDiskRepositoryTestCase;
62  import org.eclipse.jgit.lib.CLIRepositoryTestCase;
63  import org.eclipse.jgit.lib.FileMode;
64  import org.eclipse.jgit.lib.Ref;
65  import org.eclipse.jgit.revwalk.RevCommit;
66  import org.eclipse.jgit.treewalk.FileTreeIterator;
67  import org.eclipse.jgit.treewalk.FileTreeIterator.FileEntry;
68  import org.eclipse.jgit.treewalk.TreeWalk;
69  import org.eclipse.jgit.util.FS;
70  import org.eclipse.jgit.util.FileUtils;
71  import org.junit.Assume;
72  import org.junit.Test;
73  
74  public class CheckoutTest extends CLIRepositoryTestCase {
75  	/**
76  	 * Executes specified git command (with arguments), captures exception and
77  	 * returns its message as an array of lines. Throws an AssertionError if no
78  	 * exception is thrown.
79  	 *
80  	 * @param command
81  	 *            a valid git command line, e.g. "git branch -h"
82  	 * @return message contained within the exception
83  	 */
84  	private String[] executeExpectingException(String command) {
85  		try {
86  			execute(command);
87  			throw new AssertionError("Expected Die");
88  		} catch (Exception e) {
89  			return e.getMessage().split(System.lineSeparator());
90  		}
91  	}
92  
93  	@Test
94  	public void testCheckoutSelf() throws Exception {
95  		try (Git git = new Git(db)) {
96  			git.commit().setMessage("initial commit").call();
97  
98  			assertStringArrayEquals("Already on 'master'",
99  					execute("git checkout master"));
100 		}
101 	}
102 
103 	@Test
104 	public void testCheckoutBranch() throws Exception {
105 		try (Git git = new Git(db)) {
106 			git.commit().setMessage("initial commit").call();
107 			git.branchCreate().setName("side").call();
108 
109 			assertStringArrayEquals("Switched to branch 'side'",
110 					execute("git checkout side"));
111 		}
112 	}
113 
114 	@Test
115 	public void testCheckoutNewBranch() throws Exception {
116 		try (Git git = new Git(db)) {
117 			git.commit().setMessage("initial commit").call();
118 
119 			assertStringArrayEquals("Switched to a new branch 'side'",
120 					execute("git checkout -b side"));
121 		}
122 	}
123 
124 	@Test
125 	public void testCheckoutNonExistingBranch() throws Exception {
126 		assertStringArrayEquals(
127 				"error: pathspec 'side' did not match any file(s) known to git.",
128 				executeExpectingException("git checkout side"));
129 	}
130 
131 	@Test
132 	public void testCheckoutNewBranchThatAlreadyExists() throws Exception {
133 		try (Git git = new Git(db)) {
134 			git.commit().setMessage("initial commit").call();
135 
136 			assertStringArrayEquals(
137 					"fatal: A branch named 'master' already exists.",
138 				executeUnchecked("git checkout -b master"));
139 		}
140 	}
141 
142 	@Test
143 	public void testCheckoutNewBranchOnBranchToBeBorn() throws Exception {
144 		assertStringArrayEquals("fatal: You are on a branch yet to be born",
145 				executeUnchecked("git checkout -b side"));
146 	}
147 
148 	@Test
149 	public void testCheckoutUnresolvedHead() throws Exception {
150 		assertStringArrayEquals(
151 				"error: pathspec 'HEAD' did not match any file(s) known to git.",
152 				executeExpectingException("git checkout HEAD"));
153 	}
154 
155 	@Test
156 	public void testCheckoutHead() throws Exception {
157 		try (Git git = new Git(db)) {
158 			git.commit().setMessage("initial commit").call();
159 
160 			assertStringArrayEquals("", execute("git checkout HEAD"));
161 		}
162 	}
163 
164 	@Test
165 	public void testCheckoutExistingBranchWithConflict() throws Exception {
166 		try (Git git = new Git(db)) {
167 			writeTrashFile("a", "Hello world a");
168 			git.add().addFilepattern(".").call();
169 			git.commit().setMessage("commit file a").call();
170 			git.branchCreate().setName("branch_1").call();
171 			git.rm().addFilepattern("a").call();
172 			FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
173 			writeTrashFile("a/b", "Hello world b");
174 			git.add().addFilepattern("a/b").call();
175 			git.commit().setMessage("commit folder a").call();
176 			git.rm().addFilepattern("a").call();
177 			writeTrashFile("a", "New Hello world a");
178 			git.add().addFilepattern(".").call();
179 
180 			String[] execute = executeExpectingException(
181 					"git checkout branch_1");
182 			assertEquals(
183 					"error: Your local changes to the following files would be overwritten by checkout:",
184 					execute[0]);
185 			assertEquals("\ta", execute[1]);
186 		}
187 	}
188 
189 	/**
190 	 * Steps:
191 	 * <ol>
192 	 * <li>Add file 'a' and 'b'
193 	 * <li>Commit
194 	 * <li>Create branch '1'
195 	 * <li>modify file 'a'
196 	 * <li>Commit
197 	 * <li>Delete file 'a' in the working tree
198 	 * <li>Checkout branch '1'
199 	 * </ol>
200 	 * <p>
201 	 * The working tree should contain 'a' with FileMode.REGULAR_FILE after the
202 	 * checkout.
203 	 *
204 	 * @throws Exception
205 	 */
206 	@Test
207 	public void testCheckoutWithMissingWorkingTreeFile() throws Exception {
208 		try (Git git = new Git(db)) {
209 			File fileA = writeTrashFile("a", "Hello world a");
210 			writeTrashFile("b", "Hello world b");
211 			git.add().addFilepattern(".").call();
212 			git.commit().setMessage("add files a & b").call();
213 			Ref branch_1 = git.branchCreate().setName("branch_1").call();
214 			writeTrashFile("a", "b");
215 			git.add().addFilepattern("a").call();
216 			git.commit().setMessage("modify file a").call();
217 
218 			FileEntry entry = new FileTreeIterator.FileEntry(new File(
219 					db.getWorkTree(), "a"), db.getFS());
220 			assertEquals(FileMode.REGULAR_FILE, entry.getMode());
221 
222 			FileUtils.delete(fileA);
223 
224 			git.checkout().setName(branch_1.getName()).call();
225 
226 			entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
227 					db.getFS());
228 			assertEquals(FileMode.REGULAR_FILE, entry.getMode());
229 			assertEquals("Hello world a", read(fileA));
230 		}
231 	}
232 
233 	@Test
234 	public void testCheckoutOrphan() throws Exception {
235 		try (Git git = new Git(db)) {
236 			git.commit().setMessage("initial commit").call();
237 
238 			assertStringArrayEquals("Switched to a new branch 'new_branch'",
239 					execute("git checkout --orphan new_branch"));
240 			assertEquals("refs/heads/new_branch",
241 					db.exactRef("HEAD").getTarget().getName());
242 			RevCommit commit = git.commit().setMessage("orphan commit").call();
243 			assertEquals(0, commit.getParentCount());
244 		}
245 	}
246 
247 	/**
248 	 * Steps:
249 	 * <ol>
250 	 * <li>Add file 'b'
251 	 * <li>Commit
252 	 * <li>Create branch '1'
253 	 * <li>Add folder 'a'
254 	 * <li>Commit
255 	 * <li>Replace folder 'a' by file 'a' in the working tree
256 	 * <li>Checkout branch '1'
257 	 * </ol>
258 	 * <p>
259 	 * The checkout has to delete folder but the workingtree contains a dirty
260 	 * file at this path. The checkout should fail like in native git.
261 	 *
262 	 * @throws Exception
263 	 */
264 	@Test
265 	public void fileModeTestMissingThenFolderWithFileInWorkingTree()
266 			throws Exception {
267 		try (Git git = new Git(db)) {
268 			writeTrashFile("b", "Hello world b");
269 			git.add().addFilepattern(".").call();
270 			git.commit().setMessage("add file b").call();
271 			Ref branch_1 = git.branchCreate().setName("branch_1").call();
272 			File folderA = new File(db.getWorkTree(), "a");
273 			FileUtils.mkdirs(folderA);
274 			writeTrashFile("a/c", "Hello world c");
275 			git.add().addFilepattern(".").call();
276 			git.commit().setMessage("add folder a").call();
277 
278 			FileEntry entry = new FileTreeIterator.FileEntry(new File(
279 					db.getWorkTree(), "a"), db.getFS());
280 			assertEquals(FileMode.TREE, entry.getMode());
281 
282 			FileUtils.delete(folderA, FileUtils.RECURSIVE);
283 			writeTrashFile("a", "b");
284 
285 			entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
286 					db.getFS());
287 			assertEquals(FileMode.REGULAR_FILE, entry.getMode());
288 
289 			try {
290 				git.checkout().setName(branch_1.getName()).call();
291 				fail("Don't get the expected conflict");
292 			} catch (CheckoutConflictException e) {
293 				assertEquals("[a]", e.getConflictingPaths().toString());
294 				entry = new FileTreeIterator.FileEntry(
295 						new File(db.getWorkTree(), "a"), db.getFS());
296 				assertEquals(FileMode.REGULAR_FILE, entry.getMode());
297 			}
298 		}
299 	}
300 
301 	/**
302 	 * Steps:
303 	 * <ol>
304 	 * <li>Add file 'a'
305 	 * <li>Commit
306 	 * <li>Create branch '1'
307 	 * <li>Replace file 'a' by folder 'a'
308 	 * <li>Commit
309 	 * <li>Delete folder 'a' in the working tree
310 	 * <li>Checkout branch '1'
311 	 * </ol>
312 	 * <p>
313 	 * The working tree should contain 'a' with FileMode.REGULAR_FILE after the
314 	 * checkout.
315 	 *
316 	 * @throws Exception
317 	 */
318 	@Test
319 	public void fileModeTestFolderWithMissingInWorkingTree() throws Exception {
320 		try (Git git = new Git(db)) {
321 			writeTrashFile("b", "Hello world b");
322 			writeTrashFile("a", "b");
323 			git.add().addFilepattern(".").call();
324 			git.commit().setMessage("add file b & file a").call();
325 			Ref branch_1 = git.branchCreate().setName("branch_1").call();
326 			git.rm().addFilepattern("a").call();
327 			File folderA = new File(db.getWorkTree(), "a");
328 			FileUtils.mkdirs(folderA);
329 			writeTrashFile("a/c", "Hello world c");
330 			git.add().addFilepattern(".").call();
331 			git.commit().setMessage("add folder a").call();
332 
333 			FileEntry entry = new FileTreeIterator.FileEntry(new File(
334 					db.getWorkTree(), "a"), db.getFS());
335 			assertEquals(FileMode.TREE, entry.getMode());
336 
337 			FileUtils.delete(folderA, FileUtils.RECURSIVE);
338 
339 			git.checkout().setName(branch_1.getName()).call();
340 
341 			entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
342 					db.getFS());
343 			assertEquals(FileMode.REGULAR_FILE, entry.getMode());
344 		}
345 	}
346 
347 	/**
348 	 * Steps:
349 	 * <ol>
350 	 * <li>Add file 'a'
351 	 * <li>Commit
352 	 * <li>Create branch '1'
353 	 * <li>Delete file 'a'
354 	 * <li>Commit
355 	 * <li>Add folder 'a' in the working tree
356 	 * <li>Checkout branch '1'
357 	 * </ol>
358 	 * <p>
359 	 * The checkout command should raise an error. The conflicting paths are 'a'
360 	 * and 'a/c'.
361 	 *
362 	 * @throws Exception
363 	 */
364 	@Test
365 	public void fileModeTestMissingWithFolderInWorkingTree() throws Exception {
366 		try (Git git = new Git(db)) {
367 			writeTrashFile("b", "Hello world b");
368 			writeTrashFile("a", "b");
369 			git.add().addFilepattern(".").call();
370 			git.commit().setMessage("add file b & file a").call();
371 			Ref branch_1 = git.branchCreate().setName("branch_1").call();
372 			git.rm().addFilepattern("a").call();
373 			git.commit().setMessage("delete file a").call();
374 
375 			FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
376 			writeTrashFile("a/c", "Hello world c");
377 
378 			FileEntry entry = new FileTreeIterator.FileEntry(new File(
379 					db.getWorkTree(), "a"), db.getFS());
380 			assertEquals(FileMode.TREE, entry.getMode());
381 
382 			CheckoutConflictException exception = null;
383 			try {
384 				git.checkout().setName(branch_1.getName()).call();
385 			} catch (CheckoutConflictException e) {
386 				exception = e;
387 			}
388 			assertNotNull(exception);
389 			assertEquals(2, exception.getConflictingPaths().size());
390 			assertEquals("a", exception.getConflictingPaths().get(0));
391 			assertEquals("a/c", exception.getConflictingPaths().get(1));
392 		}
393 	}
394 
395 	/**
396 	 * Steps:
397 	 * <ol>
398 	 * <li>Add folder 'a'
399 	 * <li>Commit
400 	 * <li>Create branch '1'
401 	 * <li>Delete folder 'a'
402 	 * <li>Commit
403 	 * <li>Add file 'a' in the working tree
404 	 * <li>Checkout branch '1'
405 	 * </ol>
406 	 * <p>
407 	 * The checkout command should raise an error. The conflicting path is 'a'.
408 	 *
409 	 * @throws Exception
410 	 */
411 	@Test
412 	public void fileModeTestFolderThenMissingWithFileInWorkingTree()
413 			throws Exception {
414 		try (Git git = new Git(db)) {
415 			FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
416 			writeTrashFile("a/c", "Hello world c");
417 			writeTrashFile("b", "Hello world b");
418 			git.add().addFilepattern(".").call();
419 			RevCommit commit1 = git.commit().setMessage("add folder a & file b")
420 					.call();
421 			Ref branch_1 = git.branchCreate().setName("branch_1").call();
422 			git.rm().addFilepattern("a").call();
423 			RevCommit commit2 = git.commit().setMessage("delete folder a").call();
424 
425 			TreeWalk tw = new TreeWalk(db);
426 			tw.addTree(commit1.getTree());
427 			tw.addTree(commit2.getTree());
428 			List<DiffEntry> scan = DiffEntry.scan(tw);
429 			assertEquals(1, scan.size());
430 			assertEquals(FileMode.MISSING, scan.get(0).getNewMode());
431 			assertEquals(FileMode.TREE, scan.get(0).getOldMode());
432 
433 			writeTrashFile("a", "b");
434 
435 			FileEntry entry = new FileTreeIterator.FileEntry(new File(
436 					db.getWorkTree(), "a"), db.getFS());
437 			assertEquals(FileMode.REGULAR_FILE, entry.getMode());
438 
439 			CheckoutConflictException exception = null;
440 			try {
441 				git.checkout().setName(branch_1.getName()).call();
442 			} catch (CheckoutConflictException e) {
443 				exception = e;
444 			}
445 			assertNotNull(exception);
446 			assertEquals(1, exception.getConflictingPaths().size());
447 			assertEquals("a", exception.getConflictingPaths().get(0));
448 		}
449 	}
450 
451 	/**
452 	 * Steps:
453 	 * <ol>
454 	 * <li>Add folder 'a'
455 	 * <li>Commit
456 	 * <li>Create branch '1'
457 	 * <li>Replace folder 'a'by file 'a'
458 	 * <li>Commit
459 	 * <li>Delete file 'a' in the working tree
460 	 * <li>Checkout branch '1'
461 	 * </ol>
462 	 * <p>
463 	 * The working tree should contain 'a' with FileMode.TREE after the
464 	 * checkout.
465 	 *
466 	 * @throws Exception
467 	 */
468 	@Test
469 	public void fileModeTestFolderThenFileWithMissingInWorkingTree()
470 			throws Exception {
471 		try (Git git = new Git(db)) {
472 			FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
473 			writeTrashFile("a/c", "Hello world c");
474 			writeTrashFile("b", "Hello world b");
475 			git.add().addFilepattern(".").call();
476 			git.commit().setMessage("add folder a & file b").call();
477 			Ref branch_1 = git.branchCreate().setName("branch_1").call();
478 			git.rm().addFilepattern("a").call();
479 			File fileA = new File(db.getWorkTree(), "a");
480 			writeTrashFile("a", "b");
481 			git.add().addFilepattern("a").call();
482 			git.commit().setMessage("add file a").call();
483 
484 			FileEntry entry = new FileTreeIterator.FileEntry(new File(
485 					db.getWorkTree(), "a"), db.getFS());
486 			assertEquals(FileMode.REGULAR_FILE, entry.getMode());
487 
488 			FileUtils.delete(fileA);
489 
490 			git.checkout().setName(branch_1.getName()).call();
491 
492 			entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
493 					db.getFS());
494 			assertEquals(FileMode.TREE, entry.getMode());
495 		}
496 	}
497 
498 	/**
499 	 * Steps:
500 	 * <ol>
501 	 * <li>Add file 'a'
502 	 * <li>Commit
503 	 * <li>Create branch '1'
504 	 * <li>Modify file 'a'
505 	 * <li>Commit
506 	 * <li>Delete file 'a' and replace by folder 'a' in the working tree and
507 	 * index
508 	 * <li>Checkout branch '1'
509 	 * </ol>
510 	 * <p>
511 	 * The checkout command should raise an error. The conflicting path is 'a'.
512 	 *
513 	 * @throws Exception
514 	 */
515 	@Test
516 	public void fileModeTestFileThenFileWithFolderInIndex() throws Exception {
517 		try (Git git = new Git(db)) {
518 			writeTrashFile("a", "Hello world a");
519 			writeTrashFile("b", "Hello world b");
520 			git.add().addFilepattern(".").call();
521 			git.commit().setMessage("add files a & b").call();
522 			Ref branch_1 = git.branchCreate().setName("branch_1").call();
523 			writeTrashFile("a", "b");
524 			git.add().addFilepattern("a").call();
525 			git.commit().setMessage("add file a").call();
526 
527 			FileEntry entry = new FileTreeIterator.FileEntry(new File(
528 					db.getWorkTree(), "a"), db.getFS());
529 			assertEquals(FileMode.REGULAR_FILE, entry.getMode());
530 
531 			git.rm().addFilepattern("a").call();
532 			FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
533 			writeTrashFile("a/c", "Hello world c");
534 			git.add().addFilepattern(".").call();
535 
536 			entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
537 					db.getFS());
538 			assertEquals(FileMode.TREE, entry.getMode());
539 
540 			CheckoutConflictException exception = null;
541 			try {
542 				git.checkout().setName(branch_1.getName()).call();
543 			} catch (CheckoutConflictException e) {
544 				exception = e;
545 			}
546 			assertNotNull(exception);
547 			assertEquals(1, exception.getConflictingPaths().size());
548 			assertEquals("a", exception.getConflictingPaths().get(0));
549 		}
550 	}
551 
552 	/**
553 	 * Steps:
554 	 * <ol>
555 	 * <li>Add file 'a'
556 	 * <li>Commit
557 	 * <li>Create branch '1'
558 	 * <li>Modify file 'a'
559 	 * <li>Commit
560 	 * <li>Delete file 'a' and replace by folder 'a' in the working tree and
561 	 * index
562 	 * <li>Checkout branch '1'
563 	 * </ol>
564 	 * <p>
565 	 * The checkout command should raise an error. The conflicting paths are 'a'
566 	 * and 'a/c'.
567 	 *
568 	 * @throws Exception
569 	 */
570 	@Test
571 	public void fileModeTestFileWithFolderInIndex() throws Exception {
572 		try (Git git = new Git(db)) {
573 			writeTrashFile("b", "Hello world b");
574 			writeTrashFile("a", "b");
575 			git.add().addFilepattern(".").call();
576 			git.commit().setMessage("add file b & file a").call();
577 			Ref branch_1 = git.branchCreate().setName("branch_1").call();
578 			git.rm().addFilepattern("a").call();
579 			writeTrashFile("a", "Hello world a");
580 			git.add().addFilepattern("a").call();
581 			git.commit().setMessage("add file a").call();
582 
583 			FileEntry entry = new FileTreeIterator.FileEntry(new File(
584 					db.getWorkTree(), "a"), db.getFS());
585 			assertEquals(FileMode.REGULAR_FILE, entry.getMode());
586 
587 			git.rm().addFilepattern("a").call();
588 			FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
589 			writeTrashFile("a/c", "Hello world c");
590 			git.add().addFilepattern(".").call();
591 
592 			entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
593 					db.getFS());
594 			assertEquals(FileMode.TREE, entry.getMode());
595 
596 			CheckoutConflictException exception = null;
597 			try {
598 				git.checkout().setName(branch_1.getName()).call();
599 			} catch (CheckoutConflictException e) {
600 				exception = e;
601 			}
602 			assertNotNull(exception);
603 			assertEquals(1, exception.getConflictingPaths().size());
604 			assertEquals("a", exception.getConflictingPaths().get(0));
605 
606 			// TODO: ideally we'd like to get two paths from this exception
607 			// assertEquals(2, exception.getConflictingPaths().size());
608 			// assertEquals("a", exception.getConflictingPaths().get(0));
609 			// assertEquals("a/c", exception.getConflictingPaths().get(1));
610 		}
611 	}
612 
613 	@Test
614 	public void testCheckoutPath() throws Exception {
615 		try (Git git = new Git(db)) {
616 			writeTrashFile("a", "Hello world a");
617 			git.add().addFilepattern(".").call();
618 			git.commit().setMessage("commit file a").call();
619 			git.branchCreate().setName("branch_1").call();
620 			git.checkout().setName("branch_1").call();
621 			File b = writeTrashFile("b", "Hello world b");
622 			git.add().addFilepattern("b").call();
623 			git.commit().setMessage("commit file b").call();
624 			File a = writeTrashFile("a", "New Hello world a");
625 			git.add().addFilepattern(".").call();
626 			git.commit().setMessage("modified a").call();
627 			assertArrayEquals(new String[] { "" },
628 					execute("git checkout HEAD~2 -- a"));
629 			assertEquals("Hello world a", read(a));
630 			assertArrayEquals(new String[] { "* branch_1", "  master", "" },
631 					execute("git branch"));
632 			assertEquals("Hello world b", read(b));
633 		}
634 	}
635 
636 	@Test
637 	public void testCheckoutAllPaths() throws Exception {
638 		try (Git git = new Git(db)) {
639 			writeTrashFile("a", "Hello world a");
640 			git.add().addFilepattern(".").call();
641 			git.commit().setMessage("commit file a").call();
642 			git.branchCreate().setName("branch_1").call();
643 			git.checkout().setName("branch_1").call();
644 			File b = writeTrashFile("b", "Hello world b");
645 			git.add().addFilepattern("b").call();
646 			git.commit().setMessage("commit file b").call();
647 			File a = writeTrashFile("a", "New Hello world a");
648 			git.add().addFilepattern(".").call();
649 			git.commit().setMessage("modified a").call();
650 			assertArrayEquals(new String[] { "" },
651 					execute("git checkout HEAD~2 -- ."));
652 			assertEquals("Hello world a", read(a));
653 			assertArrayEquals(new String[] { "* branch_1", "  master", "" },
654 					execute("git branch"));
655 			assertEquals("Hello world b", read(b));
656 		}
657 	}
658 
659 	@Test
660 	public void testCheckoutSingleFile() throws Exception {
661 		try (Git git = new Git(db)) {
662 			File a = writeTrashFile("a", "file a");
663 			git.add().addFilepattern(".").call();
664 			git.commit().setMessage("commit file a").call();
665 			writeTrashFile("a", "b");
666 			assertEquals("b", read(a));
667 			assertEquals("[]", Arrays.toString(execute("git checkout -- a")));
668 			assertEquals("file a", read(a));
669 		}
670 	}
671 
672 	@Test
673 	public void testCheckoutLink() throws Exception {
674 		Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
675 		try (Git git = new Git(db)) {
676 			Path path = writeLink("a", "link_a");
677 			assertTrue(Files.isSymbolicLink(path));
678 			git.add().addFilepattern(".").call();
679 			git.commit().setMessage("commit link a").call();
680 			deleteTrashFile("a");
681 			writeTrashFile("a", "Hello world a");
682 			assertFalse(Files.isSymbolicLink(path));
683 			assertEquals("[]", Arrays.toString(execute("git checkout -- a")));
684 			assertEquals("link_a", FileUtils.readSymLink(path.toFile()));
685 			assertTrue(Files.isSymbolicLink(path));
686 		}
687 	}
688 
689 	@Test
690 	public void testCheckoutForce_Bug530771() throws Exception {
691 		try (Git git = new Git(db)) {
692 			File f = writeTrashFile("a", "Hello world");
693 			git.add().addFilepattern("a").call();
694 			git.commit().setMessage("create a").call();
695 			writeTrashFile("a", "Goodbye world");
696 			assertEquals("[]",
697 					Arrays.toString(execute("git checkout -f HEAD")));
698 			assertEquals("Hello world", read(f));
699 			assertEquals("[a, mode:100644, content:Hello world]",
700 					indexState(db, LocalDiskRepositoryTestCase.CONTENT));
701 		}
702 	}
703 }