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