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