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 @Test
514 public void fileModeTestFileThenFileWithFolderInIndex() throws Exception {
515 try (Git git = new Git(db)) {
516 writeTrashFile("a", "Hello world a");
517 writeTrashFile("b", "Hello world b");
518 git.add().addFilepattern(".").call();
519 git.commit().setMessage("add files a & b").call();
520 Ref branch_1 = git.branchCreate().setName("branch_1").call();
521 writeTrashFile("a", "b");
522 git.add().addFilepattern("a").call();
523 git.commit().setMessage("add file a").call();
524
525 FileEntry entry = new FileTreeIterator.FileEntry(new File(
526 db.getWorkTree(), "a"), db.getFS());
527 assertEquals(FileMode.REGULAR_FILE, entry.getMode());
528
529 git.rm().addFilepattern("a").call();
530 FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
531 writeTrashFile("a/c", "Hello world c");
532 git.add().addFilepattern(".").call();
533
534 entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
535 db.getFS());
536 assertEquals(FileMode.TREE, entry.getMode());
537
538 CheckoutConflictException exception = null;
539 try {
540 git.checkout().setName(branch_1.getName()).call();
541 } catch (CheckoutConflictException e) {
542 exception = e;
543 }
544 assertNotNull(exception);
545 assertEquals(1, exception.getConflictingPaths().size());
546 assertEquals("a", exception.getConflictingPaths().get(0));
547 }
548 }
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567 @Test
568 public void fileModeTestFileWithFolderInIndex() throws Exception {
569 try (Git git = new Git(db)) {
570 writeTrashFile("b", "Hello world b");
571 writeTrashFile("a", "b");
572 git.add().addFilepattern(".").call();
573 git.commit().setMessage("add file b & file a").call();
574 Ref branch_1 = git.branchCreate().setName("branch_1").call();
575 git.rm().addFilepattern("a").call();
576 writeTrashFile("a", "Hello world a");
577 git.add().addFilepattern("a").call();
578 git.commit().setMessage("add file a").call();
579
580 FileEntry entry = new FileTreeIterator.FileEntry(new File(
581 db.getWorkTree(), "a"), db.getFS());
582 assertEquals(FileMode.REGULAR_FILE, entry.getMode());
583
584 git.rm().addFilepattern("a").call();
585 FileUtils.mkdirs(new File(db.getWorkTree(), "a"));
586 writeTrashFile("a/c", "Hello world c");
587 git.add().addFilepattern(".").call();
588
589 entry = new FileTreeIterator.FileEntry(new File(db.getWorkTree(), "a"),
590 db.getFS());
591 assertEquals(FileMode.TREE, entry.getMode());
592
593 CheckoutConflictException exception = null;
594 try {
595 git.checkout().setName(branch_1.getName()).call();
596 } catch (CheckoutConflictException e) {
597 exception = e;
598 }
599 assertNotNull(exception);
600 assertEquals(1, exception.getConflictingPaths().size());
601 assertEquals("a", exception.getConflictingPaths().get(0));
602
603
604
605
606
607 }
608 }
609
610 @Test
611 public void testCheckoutPath() throws Exception {
612 try (Git git = new Git(db)) {
613 writeTrashFile("a", "Hello world a");
614 git.add().addFilepattern(".").call();
615 git.commit().setMessage("commit file a").call();
616 git.branchCreate().setName("branch_1").call();
617 git.checkout().setName("branch_1").call();
618 File b = writeTrashFile("b", "Hello world b");
619 git.add().addFilepattern("b").call();
620 git.commit().setMessage("commit file b").call();
621 File a = writeTrashFile("a", "New Hello world a");
622 git.add().addFilepattern(".").call();
623 git.commit().setMessage("modified a").call();
624 assertArrayEquals(new String[] { "" },
625 execute("git checkout HEAD~2 -- a"));
626 assertEquals("Hello world a", read(a));
627 assertArrayEquals(new String[] { "* branch_1", " master", "" },
628 execute("git branch"));
629 assertEquals("Hello world b", read(b));
630 }
631 }
632
633 @Test
634 public void testCheckoutAllPaths() throws Exception {
635 try (Git git = new Git(db)) {
636 writeTrashFile("a", "Hello world a");
637 git.add().addFilepattern(".").call();
638 git.commit().setMessage("commit file a").call();
639 git.branchCreate().setName("branch_1").call();
640 git.checkout().setName("branch_1").call();
641 File b = writeTrashFile("b", "Hello world b");
642 git.add().addFilepattern("b").call();
643 git.commit().setMessage("commit file b").call();
644 File a = writeTrashFile("a", "New Hello world a");
645 git.add().addFilepattern(".").call();
646 git.commit().setMessage("modified a").call();
647 assertArrayEquals(new String[] { "" },
648 execute("git checkout HEAD~2 -- ."));
649 assertEquals("Hello world a", read(a));
650 assertArrayEquals(new String[] { "* branch_1", " master", "" },
651 execute("git branch"));
652 assertEquals("Hello world b", read(b));
653 }
654 }
655
656 @Test
657 public void testCheckoutSingleFile() throws Exception {
658 try (Git git = new Git(db)) {
659 File a = writeTrashFile("a", "file a");
660 git.add().addFilepattern(".").call();
661 git.commit().setMessage("commit file a").call();
662 writeTrashFile("a", "b");
663 assertEquals("b", read(a));
664 assertEquals("[]", Arrays.toString(execute("git checkout -- a")));
665 assertEquals("file a", read(a));
666 }
667 }
668
669 @Test
670 public void testCheckoutLink() throws Exception {
671 Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
672 try (Git git = new Git(db)) {
673 Path path = writeLink("a", "link_a");
674 assertTrue(Files.isSymbolicLink(path));
675 git.add().addFilepattern(".").call();
676 git.commit().setMessage("commit link a").call();
677 deleteTrashFile("a");
678 writeTrashFile("a", "Hello world a");
679 assertFalse(Files.isSymbolicLink(path));
680 assertEquals("[]", Arrays.toString(execute("git checkout -- a")));
681 assertEquals("link_a", FileUtils.readSymLink(path.toFile()));
682 assertTrue(Files.isSymbolicLink(path));
683 }
684 }
685 }