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 package org.eclipse.jgit.lib;
42
43 import static org.junit.Assert.assertArrayEquals;
44 import static org.junit.Assert.assertEquals;
45 import static org.junit.Assert.assertFalse;
46 import static org.junit.Assert.assertNotNull;
47 import static org.junit.Assert.assertTrue;
48 import static org.junit.Assert.fail;
49
50 import java.io.File;
51 import java.io.FileInputStream;
52 import java.io.IOException;
53 import java.util.Arrays;
54 import java.util.HashMap;
55 import java.util.List;
56 import java.util.Map;
57
58 import org.eclipse.jgit.api.CheckoutCommand;
59 import org.eclipse.jgit.api.CheckoutResult;
60 import org.eclipse.jgit.api.Git;
61 import org.eclipse.jgit.api.MergeResult.MergeStatus;
62 import org.eclipse.jgit.api.ResetCommand.ResetType;
63 import org.eclipse.jgit.api.Status;
64 import org.eclipse.jgit.api.errors.GitAPIException;
65 import org.eclipse.jgit.api.errors.NoFilepatternException;
66 import org.eclipse.jgit.dircache.DirCache;
67 import org.eclipse.jgit.dircache.DirCacheCheckout;
68 import org.eclipse.jgit.dircache.DirCacheCheckout.CheckoutMetadata;
69 import org.eclipse.jgit.dircache.DirCacheEditor;
70 import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
71 import org.eclipse.jgit.dircache.DirCacheEntry;
72 import org.eclipse.jgit.errors.CheckoutConflictException;
73 import org.eclipse.jgit.errors.CorruptObjectException;
74 import org.eclipse.jgit.errors.NoWorkTreeException;
75 import org.eclipse.jgit.junit.RepositoryTestCase;
76 import org.eclipse.jgit.junit.TestRepository;
77 import org.eclipse.jgit.junit.TestRepository.BranchBuilder;
78 import org.eclipse.jgit.revwalk.RevCommit;
79 import org.eclipse.jgit.treewalk.FileTreeIterator;
80 import org.eclipse.jgit.treewalk.TreeWalk;
81 import org.eclipse.jgit.util.FS;
82 import org.eclipse.jgit.util.FileUtils;
83 import org.junit.Assume;
84 import org.junit.Test;
85
86 public class DirCacheCheckoutTest extends RepositoryTestCase {
87 private DirCacheCheckout dco;
88 protected ObjectId theHead;
89 protected ObjectId theMerge;
90 private DirCache dirCache;
91
92 private void prescanTwoTrees(ObjectId head, ObjectId merge)
93 throws IllegalStateException, IOException {
94 DirCache dc = db.lockDirCache();
95 try {
96 dco = new DirCacheCheckout(db, head, dc, merge);
97 dco.preScanTwoTrees();
98 } finally {
99 dc.unlock();
100 }
101 }
102
103 private void checkout() throws IOException {
104 DirCache dc = db.lockDirCache();
105 try {
106 dco = new DirCacheCheckout(db, theHead, dc, theMerge);
107 dco.checkout();
108 } finally {
109 dc.unlock();
110 }
111 }
112
113 private List<String> getRemoved() {
114 return dco.getRemoved();
115 }
116
117 private Map<String, CheckoutMetadata> getUpdated() {
118 return dco.getUpdated();
119 }
120
121 private List<String> getConflicts() {
122 return dco.getConflicts();
123 }
124
125 private static HashMap<String, String> mk(String a) {
126 return mkmap(a, a);
127 }
128
129 private static HashMap<String, String> mkmap(String... args) {
130 if ((args.length % 2) > 0)
131 throw new IllegalArgumentException("needs to be pairs");
132
133 HashMap<String, String> map = new HashMap<>();
134 for (int i = 0; i < args.length; i += 2) {
135 map.put(args[i], args[i + 1]);
136 }
137
138 return map;
139 }
140
141 @Test
142 public void testResetHard() throws IOException, NoFilepatternException,
143 GitAPIException {
144 try (Git git = new Git(db)) {
145 writeTrashFile("f", "f()");
146 writeTrashFile("D/g", "g()");
147 git.add().addFilepattern(".").call();
148 git.commit().setMessage("inital").call();
149 assertIndex(mkmap("f", "f()", "D/g", "g()"));
150
151 git.branchCreate().setName("topic").call();
152
153 writeTrashFile("f", "f()\nmaster");
154 writeTrashFile("D/g", "g()\ng2()");
155 writeTrashFile("E/h", "h()");
156 git.add().addFilepattern(".").call();
157 RevCommit master = git.commit().setMessage("master-1").call();
158 assertIndex(mkmap("f", "f()\nmaster", "D/g", "g()\ng2()", "E/h", "h()"));
159
160 checkoutBranch("refs/heads/topic");
161 assertIndex(mkmap("f", "f()", "D/g", "g()"));
162
163 writeTrashFile("f", "f()\nside");
164 assertTrue(new File(db.getWorkTree(), "D/g").delete());
165 writeTrashFile("G/i", "i()");
166 git.add().addFilepattern(".").call();
167 git.add().addFilepattern(".").setUpdate(true).call();
168 RevCommit topic = git.commit().setMessage("topic-1").call();
169 assertIndex(mkmap("f", "f()\nside", "G/i", "i()"));
170
171 writeTrashFile("untracked", "untracked");
172
173 resetHard(master);
174 assertIndex(mkmap("f", "f()\nmaster", "D/g", "g()\ng2()", "E/h", "h()"));
175 resetHard(topic);
176 assertIndex(mkmap("f", "f()\nside", "G/i", "i()"));
177 assertWorkDir(mkmap("f", "f()\nside", "G/i", "i()", "untracked",
178 "untracked"));
179
180 assertEquals(MergeStatus.CONFLICTING, git.merge().include(master)
181 .call().getMergeStatus());
182 assertEquals(
183 "[D/g, mode:100644, stage:1][D/g, mode:100644, stage:3][E/h, mode:100644][G/i, mode:100644][f, mode:100644, stage:1][f, mode:100644, stage:2][f, mode:100644, stage:3]",
184 indexState(0));
185
186 resetHard(master);
187 assertIndex(mkmap("f", "f()\nmaster", "D/g", "g()\ng2()", "E/h", "h()"));
188 assertWorkDir(mkmap("f", "f()\nmaster", "D/g", "g()\ng2()", "E/h",
189 "h()", "untracked", "untracked"));
190 }
191 }
192
193
194
195
196
197
198
199
200
201
202 @Test
203 public void testResetHardFromIndexEntryWithoutFileToTreeWithoutFile()
204 throws Exception {
205 try (Git git = new Git(db)) {
206 writeTrashFile("x", "x");
207 git.add().addFilepattern("x").call();
208 RevCommit id1 = git.commit().setMessage("c1").call();
209
210 writeTrashFile("f/g", "f/g");
211 git.rm().addFilepattern("x").call();
212 git.add().addFilepattern("f/g").call();
213 git.commit().setMessage("c2").call();
214 deleteTrashFile("f/g");
215 deleteTrashFile("f");
216
217
218 git.reset().setMode(ResetType.HARD).setRef(id1.getName()).call();
219 assertIndex(mkmap("x", "x"));
220 }
221 }
222
223
224
225
226
227
228 @Test
229 public void testInitialCheckout() throws Exception {
230 try (Git git = new Git(db)) {
231 TestRepository<Repository> db_t = new TestRepository<>(db);
232 BranchBuilder master = db_t.branch("master");
233 master.commit().add("f", "1").message("m0").create();
234 assertFalse(new File(db.getWorkTree(), "f").exists());
235 git.checkout().setName("master").call();
236 assertTrue(new File(db.getWorkTree(), "f").exists());
237 }
238 }
239
240 private DirCacheCheckout resetHard(RevCommit commit)
241 throws NoWorkTreeException,
242 CorruptObjectException, IOException {
243 DirCacheCheckout dc;
244 dc = new DirCacheCheckout(db, null, db.lockDirCache(),
245 commit.getTree());
246 dc.setFailOnConflict(true);
247 assertTrue(dc.checkout());
248 return dc;
249 }
250
251 private void assertIndex(HashMap<String, String> i)
252 throws CorruptObjectException, IOException {
253 String expectedValue;
254 String path;
255 DirCache read = DirCache.read(db.getIndexFile(), db.getFS());
256
257 assertEquals("Index has not the right size.", i.size(),
258 read.getEntryCount());
259 for (int j = 0; j < read.getEntryCount(); j++) {
260 path = read.getEntry(j).getPathString();
261 expectedValue = i.get(path);
262 assertNotNull("found unexpected entry for path " + path
263 + " in index", expectedValue);
264 assertTrue("unexpected content for path " + path
265 + " in index. Expected: <" + expectedValue + ">",
266 Arrays.equals(db.open(read.getEntry(j).getObjectId())
267 .getCachedBytes(), i.get(path).getBytes()));
268 }
269 }
270
271 @Test
272 public void testRules1thru3_NoIndexEntry() throws IOException {
273 ObjectId head = buildTree(mk("foo"));
274 ObjectId merge = db.newObjectInserter().insert(Constants.OBJ_TREE,
275 new byte[0]);
276
277 prescanTwoTrees(head, merge);
278
279 assertTrue(getRemoved().contains("foo"));
280
281 prescanTwoTrees(merge, head);
282
283 assertTrue(getUpdated().containsKey("foo"));
284
285 merge = buildTree(mkmap("foo", "a"));
286
287 prescanTwoTrees(head, merge);
288
289 assertConflict("foo");
290 }
291
292 void setupCase(HashMap<String, String> headEntries, HashMap<String, String> mergeEntries, HashMap<String, String> indexEntries) throws IOException {
293 theHead = buildTree(headEntries);
294 theMerge = buildTree(mergeEntries);
295 buildIndex(indexEntries);
296 }
297
298 private void buildIndex(HashMap<String, String> indexEntries) throws IOException {
299 dirCache = new DirCache(db.getIndexFile(), db.getFS());
300 if (indexEntries != null) {
301 assertTrue(dirCache.lock());
302 DirCacheEditor editor = dirCache.editor();
303 for (java.util.Map.Entry<String,String> e : indexEntries.entrySet()) {
304 writeTrashFile(e.getKey(), e.getValue());
305 ObjectInserter inserter = db.newObjectInserter();
306 final ObjectId id = inserter.insert(Constants.OBJ_BLOB,
307 Constants.encode(e.getValue()));
308 editor.add(new DirCacheEditor.DeletePath(e.getKey()));
309 editor.add(new DirCacheEditor.PathEdit(e.getKey()) {
310 @Override
311 public void apply(DirCacheEntry ent) {
312 ent.setFileMode(FileMode.REGULAR_FILE);
313 ent.setObjectId(id);
314 ent.setUpdateNeeded(false);
315 }
316 });
317 }
318 assertTrue(editor.commit());
319 }
320
321 }
322
323 static final class AddEdit extends PathEdit {
324
325 private final ObjectId data;
326
327 private final long length;
328
329 public AddEdit(String entryPath, ObjectId data, long length) {
330 super(entryPath);
331 this.data = data;
332 this.length = length;
333 }
334
335 @Override
336 public void apply(DirCacheEntry ent) {
337 ent.setFileMode(FileMode.REGULAR_FILE);
338 ent.setLength(length);
339 ent.setObjectId(data);
340 }
341
342 }
343
344 private ObjectId buildTree(HashMap<String, String> headEntries)
345 throws IOException {
346 DirCache lockDirCache = DirCache.newInCore();
347
348 DirCacheEditor editor = lockDirCache.editor();
349 if (headEntries != null) {
350 for (java.util.Map.Entry<String, String> e : headEntries.entrySet()) {
351 AddEdit addEdit = new AddEdit(e.getKey(),
352 genSha1(e.getValue()), e.getValue().length());
353 editor.add(addEdit);
354 }
355 }
356 editor.finish();
357 return lockDirCache.writeTree(db.newObjectInserter());
358 }
359
360 ObjectId genSha1(String data) {
361 try (ObjectInserter w = db.newObjectInserter()) {
362 ObjectId id = w.insert(Constants.OBJ_BLOB, data.getBytes());
363 w.flush();
364 return id;
365 } catch (IOException e) {
366 fail(e.toString());
367 }
368 return null;
369 }
370
371 protected void go() throws IllegalStateException, IOException {
372 prescanTwoTrees(theHead, theMerge);
373 }
374
375 @Test
376 public void testRules4thru13_IndexEntryNotInHead() throws IOException {
377
378 HashMap<String, String> idxMap;
379
380 idxMap = new HashMap<>();
381 idxMap.put("foo", "foo");
382 setupCase(null, null, idxMap);
383 go();
384
385 assertTrue(getUpdated().isEmpty());
386 assertTrue(getRemoved().isEmpty());
387 assertTrue(getConflicts().isEmpty());
388
389
390 idxMap = new HashMap<>();
391 idxMap.put("foo", "foo");
392 setupCase(null, idxMap, idxMap);
393 go();
394
395 assertAllEmpty();
396
397
398 HashMap<String, String> mergeMap;
399 mergeMap = new HashMap<>();
400
401 mergeMap.put("foo", "merge");
402 setupCase(null, mergeMap, idxMap);
403 go();
404
405 assertTrue(getUpdated().isEmpty());
406 assertTrue(getRemoved().isEmpty());
407 assertTrue(getConflicts().contains("foo"));
408
409
410
411 HashMap<String, String> headMap = new HashMap<>();
412 headMap.put("foo", "foo");
413 setupCase(headMap, null, idxMap);
414 go();
415
416 assertTrue(getRemoved().contains("foo"));
417 assertTrue(getUpdated().isEmpty());
418 assertTrue(getConflicts().isEmpty());
419
420
421 setupCase(headMap, null, idxMap);
422 assertTrue(new File(trash, "foo").delete());
423 writeTrashFile("foo", "bar");
424 db.readDirCache().getEntry(0).setUpdateNeeded(true);
425 go();
426
427 assertTrue(getRemoved().isEmpty());
428 assertTrue(getUpdated().isEmpty());
429 assertTrue(getConflicts().contains("foo"));
430
431
432 headMap.put("foo", "head");
433 setupCase(headMap, null, idxMap);
434 go();
435
436 assertTrue(getRemoved().isEmpty());
437 assertTrue(getUpdated().isEmpty());
438 assertTrue(getConflicts().contains("foo"));
439
440
441 setupCase(headMap, headMap, idxMap);
442 go();
443
444 assertAllEmpty();
445
446
447 setupCase(headMap, mergeMap, idxMap); go();
448 assertTrue(getConflicts().contains("foo"));
449
450
451 setupCase(headMap, idxMap, idxMap); go();
452 assertAllEmpty();
453
454
455 setupCase(idxMap, mergeMap, idxMap); go();
456 assertTrue(getUpdated().containsKey("foo"));
457
458
459 setupCase(idxMap, mergeMap, idxMap);
460 assertTrue(new File(trash, "foo").delete());
461 writeTrashFile("foo", "bar");
462 db.readDirCache().getEntry(0).setUpdateNeeded(true);
463 go();
464 assertTrue(getConflicts().contains("foo"));
465 }
466
467 private void assertAllEmpty() {
468 assertTrue(getRemoved().isEmpty());
469 assertTrue(getUpdated().isEmpty());
470 assertTrue(getConflicts().isEmpty());
471 }
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505 @Test
506 public void testDirectoryFileSimple() throws IOException {
507 ObjectId treeDF = buildTree(mkmap("DF", "DF"));
508 ObjectId treeDFDF = buildTree(mkmap("DF/DF", "DF/DF"));
509 buildIndex(mkmap("DF", "DF"));
510
511 prescanTwoTrees(treeDF, treeDFDF);
512
513 assertTrue(getRemoved().contains("DF"));
514 assertTrue(getUpdated().containsKey("DF/DF"));
515
516 recursiveDelete(new File(trash, "DF"));
517 buildIndex(mkmap("DF/DF", "DF/DF"));
518
519 prescanTwoTrees(treeDFDF, treeDF);
520 assertTrue(getRemoved().contains("DF/DF"));
521 assertTrue(getUpdated().containsKey("DF"));
522 }
523
524 @Test
525 public void testDirectoryFileConflicts_1() throws Exception {
526
527 doit(mk("DF/DF"), mk("DF"), mk("DF/DF"));
528 assertNoConflicts();
529 assertUpdated("DF");
530 assertRemoved("DF/DF");
531 }
532
533 @Test
534 public void testDirectoryFileConflicts_2() throws Exception {
535
536 setupCase(mk("DF/DF"), mk("DF"), mk("DF/DF"));
537 writeTrashFile("DF/DF", "different");
538 go();
539 assertConflict("DF/DF");
540
541 }
542
543 @Test
544 public void testDirectoryFileConflicts_3() throws Exception {
545
546 doit(mk("DF/DF"), mk("DF/DF"), mk("DF"));
547 assertNoConflicts();
548 }
549
550 @Test
551 public void testDirectoryFileConflicts_4() throws Exception {
552
553 doit(mk("DF/DF"), mkmap("DF/DF", "foo"), mk("DF"));
554 assertConflict("DF/DF");
555
556 }
557
558 @Test
559 public void testDirectoryFileConflicts_5() throws Exception {
560
561 doit(mk("DF/DF"), mk("DF"), mk("DF"));
562 assertRemoved("DF/DF");
563 assertEquals(0, dco.getConflicts().size());
564 assertEquals(0, dco.getUpdated().size());
565 }
566
567 @Test
568 public void testDirectoryFileConflicts_5b() throws Exception {
569
570 doit(mk("DF/DF"), mkmap("DF", "different"), mk("DF"));
571 assertRemoved("DF/DF");
572 assertConflict("DF");
573 assertEquals(0, dco.getUpdated().size());
574 }
575
576 @Test
577 public void testDirectoryFileConflicts_6() throws Exception {
578
579 setupCase(mk("DF/DF"), mk("DF"), mk("DF"));
580 writeTrashFile("DF", "different");
581 go();
582 assertRemoved("DF/DF");
583 assertEquals(0, dco.getConflicts().size());
584 assertEquals(0, dco.getUpdated().size());
585 }
586
587 @Test
588 public void testDirectoryFileConflicts_6b() throws Exception {
589
590 setupCase(mk("DF/DF"), mk("DF"), mkmap("DF", "different"));
591 writeTrashFile("DF", "again different");
592 go();
593 assertRemoved("DF/DF");
594 assertConflict("DF");
595 assertEquals(0, dco.getUpdated().size());
596 }
597
598 @Test
599 public void testDirectoryFileConflicts_7() throws Exception {
600
601 doit(mk("DF"), mk("DF"), mk("DF/DF"));
602 assertUpdated("DF");
603 assertRemoved("DF/DF");
604
605 cleanUpDF();
606 setupCase(mk("DF/DF"), mk("DF/DF"), mk("DF/DF/DF/DF/DF"));
607 go();
608 assertRemoved("DF/DF/DF/DF/DF");
609 assertUpdated("DF/DF");
610
611 cleanUpDF();
612 setupCase(mk("DF/DF"), mk("DF/DF"), mk("DF/DF/DF/DF/DF"));
613 writeTrashFile("DF/DF/DF/DF/DF", "diff");
614 go();
615 assertConflict("DF/DF/DF/DF/DF");
616
617
618
619
620
621
622
623
624
625 }
626
627 @Test
628 public void testDirectoryFileConflicts_8() throws Exception {
629
630 setupCase(mk("DF"), mk("DF"), mk("DF/DF"));
631 recursiveDelete(new File(db.getWorkTree(), "DF"));
632 writeTrashFile("DF", "xy");
633 go();
634 assertConflict("DF/DF");
635 }
636
637 @Test
638 public void testDirectoryFileConflicts_9() throws Exception {
639
640 doit(mkmap("DF", "QP"), mkmap("DF", "QP"), mkmap("DF/DF", "DF/DF"));
641 assertRemoved("DF/DF");
642 assertUpdated("DF");
643 }
644
645 @Test
646 public void testDirectoryFileConflicts_10() throws Exception {
647
648 cleanUpDF();
649 doit(mk("DF"), mk("DF/DF"), mk("DF/DF"));
650 assertNoConflicts();
651 }
652
653 @Test
654 public void testDirectoryFileConflicts_11() throws Exception {
655
656 doit(mk("DF"), mk("DF/DF"), mkmap("DF/DF", "asdf"));
657 assertConflict("DF/DF");
658 }
659
660 @Test
661 public void testDirectoryFileConflicts_12() throws Exception {
662
663 cleanUpDF();
664 doit(mk("DF"), mk("DF/DF"), mk("DF"));
665 assertRemoved("DF");
666 assertUpdated("DF/DF");
667 }
668
669 @Test
670 public void testDirectoryFileConflicts_13() throws Exception {
671
672 cleanUpDF();
673 setupCase(mk("DF"), mk("DF/DF"), mk("DF"));
674 writeTrashFile("DF", "asdfsdf");
675 go();
676 assertConflict("DF");
677 assertUpdated("DF/DF");
678 }
679
680 @Test
681 public void testDirectoryFileConflicts_14() throws Exception {
682
683 cleanUpDF();
684 doit(mk("DF"), mk("DF/DF"), mkmap("DF", "Foo"));
685 assertConflict("DF");
686 assertUpdated("DF/DF");
687 }
688
689 @Test
690 public void testDirectoryFileConflicts_15() throws Exception {
691
692 doit(mkmap(), mk("DF/DF"), mk("DF"));
693
694
695
696
697
698 assertUpdated("DF/DF");
699 }
700
701 @Test
702 public void testDirectoryFileConflicts_15b() throws Exception {
703
704 doit(mkmap(), mk("DF/DF/DF/DF"), mk("DF"));
705
706
707
708
709
710
711 assertUpdated("DF/DF/DF/DF");
712 }
713
714 @Test
715 public void testDirectoryFileConflicts_16() throws Exception {
716
717 cleanUpDF();
718 doit(mkmap(), mk("DF"), mk("DF/DF/DF"));
719 assertRemoved("DF/DF/DF");
720 assertUpdated("DF");
721 }
722
723 @Test
724 public void testDirectoryFileConflicts_17() throws Exception {
725
726 cleanUpDF();
727 setupCase(mkmap(), mk("DF"), mk("DF/DF/DF"));
728 writeTrashFile("DF/DF/DF", "asdf");
729 go();
730 assertConflict("DF/DF/DF");
731
732
733
734
735
736
737 }
738
739 @Test
740 public void testDirectoryFileConflicts_18() throws Exception {
741
742 cleanUpDF();
743 doit(mk("DF/DF"), mk("DF/DF/DF/DF"), null);
744 assertRemoved("DF/DF");
745 assertUpdated("DF/DF/DF/DF");
746 }
747
748 @Test
749 public void testDirectoryFileConflicts_19() throws Exception {
750
751 cleanUpDF();
752 doit(mk("DF/DF/DF/DF"), mk("DF/DF/DF"), null);
753 assertRemoved("DF/DF/DF/DF");
754 assertUpdated("DF/DF/DF");
755 }
756
757 protected void cleanUpDF() throws Exception {
758 tearDown();
759 setUp();
760 recursiveDelete(new File(trash, "DF"));
761 }
762
763 protected void assertConflict(String s) {
764 assertTrue(getConflicts().contains(s));
765 }
766
767 protected void assertUpdated(String s) {
768 assertTrue(getUpdated().containsKey(s));
769 }
770
771 protected void assertRemoved(String s) {
772 assertTrue(getRemoved().contains(s));
773 }
774
775 protected void assertNoConflicts() {
776 assertTrue(getConflicts().isEmpty());
777 }
778
779 protected void doit(HashMap<String, String> h, HashMap<String, String> m, HashMap<String, String> i)
780 throws IOException {
781 setupCase(h, m, i);
782 go();
783 }
784
785 @Test
786 public void testUntrackedConflicts() throws IOException {
787 setupCase(null, mk("foo"), null);
788 writeTrashFile("foo", "foo");
789 go();
790
791
792 recursiveDelete(new File(trash, "foo"));
793 setupCase(mk("other"), mkmap("other", "other", "foo", "foo"),
794 mk("other"));
795 writeTrashFile("foo", "bar");
796 try {
797 checkout();
798 fail("didn't get the expected exception");
799 } catch (CheckoutConflictException e) {
800 assertConflict("foo");
801 assertEquals("foo", e.getConflictingFiles()[0]);
802 assertWorkDir(mkmap("foo", "bar", "other", "other"));
803 assertIndex(mk("other"));
804 }
805
806
807 recursiveDelete(new File(trash, "other"));
808 recursiveDelete(new File(trash, "foo"));
809 setupCase(null, mk("foo"), null);
810 writeTrashFile("foo", "bar");
811 try {
812 checkout();
813 fail("didn't get the expected exception");
814 } catch (CheckoutConflictException e) {
815 assertConflict("foo");
816 assertWorkDir(mkmap("foo", "bar"));
817 assertIndex(mkmap("other", "other"));
818 }
819
820
821
822
823
824
825
826
827
828
829 recursiveDelete(new File(trash, "foo"));
830 recursiveDelete(new File(trash, "other"));
831 setupCase(null, mk("foo"), null);
832 writeTrashFile("foo/bar/baz", "");
833 writeTrashFile("foo/blahblah", "");
834 go();
835
836 assertConflict("foo");
837 assertConflict("foo/bar/baz");
838 assertConflict("foo/blahblah");
839
840 recursiveDelete(new File(trash, "foo"));
841
842 setupCase(mkmap("foo/bar", "", "foo/baz", ""),
843 mk("foo"), mkmap("foo/bar", "", "foo/baz", ""));
844 assertTrue(new File(trash, "foo/bar").exists());
845 go();
846
847 assertNoConflicts();
848 }
849
850 @Test
851 public void testCloseNameConflictsX0() throws IOException {
852 setupCase(mkmap("a/a", "a/a-c"), mkmap("a/a","a/a", "b.b/b.b","b.b/b.bs"), mkmap("a/a", "a/a-c") );
853 checkout();
854 assertIndex(mkmap("a/a", "a/a", "b.b/b.b", "b.b/b.bs"));
855 assertWorkDir(mkmap("a/a", "a/a", "b.b/b.b", "b.b/b.bs"));
856 go();
857 assertIndex(mkmap("a/a", "a/a", "b.b/b.b", "b.b/b.bs"));
858 assertWorkDir(mkmap("a/a", "a/a", "b.b/b.b", "b.b/b.bs"));
859 assertNoConflicts();
860 }
861
862 @Test
863 public void testCloseNameConflicts1() throws IOException {
864 setupCase(mkmap("a/a", "a/a-c"), mkmap("a/a","a/a", "a.a/a.a","a.a/a.a"), mkmap("a/a", "a/a-c") );
865 checkout();
866 assertIndex(mkmap("a/a", "a/a", "a.a/a.a", "a.a/a.a"));
867 assertWorkDir(mkmap("a/a", "a/a", "a.a/a.a", "a.a/a.a"));
868 go();
869 assertIndex(mkmap("a/a", "a/a", "a.a/a.a", "a.a/a.a"));
870 assertWorkDir(mkmap("a/a", "a/a", "a.a/a.a", "a.a/a.a"));
871 assertNoConflicts();
872 }
873
874 @Test
875 public void testCheckoutHierarchy() throws IOException {
876 setupCase(
877 mkmap("a", "a", "b/c", "b/c", "d", "d", "e/f", "e/f", "e/g",
878 "e/g"),
879 mkmap("a", "a2", "b/c", "b/c", "d", "d", "e/f", "e/f", "e/g",
880 "e/g2"),
881 mkmap("a", "a", "b/c", "b/c", "d", "d", "e/f", "e/f", "e/g",
882 "e/g3"));
883 try {
884 checkout();
885 } catch (CheckoutConflictException e) {
886 assertWorkDir(mkmap("a", "a", "b/c", "b/c", "d", "d", "e/f",
887 "e/f", "e/g", "e/g3"));
888 assertConflict("e/g");
889 assertEquals("e/g", e.getConflictingFiles()[0]);
890 }
891 }
892
893 @Test
894 public void testCheckoutOutChanges() throws IOException {
895 setupCase(mk("foo"), mk("foo/bar"), mk("foo"));
896 checkout();
897 assertIndex(mk("foo/bar"));
898 assertWorkDir(mk("foo/bar"));
899
900 assertFalse(new File(trash, "foo").isFile());
901 assertTrue(new File(trash, "foo/bar").isFile());
902 recursiveDelete(new File(trash, "foo"));
903
904 assertWorkDir(mkmap());
905
906 setupCase(mk("foo/bar"), mk("foo"), mk("foo/bar"));
907 checkout();
908
909 assertIndex(mk("foo"));
910 assertWorkDir(mk("foo"));
911
912 assertFalse(new File(trash, "foo/bar").isFile());
913 assertTrue(new File(trash, "foo").isFile());
914
915 setupCase(mk("foo"), mkmap("foo", "qux"), mkmap("foo", "bar"));
916
917 assertIndex(mkmap("foo", "bar"));
918 assertWorkDir(mkmap("foo", "bar"));
919
920 try {
921 checkout();
922 fail("did not throw exception");
923 } catch (CheckoutConflictException e) {
924 assertIndex(mkmap("foo", "bar"));
925 assertWorkDir(mkmap("foo", "bar"));
926 }
927 }
928
929 @Test
930 public void testCheckoutChangeLinkToEmptyDir() throws Exception {
931 Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
932 String fname = "was_file";
933 Git git = Git.wrap(db);
934
935
936 writeTrashFile(fname, "a");
937 git.add().addFilepattern(fname).call();
938
939
940 String linkName = "link";
941 File link = writeLink(linkName, fname).toFile();
942 git.add().addFilepattern(linkName).call();
943 git.commit().setMessage("Added file and link").call();
944
945 assertWorkDir(mkmap(linkName, "a", fname, "a"));
946
947
948 FileUtils.delete(link);
949 FileUtils.mkdir(link);
950 assertTrue("Link must be a directory now", link.isDirectory());
951
952
953 writeTrashFile(fname, "b");
954 assertWorkDir(mkmap(fname, "b", linkName, "/"));
955
956
957 git.checkout().setStartPoint(Constants.HEAD)
958 .addPath(fname).addPath(linkName).call();
959
960 assertWorkDir(mkmap(fname, "a", linkName, "a"));
961
962 Status st = git.status().call();
963 assertTrue(st.isClean());
964 }
965
966 @Test
967 public void testCheckoutChangeLinkToEmptyDirs() throws Exception {
968 Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
969 String fname = "was_file";
970 Git git = Git.wrap(db);
971
972
973 writeTrashFile(fname, "a");
974 git.add().addFilepattern(fname).call();
975
976
977 String linkName = "link";
978 File link = writeLink(linkName, fname).toFile();
979 git.add().addFilepattern(linkName).call();
980 git.commit().setMessage("Added file and link").call();
981
982 assertWorkDir(mkmap(linkName, "a", fname, "a"));
983
984
985 FileUtils.delete(link);
986 FileUtils.mkdirs(new File(link, "dummyDir"));
987 assertTrue("Link must be a directory now", link.isDirectory());
988
989 assertFalse("Must not delete non empty directory", link.delete());
990
991
992 writeTrashFile(fname, "b");
993 assertWorkDir(mkmap(fname, "b", linkName + "/dummyDir", "/"));
994
995
996 git.checkout().setStartPoint(Constants.HEAD)
997 .addPath(fname).addPath(linkName).call();
998
999 assertWorkDir(mkmap(fname, "a", linkName, "a"));
1000
1001 Status st = git.status().call();
1002 assertTrue(st.isClean());
1003 }
1004
1005 @Test
1006 public void testCheckoutChangeLinkToNonEmptyDirs() throws Exception {
1007 Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
1008 String fname = "file";
1009 Git git = Git.wrap(db);
1010
1011
1012 writeTrashFile(fname, "a");
1013 git.add().addFilepattern(fname).call();
1014
1015
1016 String linkName = "link";
1017 File link = writeLink(linkName, fname).toFile();
1018 git.add().addFilepattern(linkName).call();
1019 git.commit().setMessage("Added file and link").call();
1020
1021 assertWorkDir(mkmap(linkName, "a", fname, "a"));
1022
1023
1024 FileUtils.delete(link);
1025
1026
1027 writeTrashFile(linkName + "/dir1", "file1", "c");
1028
1029
1030 writeTrashFile(linkName + "/dir2", "file2", "d");
1031
1032 assertTrue("File must be a directory now", link.isDirectory());
1033 assertFalse("Must not delete non empty directory", link.delete());
1034
1035
1036 assertWorkDir(mkmap(fname, "a", linkName + "/dir1/file1", "c",
1037 linkName + "/dir2/file2", "d"));
1038
1039
1040 git.checkout().setStartPoint(Constants.HEAD).addPath(linkName).call();
1041
1042
1043 assertWorkDir(mkmap(linkName, "a", fname, "a"));
1044
1045 Status st = git.status().call();
1046 assertTrue(st.isClean());
1047 }
1048
1049 @Test
1050 public void testCheckoutChangeLinkToNonEmptyDirsAndNewIndexEntry()
1051 throws Exception {
1052 Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
1053 String fname = "file";
1054 Git git = Git.wrap(db);
1055
1056
1057 writeTrashFile(fname, "a");
1058 git.add().addFilepattern(fname).call();
1059
1060
1061 String linkName = "link";
1062 File link = writeLink(linkName, fname).toFile();
1063 git.add().addFilepattern(linkName).call();
1064 git.commit().setMessage("Added file and link").call();
1065
1066 assertWorkDir(mkmap(linkName, "a", fname, "a"));
1067
1068
1069 FileUtils.delete(link);
1070
1071
1072 writeTrashFile(linkName + "/dir1", "file1", "c");
1073 git.add().addFilepattern(linkName + "/dir1/file1").call();
1074
1075
1076 writeTrashFile(linkName + "/dir2", "file2", "d");
1077
1078 assertTrue("File must be a directory now", link.isDirectory());
1079 assertFalse("Must not delete non empty directory", link.delete());
1080
1081
1082 assertWorkDir(mkmap(fname, "a", linkName + "/dir1/file1", "c",
1083 linkName + "/dir2/file2", "d"));
1084
1085
1086 git.checkout().setStartPoint(Constants.HEAD).addPath(linkName).call();
1087
1088
1089 assertWorkDir(mkmap(linkName, "a", fname, "a"));
1090
1091 Status st = git.status().call();
1092 assertTrue(st.isClean());
1093 }
1094
1095 @Test
1096 public void testCheckoutChangeFileToEmptyDir() throws Exception {
1097 String fname = "was_file";
1098 Git git = Git.wrap(db);
1099
1100
1101 File file = writeTrashFile(fname, "a");
1102 git.add().addFilepattern(fname).call();
1103 git.commit().setMessage("Added file").call();
1104
1105
1106 FileUtils.delete(file);
1107 FileUtils.mkdir(file);
1108 assertTrue("File must be a directory now", file.isDirectory());
1109
1110 assertWorkDir(mkmap(fname, "/"));
1111
1112
1113 git.checkout().setStartPoint(Constants.HEAD).addPath(fname).call();
1114
1115 assertWorkDir(mkmap(fname, "a"));
1116
1117 Status st = git.status().call();
1118 assertTrue(st.isClean());
1119 }
1120
1121 @Test
1122 public void testCheckoutChangeFileToEmptyDirs() throws Exception {
1123 String fname = "was_file";
1124 Git git = Git.wrap(db);
1125
1126
1127 File file = writeTrashFile(fname, "a");
1128 git.add().addFilepattern(fname).call();
1129 git.commit().setMessage("Added file").call();
1130
1131
1132 FileUtils.delete(file);
1133 FileUtils.mkdirs(new File(file, "dummyDir"));
1134 assertTrue("File must be a directory now", file.isDirectory());
1135 assertFalse("Must not delete non empty directory", file.delete());
1136
1137 assertWorkDir(mkmap(fname + "/dummyDir", "/"));
1138
1139
1140 git.checkout().setStartPoint(Constants.HEAD).addPath(fname).call();
1141
1142 assertWorkDir(mkmap(fname, "a"));
1143
1144 Status st = git.status().call();
1145 assertTrue(st.isClean());
1146 }
1147
1148 @Test
1149 public void testCheckoutChangeFileToNonEmptyDirs() throws Exception {
1150 String fname = "was_file";
1151 Git git = Git.wrap(db);
1152
1153
1154 File file = writeTrashFile(fname, "a");
1155 git.add().addFilepattern(fname).call();
1156 git.commit().setMessage("Added file").call();
1157
1158 assertWorkDir(mkmap(fname, "a"));
1159
1160
1161 FileUtils.delete(file);
1162
1163
1164 writeTrashFile(fname + "/dir1", "file1", "c");
1165
1166
1167 writeTrashFile(fname + "/dir2", "file2", "d");
1168
1169 assertTrue("File must be a directory now", file.isDirectory());
1170 assertFalse("Must not delete non empty directory", file.delete());
1171
1172
1173 assertWorkDir(
1174 mkmap(fname + "/dir1/file1", "c", fname + "/dir2/file2", "d"));
1175
1176
1177 git.checkout().setStartPoint(Constants.HEAD).addPath(fname).call();
1178
1179
1180 assertWorkDir(mkmap(fname, "a"));
1181
1182 Status st = git.status().call();
1183 assertTrue(st.isClean());
1184 }
1185
1186 @Test
1187 public void testCheckoutChangeFileToNonEmptyDirsAndNewIndexEntry()
1188 throws Exception {
1189 String fname = "was_file";
1190 Git git = Git.wrap(db);
1191
1192
1193 File file = writeTrashFile(fname, "a");
1194 git.add().addFilepattern(fname).call();
1195 git.commit().setMessage("Added file").call();
1196
1197 assertWorkDir(mkmap(fname, "a"));
1198
1199
1200 FileUtils.delete(file);
1201
1202
1203 writeTrashFile(fname + "/dir", "file1", "c");
1204 git.add().addFilepattern(fname + "/dir/file1").call();
1205
1206
1207 writeTrashFile(fname + "/dir", "file2", "d");
1208
1209 assertTrue("File must be a directory now", file.isDirectory());
1210 assertFalse("Must not delete non empty directory", file.delete());
1211
1212
1213 assertWorkDir(
1214 mkmap(fname + "/dir/file1", "c", fname + "/dir/file2", "d"));
1215
1216
1217 git.checkout().setStartPoint(Constants.HEAD).addPath(fname).call();
1218 assertWorkDir(mkmap(fname, "a"));
1219
1220 Status st = git.status().call();
1221 assertTrue(st.isClean());
1222 }
1223
1224 @Test
1225 public void testCheckoutOutChangesAutoCRLFfalse() throws IOException {
1226 setupCase(mk("foo"), mkmap("foo/bar", "foo\nbar"), mk("foo"));
1227 checkout();
1228 assertIndex(mkmap("foo/bar", "foo\nbar"));
1229 assertWorkDir(mkmap("foo/bar", "foo\nbar"));
1230 }
1231
1232 @Test
1233 public void testCheckoutOutChangesAutoCRLFInput() throws IOException {
1234 setupCase(mk("foo"), mkmap("foo/bar", "foo\nbar"), mk("foo"));
1235 db.getConfig().setString("core", null, "autocrlf", "input");
1236 checkout();
1237 assertIndex(mkmap("foo/bar", "foo\nbar"));
1238 assertWorkDir(mkmap("foo/bar", "foo\nbar"));
1239 }
1240
1241 @Test
1242 public void testCheckoutOutChangesAutoCRLFtrue() throws IOException {
1243 setupCase(mk("foo"), mkmap("foo/bar", "foo\nbar"), mk("foo"));
1244 db.getConfig().setString("core", null, "autocrlf", "true");
1245 checkout();
1246 assertIndex(mkmap("foo/bar", "foo\nbar"));
1247 assertWorkDir(mkmap("foo/bar", "foo\r\nbar"));
1248 }
1249
1250 @Test
1251 public void testCheckoutOutChangesAutoCRLFtrueBinary() throws IOException {
1252 setupCase(mk("foo"), mkmap("foo/bar", "foo\nb\u0000ar"), mk("foo"));
1253 db.getConfig().setString("core", null, "autocrlf", "true");
1254 checkout();
1255 assertIndex(mkmap("foo/bar", "foo\nb\u0000ar"));
1256 assertWorkDir(mkmap("foo/bar", "foo\nb\u0000ar"));
1257 }
1258
1259 @Test
1260 public void testCheckoutUncachedChanges() throws IOException {
1261 setupCase(mk("foo"), mk("foo"), mk("foo"));
1262 writeTrashFile("foo", "otherData");
1263 checkout();
1264 assertIndex(mk("foo"));
1265 assertWorkDir(mkmap("foo", "otherData"));
1266 assertTrue(new File(trash, "foo").isFile());
1267 }
1268
1269 @Test
1270 public void testDontOverwriteDirtyFile() throws IOException {
1271 setupCase(mk("foo"), mk("other"), mk("foo"));
1272 writeTrashFile("foo", "different");
1273 try {
1274 checkout();
1275 fail("Didn't got the expected conflict");
1276 } catch (CheckoutConflictException e) {
1277 assertIndex(mk("foo"));
1278 assertWorkDir(mkmap("foo", "different"));
1279 assertEquals(Arrays.asList("foo"), getConflicts());
1280 assertTrue(new File(trash, "foo").isFile());
1281 }
1282 }
1283
1284 @Test
1285 public void testDontOverwriteEmptyFolder() throws IOException {
1286 setupCase(mk("foo"), mk("foo"), mk("foo"));
1287 FileUtils.mkdir(new File(db.getWorkTree(), "d"));
1288 checkout();
1289 assertWorkDir(mkmap("foo", "foo", "d", "/"));
1290 }
1291
1292 @Test
1293 public void testOverwriteUntrackedIgnoredFile() throws IOException,
1294 GitAPIException {
1295 String fname="file.txt";
1296 Git git = Git.wrap(db);
1297
1298
1299 writeTrashFile(fname, "a");
1300 git.add().addFilepattern(fname).call();
1301 git.commit().setMessage("create file").call();
1302
1303
1304 git.branchCreate().setName("side").call();
1305
1306
1307 writeTrashFile(fname, "b");
1308 git.add().addFilepattern(fname).call();
1309 git.commit().setMessage("modify file").call();
1310
1311
1312 git.checkout().setName("side").call();
1313 git.rm().addFilepattern(fname).call();
1314 writeTrashFile(".gitignore", fname);
1315 git.add().addFilepattern(".gitignore").call();
1316 git.commit().setMessage("delete and ignore file").call();
1317
1318 writeTrashFile(fname, "Something different");
1319 git.checkout().setName("master").call();
1320 assertWorkDir(mkmap(fname, "b"));
1321 assertTrue(git.status().call().isClean());
1322 }
1323
1324 @Test
1325 public void testOverwriteUntrackedFileModeChange()
1326 throws IOException, GitAPIException {
1327 String fname = "file.txt";
1328 Git git = Git.wrap(db);
1329
1330
1331 File file = writeTrashFile(fname, "a");
1332 git.add().addFilepattern(fname).call();
1333 git.commit().setMessage("create file").call();
1334 assertWorkDir(mkmap(fname, "a"));
1335
1336
1337 git.branchCreate().setName("side").call();
1338
1339
1340 git.checkout().setName("side").call();
1341
1342
1343 FileUtils.delete(file);
1344
1345
1346 writeTrashFile(fname + "/dir1", "file1", "c");
1347 git.add().addFilepattern(fname + "/dir1/file1").call();
1348
1349
1350 writeTrashFile(fname + "/dir2", "file2", "d");
1351
1352 assertTrue("File must be a directory now", file.isDirectory());
1353 assertFalse("Must not delete non empty directory", file.delete());
1354
1355
1356 assertWorkDir(
1357 mkmap(fname + "/dir1/file1", "c", fname + "/dir2/file2", "d"));
1358
1359 try {
1360 git.checkout().setName("master").call();
1361 fail("did not throw exception");
1362 } catch (Exception e) {
1363
1364 assertWorkDir(mkmap(fname + "/dir1/file1", "c",
1365 fname + "/dir2/file2", "d"));
1366 }
1367 }
1368
1369 @Test
1370 public void testOverwriteUntrackedLinkModeChange()
1371 throws Exception {
1372 Assume.assumeTrue(FS.DETECTED.supportsSymlinks());
1373 String fname = "file.txt";
1374 Git git = Git.wrap(db);
1375
1376
1377 writeTrashFile(fname, "a");
1378 git.add().addFilepattern(fname).call();
1379
1380
1381 String linkName = "link";
1382 File link = writeLink(linkName, fname).toFile();
1383 git.add().addFilepattern(linkName).call();
1384 git.commit().setMessage("Added file and link").call();
1385
1386 assertWorkDir(mkmap(linkName, "a", fname, "a"));
1387
1388
1389 git.branchCreate().setName("side").call();
1390
1391
1392 git.checkout().setName("side").call();
1393
1394
1395 FileUtils.delete(link);
1396
1397
1398 writeTrashFile(linkName + "/dir1", "file1", "c");
1399 git.add().addFilepattern(linkName + "/dir1/file1").call();
1400
1401
1402 writeTrashFile(linkName + "/dir2", "file2", "d");
1403
1404 assertTrue("Link must be a directory now", link.isDirectory());
1405 assertFalse("Must not delete non empty directory", link.delete());
1406
1407
1408 assertWorkDir(mkmap(fname, "a", linkName + "/dir1/file1", "c",
1409 linkName + "/dir2/file2", "d"));
1410
1411 try {
1412 git.checkout().setName("master").call();
1413 fail("did not throw exception");
1414 } catch (Exception e) {
1415
1416 assertWorkDir(mkmap(fname, "a", linkName + "/dir1/file1", "c",
1417 linkName + "/dir2/file2", "d"));
1418 }
1419 }
1420
1421 @Test
1422 public void testFileModeChangeWithNoContentChangeUpdate() throws Exception {
1423 if (!FS.DETECTED.supportsExecute())
1424 return;
1425
1426 Git git = Git.wrap(db);
1427
1428
1429 File file = writeTrashFile("file.txt", "a");
1430 git.add().addFilepattern("file.txt").call();
1431 git.commit().setMessage("commit1").call();
1432 assertFalse(db.getFS().canExecute(file));
1433
1434
1435 git.branchCreate().setName("b1").call();
1436
1437
1438 db.getFS().setExecute(file, true);
1439 git.add().addFilepattern("file.txt").call();
1440 git.commit().setMessage("commit2").call();
1441
1442
1443 Status status = git.status().call();
1444 assertTrue(status.getModified().isEmpty());
1445 assertTrue(status.getChanged().isEmpty());
1446 assertTrue(db.getFS().canExecute(file));
1447
1448
1449 git.checkout().setName("b1").call();
1450
1451
1452 status = git.status().call();
1453 assertTrue(status.getModified().isEmpty());
1454 assertTrue(status.getChanged().isEmpty());
1455 assertFalse(db.getFS().canExecute(file));
1456 }
1457
1458 @Test
1459 public void testFileModeChangeAndContentChangeConflict() throws Exception {
1460 if (!FS.DETECTED.supportsExecute())
1461 return;
1462
1463 Git git = Git.wrap(db);
1464
1465
1466 File file = writeTrashFile("file.txt", "a");
1467 git.add().addFilepattern("file.txt").call();
1468 git.commit().setMessage("commit1").call();
1469 assertFalse(db.getFS().canExecute(file));
1470
1471
1472 git.branchCreate().setName("b1").call();
1473
1474
1475 db.getFS().setExecute(file, true);
1476 git.add().addFilepattern("file.txt").call();
1477 git.commit().setMessage("commit2").call();
1478
1479
1480 Status status = git.status().call();
1481 assertTrue(status.getModified().isEmpty());
1482 assertTrue(status.getChanged().isEmpty());
1483 assertTrue(db.getFS().canExecute(file));
1484
1485 writeTrashFile("file.txt", "b");
1486
1487
1488 CheckoutCommand checkout = git.checkout().setName("b1");
1489 try {
1490 checkout.call();
1491 fail("Checkout exception not thrown");
1492 } catch (org.eclipse.jgit.api.errors.CheckoutConflictException e) {
1493 CheckoutResult result = checkout.getResult();
1494 assertNotNull(result);
1495 assertNotNull(result.getConflictList());
1496 assertEquals(1, result.getConflictList().size());
1497 assertTrue(result.getConflictList().contains("file.txt"));
1498 }
1499 }
1500
1501 @Test
1502 public void testDirtyFileModeEqualHeadMerge()
1503 throws Exception {
1504 if (!FS.DETECTED.supportsExecute())
1505 return;
1506
1507 Git git = Git.wrap(db);
1508
1509
1510 File file = writeTrashFile("file.txt", "a");
1511 git.add().addFilepattern("file.txt").call();
1512 git.commit().setMessage("commit1").call();
1513 assertFalse(db.getFS().canExecute(file));
1514
1515
1516 git.branchCreate().setName("b1").call();
1517
1518
1519 writeTrashFile("file2.txt", "");
1520 git.add().addFilepattern("file2.txt").call();
1521 git.commit().setMessage("commit2").call();
1522
1523
1524 writeTrashFile("file.txt", "a");
1525 db.getFS().setExecute(file, true);
1526 git.add().addFilepattern("file.txt").call();
1527
1528
1529 writeTrashFile("file.txt", "b");
1530
1531 assertEquals(
1532 "[file.txt, mode:100755, content:a][file2.txt, mode:100644, content:]",
1533 indexState(CONTENT));
1534 assertWorkDir(mkmap("file.txt", "b", "file2.txt", ""));
1535
1536
1537
1538 git.checkout().setName("b1").call();
1539 assertEquals("[file.txt, mode:100755, content:a]", indexState(CONTENT));
1540 assertWorkDir(mkmap("file.txt", "b"));
1541 }
1542
1543 @Test
1544 public void testDirtyFileModeEqualIndexMerge()
1545 throws Exception {
1546 if (!FS.DETECTED.supportsExecute())
1547 return;
1548
1549 Git git = Git.wrap(db);
1550
1551
1552 File file = writeTrashFile("file.txt", "a");
1553 git.add().addFilepattern("file.txt").call();
1554 git.commit().setMessage("commit1").call();
1555 assertFalse(db.getFS().canExecute(file));
1556
1557
1558 git.branchCreate().setName("b1").call();
1559
1560
1561 file = writeTrashFile("file.txt", "b");
1562 db.getFS().setExecute(file, true);
1563 git.add().addFilepattern("file.txt").call();
1564 git.commit().setMessage("commit2").call();
1565
1566
1567 writeTrashFile("file.txt", "a");
1568 db.getFS().setExecute(file, false);
1569 git.add().addFilepattern("file.txt").call();
1570
1571
1572 writeTrashFile("file.txt", "c");
1573 db.getFS().setExecute(file, true);
1574
1575 assertEquals("[file.txt, mode:100644, content:a]", indexState(CONTENT));
1576 assertWorkDir(mkmap("file.txt", "c"));
1577
1578
1579
1580 git.checkout().setName("b1").call();
1581 assertEquals("[file.txt, mode:100644, content:a]", indexState(CONTENT));
1582 assertWorkDir(mkmap("file.txt", "c"));
1583 }
1584
1585 @Test
1586 public void testFileModeChangeAndContentChangeNoConflict() throws Exception {
1587 if (!FS.DETECTED.supportsExecute())
1588 return;
1589
1590 Git git = Git.wrap(db);
1591
1592
1593 File file1 = writeTrashFile("file1.txt", "a");
1594 git.add().addFilepattern("file1.txt").call();
1595 git.commit().setMessage("commit1").call();
1596 assertFalse(db.getFS().canExecute(file1));
1597
1598
1599 File file2 = writeTrashFile("file2.txt", "b");
1600 git.add().addFilepattern("file2.txt").call();
1601 git.commit().setMessage("commit2").call();
1602 assertFalse(db.getFS().canExecute(file2));
1603
1604
1605 assertNotNull(git.checkout().setCreateBranch(true).setName("b1")
1606 .setStartPoint(Constants.HEAD + "~1").call());
1607
1608
1609 file1 = writeTrashFile("file1.txt", "c");
1610 db.getFS().setExecute(file1, true);
1611 git.add().addFilepattern("file1.txt").call();
1612
1613
1614 assertNotNull(git.checkout().setName(Constants.MASTER).call());
1615 }
1616
1617 @Test(expected = CheckoutConflictException.class)
1618 public void testFolderFileConflict() throws Exception {
1619 RevCommit headCommit = commitFile("f/a", "initial content", "master");
1620 RevCommit checkoutCommit = commitFile("f/a", "side content", "side");
1621 FileUtils.delete(new File(db.getWorkTree(), "f"), FileUtils.RECURSIVE);
1622 writeTrashFile("f", "file instead of folder");
1623 new DirCacheCheckout(db, headCommit.getTree(), db.lockDirCache(),
1624 checkoutCommit.getTree()).checkout();
1625 }
1626
1627 @Test
1628 public void testMultipleContentConflicts() throws Exception {
1629 commitFile("a", "initial content", "master");
1630 RevCommit headCommit = commitFile("b", "initial content", "master");
1631 commitFile("a", "side content", "side");
1632 RevCommit checkoutCommit = commitFile("b", "side content", "side");
1633 writeTrashFile("a", "changed content");
1634 writeTrashFile("b", "changed content");
1635
1636 try {
1637 new DirCacheCheckout(db, headCommit.getTree(), db.lockDirCache(),
1638 checkoutCommit.getTree()).checkout();
1639 fail();
1640 } catch (CheckoutConflictException expected) {
1641 assertEquals(2, expected.getConflictingFiles().length);
1642 assertTrue(Arrays.asList(expected.getConflictingFiles())
1643 .contains("a"));
1644 assertTrue(Arrays.asList(expected.getConflictingFiles())
1645 .contains("b"));
1646 assertEquals("changed content", read("a"));
1647 assertEquals("changed content", read("b"));
1648 }
1649 }
1650
1651 @Test
1652 public void testFolderFileAndContentConflicts() throws Exception {
1653 RevCommit headCommit = commitFile("f/a", "initial content", "master");
1654 commitFile("b", "side content", "side");
1655 RevCommit checkoutCommit = commitFile("f/a", "side content", "side");
1656 FileUtils.delete(new File(db.getWorkTree(), "f"), FileUtils.RECURSIVE);
1657 writeTrashFile("f", "file instead of a folder");
1658 writeTrashFile("b", "changed content");
1659
1660 try {
1661 new DirCacheCheckout(db, headCommit.getTree(), db.lockDirCache(),
1662 checkoutCommit.getTree()).checkout();
1663 fail();
1664 } catch (CheckoutConflictException expected) {
1665 assertEquals(2, expected.getConflictingFiles().length);
1666 assertTrue(Arrays.asList(expected.getConflictingFiles())
1667 .contains("b"));
1668 assertTrue(Arrays.asList(expected.getConflictingFiles())
1669 .contains("f"));
1670 assertEquals("file instead of a folder", read("f"));
1671 assertEquals("changed content", read("b"));
1672 }
1673 }
1674
1675 public void assertWorkDir(Map<String, String> i)
1676 throws CorruptObjectException,
1677 IOException {
1678 try (TreeWalk walk = new TreeWalk(db)) {
1679 walk.setRecursive(false);
1680 walk.addTree(new FileTreeIterator(db));
1681 String expectedValue;
1682 String path;
1683 int nrFiles = 0;
1684 FileTreeIterator ft;
1685 while (walk.next()) {
1686 ft = walk.getTree(0, FileTreeIterator.class);
1687 path = ft.getEntryPathString();
1688 expectedValue = i.get(path);
1689 File file = new File(db.getWorkTree(), path);
1690 assertTrue(file.exists());
1691 if (file.isFile()) {
1692 assertNotNull("found unexpected file for path " + path
1693 + " in workdir", expectedValue);
1694 FileInputStream is = new FileInputStream(file);
1695 byte[] buffer = new byte[(int) file.length()];
1696 int offset = 0;
1697 int numRead = 0;
1698 while (offset < buffer.length
1699 && (numRead = is.read(buffer, offset, buffer.length
1700 - offset)) >= 0) {
1701 offset += numRead;
1702 }
1703 is.close();
1704 assertArrayEquals("unexpected content for path " + path
1705 + " in workDir. ", buffer, i.get(path).getBytes());
1706 nrFiles++;
1707 } else if (file.isDirectory()) {
1708 String[] files = file.list();
1709 if (files != null && files.length == 0) {
1710 assertEquals("found unexpected empty folder for path "
1711 + path + " in workDir. ", "/", i.get(path));
1712 nrFiles++;
1713 }
1714 }
1715 if (walk.isSubtree()) {
1716 walk.enterSubtree();
1717 }
1718 }
1719 assertEquals("WorkDir has not the right size.", i.size(), nrFiles);
1720 }
1721 }
1722 }