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