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.DirCacheEditor;
69 import org.eclipse.jgit.dircache.DirCacheEditor.PathEdit;
70 import org.eclipse.jgit.dircache.DirCacheEntry;
71 import org.eclipse.jgit.errors.CheckoutConflictException;
72 import org.eclipse.jgit.errors.CorruptObjectException;
73 import org.eclipse.jgit.errors.NoWorkTreeException;
74 import org.eclipse.jgit.junit.RepositoryTestCase;
75 import org.eclipse.jgit.junit.TestRepository;
76 import org.eclipse.jgit.junit.TestRepository.BranchBuilder;
77 import org.eclipse.jgit.revwalk.RevCommit;
78 import org.eclipse.jgit.treewalk.FileTreeIterator;
79 import org.eclipse.jgit.treewalk.TreeWalk;
80 import org.eclipse.jgit.util.FS;
81 import org.junit.Test;
82
83 public class DirCacheCheckoutTest extends RepositoryTestCase {
84 private DirCacheCheckout dco;
85 protected ObjectId theHead;
86 protected ObjectId theMerge;
87 private DirCache dirCache;
88
89 private void prescanTwoTrees(ObjectId head, ObjectId merge)
90 throws IllegalStateException, IOException {
91 DirCache dc = db.lockDirCache();
92 try {
93 dco = new DirCacheCheckout(db, head, dc, merge);
94 dco.preScanTwoTrees();
95 } finally {
96 dc.unlock();
97 }
98 }
99
100 private void checkout() throws IOException {
101 DirCache dc = db.lockDirCache();
102 try {
103 dco = new DirCacheCheckout(db, theHead, dc, theMerge);
104 dco.checkout();
105 } finally {
106 dc.unlock();
107 }
108 }
109
110 private List<String> getRemoved() {
111 return dco.getRemoved();
112 }
113
114 private Map<String, ObjectId> getUpdated() {
115 return dco.getUpdated();
116 }
117
118 private List<String> getConflicts() {
119 return dco.getConflicts();
120 }
121
122 private static HashMap<String, String> mk(String a) {
123 return mkmap(a, a);
124 }
125
126 private static HashMap<String, String> mkmap(String... args) {
127 if ((args.length % 2) > 0)
128 throw new IllegalArgumentException("needs to be pairs");
129
130 HashMap<String, String> map = new HashMap<String, String>();
131 for (int i = 0; i < args.length; i += 2) {
132 map.put(args[i], args[i + 1]);
133 }
134
135 return map;
136 }
137
138 @Test
139 public void testResetHard() throws IOException, NoFilepatternException,
140 GitAPIException {
141 Git git = new Git(db);
142 writeTrashFile("f", "f()");
143 writeTrashFile("D/g", "g()");
144 git.add().addFilepattern(".").call();
145 git.commit().setMessage("inital").call();
146 assertIndex(mkmap("f", "f()", "D/g", "g()"));
147
148 git.branchCreate().setName("topic").call();
149
150 writeTrashFile("f", "f()\nmaster");
151 writeTrashFile("D/g", "g()\ng2()");
152 writeTrashFile("E/h", "h()");
153 git.add().addFilepattern(".").call();
154 RevCommit master = git.commit().setMessage("master-1").call();
155 assertIndex(mkmap("f", "f()\nmaster", "D/g", "g()\ng2()", "E/h", "h()"));
156
157 checkoutBranch("refs/heads/topic");
158 assertIndex(mkmap("f", "f()", "D/g", "g()"));
159
160 writeTrashFile("f", "f()\nside");
161 assertTrue(new File(db.getWorkTree(), "D/g").delete());
162 writeTrashFile("G/i", "i()");
163 git.add().addFilepattern(".").call();
164 git.add().addFilepattern(".").setUpdate(true).call();
165 RevCommit topic = git.commit().setMessage("topic-1").call();
166 assertIndex(mkmap("f", "f()\nside", "G/i", "i()"));
167
168 writeTrashFile("untracked", "untracked");
169
170 resetHard(master);
171 assertIndex(mkmap("f", "f()\nmaster", "D/g", "g()\ng2()", "E/h", "h()"));
172 resetHard(topic);
173 assertIndex(mkmap("f", "f()\nside", "G/i", "i()"));
174 assertWorkDir(mkmap("f", "f()\nside", "G/i", "i()", "untracked",
175 "untracked"));
176
177 assertEquals(MergeStatus.CONFLICTING, git.merge().include(master)
178 .call().getMergeStatus());
179 assertEquals(
180 "[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]",
181 indexState(0));
182
183 resetHard(master);
184 assertIndex(mkmap("f", "f()\nmaster", "D/g", "g()\ng2()", "E/h", "h()"));
185 assertWorkDir(mkmap("f", "f()\nmaster", "D/g", "g()\ng2()", "E/h",
186 "h()", "untracked", "untracked"));
187 }
188
189
190
191
192
193
194
195
196
197
198 @Test
199 public void testResetHardFromIndexEntryWithoutFileToTreeWithoutFile()
200 throws Exception {
201 Git git = new Git(db);
202 writeTrashFile("x", "x");
203 git.add().addFilepattern("x").call();
204 RevCommit id1 = git.commit().setMessage("c1").call();
205
206 writeTrashFile("f/g", "f/g");
207 git.rm().addFilepattern("x").call();
208 git.add().addFilepattern("f/g").call();
209 git.commit().setMessage("c2").call();
210 deleteTrashFile("f/g");
211 deleteTrashFile("f");
212
213
214 git.reset().setMode(ResetType.HARD).setRef(id1.getName()).call();
215 assertIndex(mkmap("x", "x"));
216 }
217
218
219
220
221
222
223 @Test
224 public void testInitialCheckout() throws Exception {
225 Git git = new Git(db);
226
227 TestRepository<Repository> db_t = new TestRepository<Repository>(db);
228 BranchBuilder master = db_t.branch("master");
229 master.commit().add("f", "1").message("m0").create();
230 assertFalse(new File(db.getWorkTree(), "f").exists());
231 git.checkout().setName("master").call();
232 assertTrue(new File(db.getWorkTree(), "f").exists());
233 }
234
235 private DirCacheCheckout resetHard(RevCommit commit)
236 throws NoWorkTreeException,
237 CorruptObjectException, IOException {
238 DirCacheCheckout dc;
239 dc = new DirCacheCheckout(db, null, db.lockDirCache(),
240 commit.getTree());
241 dc.setFailOnConflict(true);
242 assertTrue(dc.checkout());
243 return dc;
244 }
245
246 private void assertIndex(HashMap<String, String> i)
247 throws CorruptObjectException, IOException {
248 String expectedValue;
249 String path;
250 DirCache read = DirCache.read(db.getIndexFile(), db.getFS());
251
252 assertEquals("Index has not the right size.", i.size(),
253 read.getEntryCount());
254 for (int j = 0; j < read.getEntryCount(); j++) {
255 path = read.getEntry(j).getPathString();
256 expectedValue = i.get(path);
257 assertNotNull("found unexpected entry for path " + path
258 + " in index", expectedValue);
259 assertTrue("unexpected content for path " + path
260 + " in index. Expected: <" + expectedValue + ">",
261 Arrays.equals(db.open(read.getEntry(j).getObjectId())
262 .getCachedBytes(), i.get(path).getBytes()));
263 }
264 }
265
266 @Test
267 public void testRules1thru3_NoIndexEntry() throws IOException {
268 ObjectId head = buildTree(mk("foo"));
269 TreeWalk tw = TreeWalk.forPath(db, "foo", head);
270 ObjectId objectId = tw.getObjectId(0);
271 ObjectId merge = db.newObjectInserter().insert(Constants.OBJ_TREE,
272 new byte[0]);
273
274 prescanTwoTrees(head, merge);
275
276 assertTrue(getRemoved().contains("foo"));
277
278 prescanTwoTrees(merge, head);
279
280 assertEquals(objectId, getUpdated().get("foo"));
281
282 merge = buildTree(mkmap("foo", "a"));
283 tw = TreeWalk.forPath(db, "foo", merge);
284
285 prescanTwoTrees(head, merge);
286
287 assertConflict("foo");
288 }
289
290 void setupCase(HashMap<String, String> headEntries, HashMap<String, String> mergeEntries, HashMap<String, String> indexEntries) throws IOException {
291 theHead = buildTree(headEntries);
292 theMerge = buildTree(mergeEntries);
293 buildIndex(indexEntries);
294 }
295
296 private void buildIndex(HashMap<String, String> indexEntries) throws IOException {
297 dirCache = new DirCache(db.getIndexFile(), db.getFS());
298 if (indexEntries != null) {
299 assertTrue(dirCache.lock());
300 DirCacheEditor editor = dirCache.editor();
301 for (java.util.Map.Entry<String,String> e : indexEntries.entrySet()) {
302 writeTrashFile(e.getKey(), e.getValue());
303 ObjectInserter inserter = db.newObjectInserter();
304 final ObjectId id = inserter.insert(Constants.OBJ_BLOB,
305 Constants.encode(e.getValue()));
306 editor.add(new DirCacheEditor.DeletePath(e.getKey()));
307 editor.add(new DirCacheEditor.PathEdit(e.getKey()) {
308 @Override
309 public void apply(DirCacheEntry ent) {
310 ent.setFileMode(FileMode.REGULAR_FILE);
311 ent.setObjectId(id);
312 ent.setUpdateNeeded(false);
313 }
314 });
315 }
316 assertTrue(editor.commit());
317 }
318
319 }
320
321 static final class AddEdit extends PathEdit {
322
323 private final ObjectId data;
324
325 private final long length;
326
327 public AddEdit(String entryPath, ObjectId data, long length) {
328 super(entryPath);
329 this.data = data;
330 this.length = length;
331 }
332
333 @Override
334 public void apply(DirCacheEntry ent) {
335 ent.setFileMode(FileMode.REGULAR_FILE);
336 ent.setLength(length);
337 ent.setObjectId(data);
338 }
339
340 }
341
342 private ObjectId buildTree(HashMap<String, String> headEntries)
343 throws IOException {
344 DirCache lockDirCache = DirCache.newInCore();
345
346 DirCacheEditor editor = lockDirCache.editor();
347 if (headEntries != null) {
348 for (java.util.Map.Entry<String, String> e : headEntries.entrySet()) {
349 AddEdit addEdit = new AddEdit(e.getKey(),
350 genSha1(e.getValue()), e.getValue().length());
351 editor.add(addEdit);
352 }
353 }
354 editor.finish();
355 return lockDirCache.writeTree(db.newObjectInserter());
356 }
357
358 ObjectId genSha1(String data) {
359 try (ObjectInserter w = db.newObjectInserter()) {
360 ObjectId id = w.insert(Constants.OBJ_BLOB, data.getBytes());
361 w.flush();
362 return id;
363 } catch (IOException e) {
364 fail(e.toString());
365 }
366 return null;
367 }
368
369 protected void go() throws IllegalStateException, IOException {
370 prescanTwoTrees(theHead, theMerge);
371 }
372
373 @Test
374 public void testRules4thru13_IndexEntryNotInHead() throws IOException {
375
376 HashMap<String, String> idxMap;
377
378 idxMap = new HashMap<String, String>();
379 idxMap.put("foo", "foo");
380 setupCase(null, null, idxMap);
381 go();
382
383 assertTrue(getUpdated().isEmpty());
384 assertTrue(getRemoved().isEmpty());
385 assertTrue(getConflicts().isEmpty());
386
387
388 idxMap = new HashMap<String, String>();
389 idxMap.put("foo", "foo");
390 setupCase(null, idxMap, idxMap);
391 go();
392
393 assertAllEmpty();
394
395
396 HashMap<String, String> mergeMap;
397 mergeMap = new HashMap<String, String>();
398
399 mergeMap.put("foo", "merge");
400 setupCase(null, mergeMap, idxMap);
401 go();
402
403 assertTrue(getUpdated().isEmpty());
404 assertTrue(getRemoved().isEmpty());
405 assertTrue(getConflicts().contains("foo"));
406
407
408
409 HashMap<String, String> headMap = new HashMap<String, String>();
410 headMap.put("foo", "foo");
411 setupCase(headMap, null, idxMap);
412 go();
413
414 assertTrue(getRemoved().contains("foo"));
415 assertTrue(getUpdated().isEmpty());
416 assertTrue(getConflicts().isEmpty());
417
418
419 setupCase(headMap, null, idxMap);
420 assertTrue(new File(trash, "foo").delete());
421 writeTrashFile("foo", "bar");
422 db.readDirCache().getEntry(0).setUpdateNeeded(true);
423 go();
424
425 assertTrue(getRemoved().isEmpty());
426 assertTrue(getUpdated().isEmpty());
427 assertTrue(getConflicts().contains("foo"));
428
429
430 headMap.put("foo", "head");
431 setupCase(headMap, null, idxMap);
432 go();
433
434 assertTrue(getRemoved().isEmpty());
435 assertTrue(getUpdated().isEmpty());
436 assertTrue(getConflicts().contains("foo"));
437
438
439 setupCase(headMap, headMap, idxMap);
440 go();
441
442 assertAllEmpty();
443
444
445 setupCase(headMap, mergeMap, idxMap); go();
446 assertTrue(getConflicts().contains("foo"));
447
448
449 setupCase(headMap, idxMap, idxMap); go();
450 assertAllEmpty();
451
452
453 setupCase(idxMap, mergeMap, idxMap); go();
454 assertTrue(getUpdated().containsKey("foo"));
455
456
457 setupCase(idxMap, mergeMap, idxMap);
458 assertTrue(new File(trash, "foo").delete());
459 writeTrashFile("foo", "bar");
460 db.readDirCache().getEntry(0).setUpdateNeeded(true);
461 go();
462 assertTrue(getConflicts().contains("foo"));
463 }
464
465 private void assertAllEmpty() {
466 assertTrue(getRemoved().isEmpty());
467 assertTrue(getUpdated().isEmpty());
468 assertTrue(getConflicts().isEmpty());
469 }
470
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 @Test
504 public void testDirectoryFileSimple() throws IOException {
505 ObjectId treeDF = buildTree(mkmap("DF", "DF"));
506 ObjectId treeDFDF = buildTree(mkmap("DF/DF", "DF/DF"));
507 buildIndex(mkmap("DF", "DF"));
508
509 prescanTwoTrees(treeDF, treeDFDF);
510
511 assertTrue(getRemoved().contains("DF"));
512 assertTrue(getUpdated().containsKey("DF/DF"));
513
514 recursiveDelete(new File(trash, "DF"));
515 buildIndex(mkmap("DF/DF", "DF/DF"));
516
517 prescanTwoTrees(treeDFDF, treeDF);
518 assertTrue(getRemoved().contains("DF/DF"));
519 assertTrue(getUpdated().containsKey("DF"));
520 }
521
522 @Test
523 public void testDirectoryFileConflicts_1() throws Exception {
524
525 doit(mk("DF/DF"), mk("DF"), mk("DF/DF"));
526 assertNoConflicts();
527 assertUpdated("DF");
528 assertRemoved("DF/DF");
529 }
530
531 @Test
532 public void testDirectoryFileConflicts_2() throws Exception {
533
534 setupCase(mk("DF/DF"), mk("DF"), mk("DF/DF"));
535 writeTrashFile("DF/DF", "different");
536 go();
537 assertConflict("DF/DF");
538
539 }
540
541 @Test
542 public void testDirectoryFileConflicts_3() throws Exception {
543
544 doit(mk("DF/DF"), mk("DF/DF"), mk("DF"));
545 assertNoConflicts();
546 }
547
548 @Test
549 public void testDirectoryFileConflicts_4() throws Exception {
550
551 doit(mk("DF/DF"), mkmap("DF/DF", "foo"), mk("DF"));
552 assertConflict("DF/DF");
553
554 }
555
556 @Test
557 public void testDirectoryFileConflicts_5() throws Exception {
558
559 doit(mk("DF/DF"), mk("DF"), mk("DF"));
560 assertRemoved("DF/DF");
561 assertEquals(0, dco.getConflicts().size());
562 assertEquals(0, dco.getUpdated().size());
563 }
564
565 @Test
566 public void testDirectoryFileConflicts_5b() throws Exception {
567
568 doit(mk("DF/DF"), mkmap("DF", "different"), mk("DF"));
569 assertRemoved("DF/DF");
570 assertConflict("DF");
571 assertEquals(0, dco.getUpdated().size());
572 }
573
574 @Test
575 public void testDirectoryFileConflicts_6() throws Exception {
576
577 setupCase(mk("DF/DF"), mk("DF"), mk("DF"));
578 writeTrashFile("DF", "different");
579 go();
580 assertRemoved("DF/DF");
581 assertEquals(0, dco.getConflicts().size());
582 assertEquals(0, dco.getUpdated().size());
583 }
584
585 @Test
586 public void testDirectoryFileConflicts_6b() throws Exception {
587
588 setupCase(mk("DF/DF"), mk("DF"), mkmap("DF", "different"));
589 writeTrashFile("DF", "again different");
590 go();
591 assertRemoved("DF/DF");
592 assertConflict("DF");
593 assertEquals(0, dco.getUpdated().size());
594 }
595
596 @Test
597 public void testDirectoryFileConflicts_7() throws Exception {
598
599 doit(mk("DF"), mk("DF"), mk("DF/DF"));
600 assertUpdated("DF");
601 assertRemoved("DF/DF");
602
603 cleanUpDF();
604 setupCase(mk("DF/DF"), mk("DF/DF"), mk("DF/DF/DF/DF/DF"));
605 go();
606 assertRemoved("DF/DF/DF/DF/DF");
607 assertUpdated("DF/DF");
608
609 cleanUpDF();
610 setupCase(mk("DF/DF"), mk("DF/DF"), mk("DF/DF/DF/DF/DF"));
611 writeTrashFile("DF/DF/DF/DF/DF", "diff");
612 go();
613 assertConflict("DF/DF/DF/DF/DF");
614
615
616
617
618
619
620
621
622
623 }
624
625 @Test
626 public void testDirectoryFileConflicts_8() throws Exception {
627
628 setupCase(mk("DF"), mk("DF"), mk("DF/DF"));
629 recursiveDelete(new File(db.getWorkTree(), "DF"));
630 writeTrashFile("DF", "xy");
631 go();
632 assertConflict("DF/DF");
633 }
634
635 @Test
636 public void testDirectoryFileConflicts_9() throws Exception {
637
638 doit(mkmap("DF", "QP"), mkmap("DF", "QP"), mkmap("DF/DF", "DF/DF"));
639 assertRemoved("DF/DF");
640 assertUpdated("DF");
641 }
642
643 @Test
644 public void testDirectoryFileConflicts_10() throws Exception {
645
646 cleanUpDF();
647 doit(mk("DF"), mk("DF/DF"), mk("DF/DF"));
648 assertNoConflicts();
649 }
650
651 @Test
652 public void testDirectoryFileConflicts_11() throws Exception {
653
654 doit(mk("DF"), mk("DF/DF"), mkmap("DF/DF", "asdf"));
655 assertConflict("DF/DF");
656 }
657
658 @Test
659 public void testDirectoryFileConflicts_12() throws Exception {
660
661 cleanUpDF();
662 doit(mk("DF"), mk("DF/DF"), mk("DF"));
663 assertRemoved("DF");
664 assertUpdated("DF/DF");
665 }
666
667 @Test
668 public void testDirectoryFileConflicts_13() throws Exception {
669
670 cleanUpDF();
671 setupCase(mk("DF"), mk("DF/DF"), mk("DF"));
672 writeTrashFile("DF", "asdfsdf");
673 go();
674 assertConflict("DF");
675 assertUpdated("DF/DF");
676 }
677
678 @Test
679 public void testDirectoryFileConflicts_14() throws Exception {
680
681 cleanUpDF();
682 doit(mk("DF"), mk("DF/DF"), mkmap("DF", "Foo"));
683 assertConflict("DF");
684 assertUpdated("DF/DF");
685 }
686
687 @Test
688 public void testDirectoryFileConflicts_15() throws Exception {
689
690 doit(mkmap(), mk("DF/DF"), mk("DF"));
691
692
693
694
695
696 assertUpdated("DF/DF");
697 }
698
699 @Test
700 public void testDirectoryFileConflicts_15b() throws Exception {
701
702 doit(mkmap(), mk("DF/DF/DF/DF"), mk("DF"));
703
704
705
706
707
708
709 assertUpdated("DF/DF/DF/DF");
710 }
711
712 @Test
713 public void testDirectoryFileConflicts_16() throws Exception {
714
715 cleanUpDF();
716 doit(mkmap(), mk("DF"), mk("DF/DF/DF"));
717 assertRemoved("DF/DF/DF");
718 assertUpdated("DF");
719 }
720
721 @Test
722 public void testDirectoryFileConflicts_17() throws Exception {
723
724 cleanUpDF();
725 setupCase(mkmap(), mk("DF"), mk("DF/DF/DF"));
726 writeTrashFile("DF/DF/DF", "asdf");
727 go();
728 assertConflict("DF/DF/DF");
729
730
731
732
733
734
735 }
736
737 @Test
738 public void testDirectoryFileConflicts_18() throws Exception {
739
740 cleanUpDF();
741 doit(mk("DF/DF"), mk("DF/DF/DF/DF"), null);
742 assertRemoved("DF/DF");
743 assertUpdated("DF/DF/DF/DF");
744 }
745
746 @Test
747 public void testDirectoryFileConflicts_19() throws Exception {
748
749 cleanUpDF();
750 doit(mk("DF/DF/DF/DF"), mk("DF/DF/DF"), null);
751 assertRemoved("DF/DF/DF/DF");
752 assertUpdated("DF/DF/DF");
753 }
754
755 protected void cleanUpDF() throws Exception {
756 tearDown();
757 setUp();
758 recursiveDelete(new File(trash, "DF"));
759 }
760
761 protected void assertConflict(String s) {
762 assertTrue(getConflicts().contains(s));
763 }
764
765 protected void assertUpdated(String s) {
766 assertTrue(getUpdated().containsKey(s));
767 }
768
769 protected void assertRemoved(String s) {
770 assertTrue(getRemoved().contains(s));
771 }
772
773 protected void assertNoConflicts() {
774 assertTrue(getConflicts().isEmpty());
775 }
776
777 protected void doit(HashMap<String, String> h, HashMap<String, String> m, HashMap<String, String> i)
778 throws IOException {
779 setupCase(h, m, i);
780 go();
781 }
782
783 @Test
784 public void testUntrackedConflicts() throws IOException {
785 setupCase(null, mk("foo"), null);
786 writeTrashFile("foo", "foo");
787 go();
788
789
790 recursiveDelete(new File(trash, "foo"));
791 setupCase(mk("other"), mkmap("other", "other", "foo", "foo"),
792 mk("other"));
793 writeTrashFile("foo", "bar");
794 try {
795 checkout();
796 fail("didn't get the expected exception");
797 } catch (CheckoutConflictException e) {
798 assertConflict("foo");
799 assertWorkDir(mkmap("foo", "bar", "other", "other"));
800 assertIndex(mk("other"));
801 }
802
803
804 recursiveDelete(new File(trash, "other"));
805 recursiveDelete(new File(trash, "foo"));
806 setupCase(null, mk("foo"), null);
807 writeTrashFile("foo", "bar");
808 try {
809 checkout();
810 fail("didn't get the expected exception");
811 } catch (CheckoutConflictException e) {
812 assertConflict("foo");
813 assertWorkDir(mkmap("foo", "bar"));
814 assertIndex(mkmap("other", "other"));
815 }
816
817
818
819
820
821
822
823
824
825
826 recursiveDelete(new File(trash, "foo"));
827 recursiveDelete(new File(trash, "other"));
828 setupCase(null, mk("foo"), null);
829 writeTrashFile("foo/bar/baz", "");
830 writeTrashFile("foo/blahblah", "");
831 go();
832
833 assertConflict("foo");
834 assertConflict("foo/bar/baz");
835 assertConflict("foo/blahblah");
836
837 recursiveDelete(new File(trash, "foo"));
838
839 setupCase(mkmap("foo/bar", "", "foo/baz", ""),
840 mk("foo"), mkmap("foo/bar", "", "foo/baz", ""));
841 assertTrue(new File(trash, "foo/bar").exists());
842 go();
843
844 assertNoConflicts();
845 }
846
847 @Test
848 public void testCloseNameConflictsX0() throws IOException {
849 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") );
850 checkout();
851 assertIndex(mkmap("a/a", "a/a", "b.b/b.b", "b.b/b.bs"));
852 assertWorkDir(mkmap("a/a", "a/a", "b.b/b.b", "b.b/b.bs"));
853 go();
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 assertNoConflicts();
857 }
858
859 @Test
860 public void testCloseNameConflicts1() throws IOException {
861 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") );
862 checkout();
863 assertIndex(mkmap("a/a", "a/a", "a.a/a.a", "a.a/a.a"));
864 assertWorkDir(mkmap("a/a", "a/a", "a.a/a.a", "a.a/a.a"));
865 go();
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 assertNoConflicts();
869 }
870
871 @Test
872 public void testCheckoutHierarchy() throws IOException {
873 setupCase(
874 mkmap("a", "a", "b/c", "b/c", "d", "d", "e/f", "e/f", "e/g",
875 "e/g"),
876 mkmap("a", "a2", "b/c", "b/c", "d", "d", "e/f", "e/f", "e/g",
877 "e/g2"),
878 mkmap("a", "a", "b/c", "b/c", "d", "d", "e/f", "e/f", "e/g",
879 "e/g3"));
880 try {
881 checkout();
882 } catch (CheckoutConflictException e) {
883 assertWorkDir(mkmap("a", "a", "b/c", "b/c", "d", "d", "e/f",
884 "e/f", "e/g", "e/g3"));
885 assertConflict("e/g");
886 }
887 }
888
889 @Test
890 public void testCheckoutOutChanges() throws IOException {
891 setupCase(mk("foo"), mk("foo/bar"), mk("foo"));
892 checkout();
893 assertIndex(mk("foo/bar"));
894 assertWorkDir(mk("foo/bar"));
895
896 assertFalse(new File(trash, "foo").isFile());
897 assertTrue(new File(trash, "foo/bar").isFile());
898 recursiveDelete(new File(trash, "foo"));
899
900 assertWorkDir(mkmap());
901
902 setupCase(mk("foo/bar"), mk("foo"), mk("foo/bar"));
903 checkout();
904
905 assertIndex(mk("foo"));
906 assertWorkDir(mk("foo"));
907
908 assertFalse(new File(trash, "foo/bar").isFile());
909 assertTrue(new File(trash, "foo").isFile());
910
911 setupCase(mk("foo"), mkmap("foo", "qux"), mkmap("foo", "bar"));
912
913 assertIndex(mkmap("foo", "bar"));
914 assertWorkDir(mkmap("foo", "bar"));
915
916 try {
917 checkout();
918 fail("did not throw exception");
919 } catch (CheckoutConflictException e) {
920 assertIndex(mkmap("foo", "bar"));
921 assertWorkDir(mkmap("foo", "bar"));
922 }
923 }
924
925 @Test
926 public void testCheckoutOutChangesAutoCRLFfalse() throws IOException {
927 setupCase(mk("foo"), mkmap("foo/bar", "foo\nbar"), mk("foo"));
928 checkout();
929 assertIndex(mkmap("foo/bar", "foo\nbar"));
930 assertWorkDir(mkmap("foo/bar", "foo\nbar"));
931 }
932
933 @Test
934 public void testCheckoutOutChangesAutoCRLFInput() throws IOException {
935 setupCase(mk("foo"), mkmap("foo/bar", "foo\nbar"), mk("foo"));
936 db.getConfig().setString("core", null, "autocrlf", "input");
937 checkout();
938 assertIndex(mkmap("foo/bar", "foo\nbar"));
939 assertWorkDir(mkmap("foo/bar", "foo\nbar"));
940 }
941
942 @Test
943 public void testCheckoutOutChangesAutoCRLFtrue() throws IOException {
944 setupCase(mk("foo"), mkmap("foo/bar", "foo\nbar"), mk("foo"));
945 db.getConfig().setString("core", null, "autocrlf", "true");
946 checkout();
947 assertIndex(mkmap("foo/bar", "foo\nbar"));
948 assertWorkDir(mkmap("foo/bar", "foo\r\nbar"));
949 }
950
951 @Test
952 public void testCheckoutOutChangesAutoCRLFtrueBinary() throws IOException {
953 setupCase(mk("foo"), mkmap("foo/bar", "foo\nb\u0000ar"), mk("foo"));
954 db.getConfig().setString("core", null, "autocrlf", "true");
955 checkout();
956 assertIndex(mkmap("foo/bar", "foo\nb\u0000ar"));
957 assertWorkDir(mkmap("foo/bar", "foo\nb\u0000ar"));
958 }
959
960 @Test
961 public void testCheckoutUncachedChanges() throws IOException {
962 setupCase(mk("foo"), mk("foo"), mk("foo"));
963 writeTrashFile("foo", "otherData");
964 checkout();
965 assertIndex(mk("foo"));
966 assertWorkDir(mkmap("foo", "otherData"));
967 assertTrue(new File(trash, "foo").isFile());
968 }
969
970 @Test
971 public void testDontOverwriteDirtyFile() throws IOException {
972 setupCase(mk("foo"), mk("other"), mk("foo"));
973 writeTrashFile("foo", "different");
974 try {
975 checkout();
976 fail("Didn't got the expected conflict");
977 } catch (CheckoutConflictException e) {
978 assertIndex(mk("foo"));
979 assertWorkDir(mkmap("foo", "different"));
980 assertEquals(Arrays.asList("foo"), getConflicts());
981 assertTrue(new File(trash, "foo").isFile());
982 }
983 }
984
985 @Test
986 public void testOverwriteUntrackedIgnoredFile() throws IOException,
987 GitAPIException {
988 String fname="file.txt";
989 Git git = Git.wrap(db);
990
991
992 writeTrashFile(fname, "a");
993 git.add().addFilepattern(fname).call();
994 git.commit().setMessage("create file").call();
995
996
997 git.branchCreate().setName("side").call();
998
999
1000 writeTrashFile(fname, "b");
1001 git.add().addFilepattern(fname).call();
1002 git.commit().setMessage("modify file").call();
1003
1004
1005 git.checkout().setName("side").call();
1006 git.rm().addFilepattern(fname).call();
1007 writeTrashFile(".gitignore", fname);
1008 git.add().addFilepattern(".gitignore").call();
1009 git.commit().setMessage("delete and ignore file").call();
1010
1011 writeTrashFile(fname, "Something different");
1012 git.checkout().setName("master").call();
1013 assertWorkDir(mkmap(fname, "b"));
1014 assertTrue(git.status().call().isClean());
1015 }
1016
1017 @Test
1018 public void testFileModeChangeWithNoContentChangeUpdate() throws Exception {
1019 if (!FS.DETECTED.supportsExecute())
1020 return;
1021
1022 Git git = Git.wrap(db);
1023
1024
1025 File file = writeTrashFile("file.txt", "a");
1026 git.add().addFilepattern("file.txt").call();
1027 git.commit().setMessage("commit1").call();
1028 assertFalse(db.getFS().canExecute(file));
1029
1030
1031 git.branchCreate().setName("b1").call();
1032
1033
1034 db.getFS().setExecute(file, true);
1035 git.add().addFilepattern("file.txt").call();
1036 git.commit().setMessage("commit2").call();
1037
1038
1039 Status status = git.status().call();
1040 assertTrue(status.getModified().isEmpty());
1041 assertTrue(status.getChanged().isEmpty());
1042 assertTrue(db.getFS().canExecute(file));
1043
1044
1045 git.checkout().setName("b1").call();
1046
1047
1048 status = git.status().call();
1049 assertTrue(status.getModified().isEmpty());
1050 assertTrue(status.getChanged().isEmpty());
1051 assertFalse(db.getFS().canExecute(file));
1052 }
1053
1054 @Test
1055 public void testFileModeChangeAndContentChangeConflict() throws Exception {
1056 if (!FS.DETECTED.supportsExecute())
1057 return;
1058
1059 Git git = Git.wrap(db);
1060
1061
1062 File file = writeTrashFile("file.txt", "a");
1063 git.add().addFilepattern("file.txt").call();
1064 git.commit().setMessage("commit1").call();
1065 assertFalse(db.getFS().canExecute(file));
1066
1067
1068 git.branchCreate().setName("b1").call();
1069
1070
1071 db.getFS().setExecute(file, true);
1072 git.add().addFilepattern("file.txt").call();
1073 git.commit().setMessage("commit2").call();
1074
1075
1076 Status status = git.status().call();
1077 assertTrue(status.getModified().isEmpty());
1078 assertTrue(status.getChanged().isEmpty());
1079 assertTrue(db.getFS().canExecute(file));
1080
1081 writeTrashFile("file.txt", "b");
1082
1083
1084 CheckoutCommand checkout = git.checkout().setName("b1");
1085 try {
1086 checkout.call();
1087 fail("Checkout exception not thrown");
1088 } catch (org.eclipse.jgit.api.errors.CheckoutConflictException e) {
1089 CheckoutResult result = checkout.getResult();
1090 assertNotNull(result);
1091 assertNotNull(result.getConflictList());
1092 assertEquals(1, result.getConflictList().size());
1093 assertTrue(result.getConflictList().contains("file.txt"));
1094 }
1095 }
1096
1097 @Test
1098 public void testDirtyFileModeEqualHeadMerge()
1099 throws Exception {
1100 if (!FS.DETECTED.supportsExecute())
1101 return;
1102
1103 Git git = Git.wrap(db);
1104
1105
1106 File file = writeTrashFile("file.txt", "a");
1107 git.add().addFilepattern("file.txt").call();
1108 git.commit().setMessage("commit1").call();
1109 assertFalse(db.getFS().canExecute(file));
1110
1111
1112 git.branchCreate().setName("b1").call();
1113
1114
1115 writeTrashFile("file2.txt", "");
1116 git.add().addFilepattern("file2.txt").call();
1117 git.commit().setMessage("commit2").call();
1118
1119
1120 writeTrashFile("file.txt", "a");
1121 db.getFS().setExecute(file, true);
1122 git.add().addFilepattern("file.txt").call();
1123
1124
1125 writeTrashFile("file.txt", "b");
1126
1127 assertEquals(
1128 "[file.txt, mode:100755, content:a][file2.txt, mode:100644, content:]",
1129 indexState(CONTENT));
1130 assertWorkDir(mkmap("file.txt", "b", "file2.txt", ""));
1131
1132
1133
1134 git.checkout().setName("b1").call();
1135 assertEquals("[file.txt, mode:100755, content:a]", indexState(CONTENT));
1136 assertWorkDir(mkmap("file.txt", "b"));
1137 }
1138
1139 @Test
1140 public void testDirtyFileModeEqualIndexMerge()
1141 throws Exception {
1142 if (!FS.DETECTED.supportsExecute())
1143 return;
1144
1145 Git git = Git.wrap(db);
1146
1147
1148 File file = writeTrashFile("file.txt", "a");
1149 git.add().addFilepattern("file.txt").call();
1150 git.commit().setMessage("commit1").call();
1151 assertFalse(db.getFS().canExecute(file));
1152
1153
1154 git.branchCreate().setName("b1").call();
1155
1156
1157 file = writeTrashFile("file.txt", "b");
1158 db.getFS().setExecute(file, true);
1159 git.add().addFilepattern("file.txt").call();
1160 git.commit().setMessage("commit2").call();
1161
1162
1163 writeTrashFile("file.txt", "a");
1164 db.getFS().setExecute(file, false);
1165 git.add().addFilepattern("file.txt").call();
1166
1167
1168 writeTrashFile("file.txt", "c");
1169 db.getFS().setExecute(file, true);
1170
1171 assertEquals("[file.txt, mode:100644, content:a]", indexState(CONTENT));
1172 assertWorkDir(mkmap("file.txt", "c"));
1173
1174
1175
1176 git.checkout().setName("b1").call();
1177 assertEquals("[file.txt, mode:100644, content:a]", indexState(CONTENT));
1178 assertWorkDir(mkmap("file.txt", "c"));
1179 }
1180
1181 @Test
1182 public void testFileModeChangeAndContentChangeNoConflict() throws Exception {
1183 if (!FS.DETECTED.supportsExecute())
1184 return;
1185
1186 Git git = Git.wrap(db);
1187
1188
1189 File file1 = writeTrashFile("file1.txt", "a");
1190 git.add().addFilepattern("file1.txt").call();
1191 git.commit().setMessage("commit1").call();
1192 assertFalse(db.getFS().canExecute(file1));
1193
1194
1195 File file2 = writeTrashFile("file2.txt", "b");
1196 git.add().addFilepattern("file2.txt").call();
1197 git.commit().setMessage("commit2").call();
1198 assertFalse(db.getFS().canExecute(file2));
1199
1200
1201 assertNotNull(git.checkout().setCreateBranch(true).setName("b1")
1202 .setStartPoint(Constants.HEAD + "~1").call());
1203
1204
1205 file1 = writeTrashFile("file1.txt", "c");
1206 db.getFS().setExecute(file1, true);
1207 git.add().addFilepattern("file1.txt").call();
1208
1209
1210 assertNotNull(git.checkout().setName(Constants.MASTER).call());
1211 }
1212
1213 public void assertWorkDir(HashMap<String, String> i) throws CorruptObjectException,
1214 IOException {
1215 TreeWalk walk = new TreeWalk(db);
1216 walk.setRecursive(true);
1217 walk.addTree(new FileTreeIterator(db));
1218 String expectedValue;
1219 String path;
1220 int nrFiles = 0;
1221 FileTreeIterator ft;
1222 while (walk.next()) {
1223 ft = walk.getTree(0, FileTreeIterator.class);
1224 path = ft.getEntryPathString();
1225 expectedValue = i.get(path);
1226 assertNotNull("found unexpected file for path " + path
1227 + " in workdir", expectedValue);
1228 File file = new File(db.getWorkTree(), path);
1229 assertTrue(file.exists());
1230 if (file.isFile()) {
1231 FileInputStream is = new FileInputStream(file);
1232 byte[] buffer = new byte[(int) file.length()];
1233 int offset = 0;
1234 int numRead = 0;
1235 while (offset < buffer.length
1236 && (numRead = is.read(buffer, offset, buffer.length
1237 - offset)) >= 0) {
1238 offset += numRead;
1239 }
1240 is.close();
1241 assertArrayEquals("unexpected content for path " + path
1242 + " in workDir. ", buffer, i.get(path).getBytes());
1243 nrFiles++;
1244 }
1245 }
1246 assertEquals("WorkDir has not the right size.", i.size(), nrFiles);
1247 }
1248 }