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