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
42
43 package org.eclipse.jgit.merge;
44
45 import static org.junit.Assert.assertEquals;
46 import static org.junit.Assert.assertTrue;
47
48 import java.io.File;
49 import java.io.FileInputStream;
50 import java.io.IOException;
51
52 import org.eclipse.jgit.api.Git;
53 import org.eclipse.jgit.api.MergeResult;
54 import org.eclipse.jgit.api.MergeResult.MergeStatus;
55 import org.eclipse.jgit.api.errors.CheckoutConflictException;
56 import org.eclipse.jgit.api.errors.GitAPIException;
57 import org.eclipse.jgit.api.errors.JGitInternalException;
58 import org.eclipse.jgit.dircache.DirCache;
59 import org.eclipse.jgit.errors.NoMergeBaseException;
60 import org.eclipse.jgit.errors.NoMergeBaseException.MergeBaseFailureReason;
61 import org.eclipse.jgit.junit.RepositoryTestCase;
62 import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason;
63 import org.eclipse.jgit.revwalk.RevCommit;
64 import org.eclipse.jgit.treewalk.FileTreeIterator;
65 import org.eclipse.jgit.util.FS;
66 import org.eclipse.jgit.util.FileUtils;
67 import org.junit.Assert;
68 import org.junit.experimental.theories.DataPoint;
69 import org.junit.experimental.theories.Theories;
70 import org.junit.experimental.theories.Theory;
71 import org.junit.runner.RunWith;
72
73 @RunWith(Theories.class)
74 public class ResolveMergerTest extends RepositoryTestCase {
75
76 @DataPoint
77 public static MergeStrategy resolve = MergeStrategy.RESOLVE;
78
79 @DataPoint
80 public static MergeStrategy recursive = MergeStrategy.RECURSIVE;
81
82 @Theory
83 public void failingDeleteOfDirectoryWithUntrackedContent(
84 MergeStrategy strategy) throws Exception {
85 File folder1 = new File(db.getWorkTree(), "folder1");
86 FileUtils.mkdir(folder1);
87 File file = new File(folder1, "file1.txt");
88 write(file, "folder1--file1.txt");
89 file = new File(folder1, "file2.txt");
90 write(file, "folder1--file2.txt");
91
92 try (Git git = new Git(db)) {
93 git.add().addFilepattern(folder1.getName()).call();
94 RevCommit base = git.commit().setMessage("adding folder").call();
95
96 recursiveDelete(folder1);
97 git.rm().addFilepattern("folder1/file1.txt")
98 .addFilepattern("folder1/file2.txt").call();
99 RevCommit other = git.commit()
100 .setMessage("removing folders on 'other'").call();
101
102 git.checkout().setName(base.name()).call();
103
104 file = new File(db.getWorkTree(), "unrelated.txt");
105 write(file, "unrelated");
106
107 git.add().addFilepattern("unrelated.txt").call();
108 RevCommit head = git.commit().setMessage("Adding another file").call();
109
110
111
112 file = new File(folder1, "file3.txt");
113 write(file, "folder1--file3.txt");
114
115 ResolveMerger merger = (ResolveMerger) strategy.newMerger(db, false);
116 merger.setCommitNames(new String[] { "BASE", "HEAD", "other" });
117 merger.setWorkingTreeIterator(new FileTreeIterator(db));
118 boolean ok = merger.merge(head.getId(), other.getId());
119 assertTrue(ok);
120 assertTrue(file.exists());
121 }
122 }
123
124
125
126
127
128
129
130
131 @Theory
132 public void checkMergeConflictingTreesWithoutIndex(MergeStrategy strategy)
133 throws Exception {
134 Git git = Git.wrap(db);
135
136 writeTrashFile("d/1", "orig");
137 git.add().addFilepattern("d/1").call();
138 RevCommit first = git.commit().setMessage("added d/1").call();
139
140 writeTrashFile("d/1", "master");
141 RevCommit masterCommit = git.commit().setAll(true)
142 .setMessage("modified d/1 on master").call();
143
144 git.checkout().setCreateBranch(true).setStartPoint(first)
145 .setName("side").call();
146 writeTrashFile("d/1", "side");
147 git.commit().setAll(true).setMessage("modified d/1 on side").call();
148
149 git.rm().addFilepattern("d/1").call();
150 git.rm().addFilepattern("d").call();
151 MergeResult mergeRes = git.merge().setStrategy(strategy)
152 .include(masterCommit).call();
153 assertEquals(MergeStatus.CONFLICTING, mergeRes.getMergeStatus());
154 assertEquals(
155 "[d/1, mode:100644, stage:1, content:orig][d/1, mode:100644, stage:2, content:side][d/1, mode:100644, stage:3, content:master]",
156 indexState(CONTENT));
157 }
158
159
160
161
162
163
164
165
166 @Theory
167 public void checkMergeMergeableTreesWithoutIndex(MergeStrategy strategy)
168 throws Exception {
169 Git git = Git.wrap(db);
170
171 writeTrashFile("d/1", "1\n2\n3");
172 git.add().addFilepattern("d/1").call();
173 RevCommit first = git.commit().setMessage("added d/1").call();
174
175 writeTrashFile("d/1", "1master\n2\n3");
176 RevCommit masterCommit = git.commit().setAll(true)
177 .setMessage("modified d/1 on master").call();
178
179 git.checkout().setCreateBranch(true).setStartPoint(first)
180 .setName("side").call();
181 writeTrashFile("d/1", "1\n2\n3side");
182 git.commit().setAll(true).setMessage("modified d/1 on side").call();
183
184 git.rm().addFilepattern("d/1").call();
185 git.rm().addFilepattern("d").call();
186 MergeResult mergeRes = git.merge().setStrategy(strategy)
187 .include(masterCommit).call();
188 assertEquals(MergeStatus.MERGED, mergeRes.getMergeStatus());
189 assertEquals("[d/1, mode:100644, content:1master\n2\n3side]",
190 indexState(CONTENT));
191 }
192
193
194
195
196
197
198
199
200 @Theory
201 public void checkUntrackedFolderIsNotAConflict(
202 MergeStrategy strategy) throws Exception {
203 Git git = Git.wrap(db);
204
205 writeTrashFile("d/1", "1");
206 git.add().addFilepattern("d/1").call();
207 RevCommit first = git.commit().setMessage("added d/1").call();
208
209 writeTrashFile("e/1", "4");
210 git.add().addFilepattern("e/1").call();
211 RevCommit masterCommit = git.commit().setMessage("added e/1").call();
212
213 git.checkout().setCreateBranch(true).setStartPoint(first)
214 .setName("side").call();
215 writeTrashFile("f/1", "5");
216 git.add().addFilepattern("f/1").call();
217 git.commit().setAll(true).setMessage("added f/1")
218 .call();
219
220
221 writeTrashFile("e/2", "d two");
222
223 MergeResult mergeRes = git.merge().setStrategy(strategy)
224 .include(masterCommit).call();
225 assertEquals(MergeStatus.MERGED, mergeRes.getMergeStatus());
226 assertEquals(
227 "[d/1, mode:100644, content:1][e/1, mode:100644, content:4][f/1, mode:100644, content:5]",
228 indexState(CONTENT));
229 }
230
231
232
233
234
235
236
237 @Theory
238 public void checkFileReplacedByFolderInTheirs(MergeStrategy strategy)
239 throws Exception {
240 Git git = Git.wrap(db);
241
242 writeTrashFile("sub", "file");
243 git.add().addFilepattern("sub").call();
244 RevCommit first = git.commit().setMessage("initial").call();
245
246 git.checkout().setCreateBranch(true).setStartPoint(first)
247 .setName("side").call();
248
249 git.rm().addFilepattern("sub").call();
250 writeTrashFile("sub/file", "subfile");
251 git.add().addFilepattern("sub/file").call();
252 RevCommit masterCommit = git.commit().setMessage("file -> folder")
253 .call();
254
255 git.checkout().setName("master").call();
256 writeTrashFile("noop", "other");
257 git.add().addFilepattern("noop").call();
258 git.commit().setAll(true).setMessage("noop").call();
259
260 MergeResult mergeRes = git.merge().setStrategy(strategy)
261 .include(masterCommit).call();
262 assertEquals(MergeStatus.MERGED, mergeRes.getMergeStatus());
263 assertEquals(
264 "[noop, mode:100644, content:other][sub/file, mode:100644, content:subfile]",
265 indexState(CONTENT));
266 }
267
268
269
270
271
272
273
274 @Theory
275 public void checkFileReplacedByFolderInOurs(MergeStrategy strategy)
276 throws Exception {
277 Git git = Git.wrap(db);
278
279 writeTrashFile("sub", "file");
280 git.add().addFilepattern("sub").call();
281 RevCommit first = git.commit().setMessage("initial").call();
282
283 git.checkout().setCreateBranch(true).setStartPoint(first)
284 .setName("side").call();
285 writeTrashFile("noop", "other");
286 git.add().addFilepattern("noop").call();
287 RevCommit sideCommit = git.commit().setAll(true).setMessage("noop")
288 .call();
289
290 git.checkout().setName("master").call();
291 git.rm().addFilepattern("sub").call();
292 writeTrashFile("sub/file", "subfile");
293 git.add().addFilepattern("sub/file").call();
294 git.commit().setMessage("file -> folder")
295 .call();
296
297 MergeResult mergeRes = git.merge().setStrategy(strategy)
298 .include(sideCommit).call();
299 assertEquals(MergeStatus.MERGED, mergeRes.getMergeStatus());
300 assertEquals(
301 "[noop, mode:100644, content:other][sub/file, mode:100644, content:subfile]",
302 indexState(CONTENT));
303 }
304
305
306
307
308
309
310
311
312 @Theory
313 public void checkUntrackedEmpytFolderIsNotAConflictWithFile(
314 MergeStrategy strategy)
315 throws Exception {
316 Git git = Git.wrap(db);
317
318 writeTrashFile("d/1", "1");
319 git.add().addFilepattern("d/1").call();
320 RevCommit first = git.commit().setMessage("added d/1").call();
321
322 writeTrashFile("e", "4");
323 git.add().addFilepattern("e").call();
324 RevCommit masterCommit = git.commit().setMessage("added e").call();
325
326 git.checkout().setCreateBranch(true).setStartPoint(first)
327 .setName("side").call();
328 writeTrashFile("f/1", "5");
329 git.add().addFilepattern("f/1").call();
330 git.commit().setAll(true).setMessage("added f/1").call();
331
332
333
334 FileUtils.mkdirs(new File(trash, "e/1"), true);
335
336 MergeResult mergeRes = git.merge().setStrategy(strategy)
337 .include(masterCommit).call();
338 assertEquals(MergeStatus.MERGED, mergeRes.getMergeStatus());
339 assertEquals(
340 "[d/1, mode:100644, content:1][e, mode:100644, content:4][f/1, mode:100644, content:5]",
341 indexState(CONTENT));
342 }
343
344 @Theory
345 public void mergeWithCrlfInWT(MergeStrategy strategy) throws IOException,
346 GitAPIException {
347 Git git = Git.wrap(db);
348 db.getConfig().setString("core", null, "autocrlf", "false");
349 db.getConfig().save();
350 writeTrashFile("crlf.txt", "some\r\ndata\r\n");
351 git.add().addFilepattern("crlf.txt").call();
352 git.commit().setMessage("base").call();
353
354 git.branchCreate().setName("brancha").call();
355
356 writeTrashFile("crlf.txt", "some\r\nmore\r\ndata\r\n");
357 git.add().addFilepattern("crlf.txt").call();
358 git.commit().setMessage("on master").call();
359
360 git.checkout().setName("brancha").call();
361 writeTrashFile("crlf.txt", "some\r\ndata\r\ntoo\r\n");
362 git.add().addFilepattern("crlf.txt").call();
363 git.commit().setMessage("on brancha").call();
364
365 db.getConfig().setString("core", null, "autocrlf", "input");
366 db.getConfig().save();
367
368 MergeResult mergeResult = git.merge().setStrategy(strategy)
369 .include(db.resolve("master"))
370 .call();
371 assertEquals(MergeResult.MergeStatus.MERGED,
372 mergeResult.getMergeStatus());
373 }
374
375
376
377
378
379
380
381
382 @Theory
383 public void checkMergeEqualTreesWithoutIndex(MergeStrategy strategy)
384 throws Exception {
385 Git git = Git.wrap(db);
386
387 writeTrashFile("d/1", "orig");
388 git.add().addFilepattern("d/1").call();
389 RevCommit first = git.commit().setMessage("added d/1").call();
390
391 writeTrashFile("d/1", "modified");
392 RevCommit masterCommit = git.commit().setAll(true)
393 .setMessage("modified d/1 on master").call();
394
395 git.checkout().setCreateBranch(true).setStartPoint(first)
396 .setName("side").call();
397 writeTrashFile("d/1", "modified");
398 git.commit().setAll(true).setMessage("modified d/1 on side").call();
399
400 git.rm().addFilepattern("d/1").call();
401 git.rm().addFilepattern("d").call();
402 MergeResult mergeRes = git.merge().setStrategy(strategy)
403 .include(masterCommit).call();
404 assertEquals(MergeStatus.MERGED, mergeRes.getMergeStatus());
405 assertEquals("[d/1, mode:100644, content:modified]",
406 indexState(CONTENT));
407 }
408
409
410
411
412
413
414
415
416 @Theory
417 public void checkMergeEqualTreesInCore(MergeStrategy strategy)
418 throws Exception {
419 Git git = Git.wrap(db);
420
421 writeTrashFile("d/1", "orig");
422 git.add().addFilepattern("d/1").call();
423 RevCommit first = git.commit().setMessage("added d/1").call();
424
425 writeTrashFile("d/1", "modified");
426 RevCommit masterCommit = git.commit().setAll(true)
427 .setMessage("modified d/1 on master").call();
428
429 git.checkout().setCreateBranch(true).setStartPoint(first)
430 .setName("side").call();
431 writeTrashFile("d/1", "modified");
432 RevCommit sideCommit = git.commit().setAll(true)
433 .setMessage("modified d/1 on side").call();
434
435 git.rm().addFilepattern("d/1").call();
436 git.rm().addFilepattern("d").call();
437
438 ThreeWayMerger resolveMerger = (ThreeWayMerger) strategy.newMerger(db,
439 true);
440 boolean noProblems = resolveMerger.merge(masterCommit, sideCommit);
441 assertTrue(noProblems);
442 }
443
444
445
446
447
448
449
450
451 @Theory
452 public void checkMergeEqualNewTrees(MergeStrategy strategy)
453 throws Exception {
454 Git git = Git.wrap(db);
455
456 writeTrashFile("2", "orig");
457 git.add().addFilepattern("2").call();
458 RevCommit first = git.commit().setMessage("added 2").call();
459
460 writeTrashFile("d/1", "orig");
461 git.add().addFilepattern("d/1").call();
462 RevCommit masterCommit = git.commit().setAll(true)
463 .setMessage("added d/1 on master").call();
464
465 git.checkout().setCreateBranch(true).setStartPoint(first)
466 .setName("side").call();
467 writeTrashFile("d/1", "orig");
468 git.add().addFilepattern("d/1").call();
469 git.commit().setAll(true).setMessage("added d/1 on side").call();
470
471 git.rm().addFilepattern("d/1").call();
472 git.rm().addFilepattern("d").call();
473 MergeResult mergeRes = git.merge().setStrategy(strategy)
474 .include(masterCommit).call();
475 assertEquals(MergeStatus.MERGED, mergeRes.getMergeStatus());
476 assertEquals(
477 "[2, mode:100644, content:orig][d/1, mode:100644, content:orig]",
478 indexState(CONTENT));
479 }
480
481
482
483
484
485
486
487
488 @Theory
489 public void checkMergeConflictingNewTrees(MergeStrategy strategy)
490 throws Exception {
491 Git git = Git.wrap(db);
492
493 writeTrashFile("2", "orig");
494 git.add().addFilepattern("2").call();
495 RevCommit first = git.commit().setMessage("added 2").call();
496
497 writeTrashFile("d/1", "master");
498 git.add().addFilepattern("d/1").call();
499 RevCommit masterCommit = git.commit().setAll(true)
500 .setMessage("added d/1 on master").call();
501
502 git.checkout().setCreateBranch(true).setStartPoint(first)
503 .setName("side").call();
504 writeTrashFile("d/1", "side");
505 git.add().addFilepattern("d/1").call();
506 git.commit().setAll(true).setMessage("added d/1 on side").call();
507
508 git.rm().addFilepattern("d/1").call();
509 git.rm().addFilepattern("d").call();
510 MergeResult mergeRes = git.merge().setStrategy(strategy)
511 .include(masterCommit).call();
512 assertEquals(MergeStatus.CONFLICTING, mergeRes.getMergeStatus());
513 assertEquals(
514 "[2, mode:100644, content:orig][d/1, mode:100644, stage:2, content:side][d/1, mode:100644, stage:3, content:master]",
515 indexState(CONTENT));
516 }
517
518
519
520
521
522
523
524
525 @Theory
526 public void checkMergeConflictingFilesWithTreeInIndex(MergeStrategy strategy)
527 throws Exception {
528 Git git = Git.wrap(db);
529
530 writeTrashFile("0", "orig");
531 git.add().addFilepattern("0").call();
532 RevCommit first = git.commit().setMessage("added 0").call();
533
534 writeTrashFile("0", "master");
535 RevCommit masterCommit = git.commit().setAll(true)
536 .setMessage("modified 0 on master").call();
537
538 git.checkout().setCreateBranch(true).setStartPoint(first)
539 .setName("side").call();
540 writeTrashFile("0", "side");
541 git.commit().setAll(true).setMessage("modified 0 on side").call();
542
543 git.rm().addFilepattern("0").call();
544 writeTrashFile("0/0", "side");
545 git.add().addFilepattern("0/0").call();
546 MergeResult mergeRes = git.merge().setStrategy(strategy)
547 .include(masterCommit).call();
548 assertEquals(MergeStatus.FAILED, mergeRes.getMergeStatus());
549 }
550
551
552
553
554
555
556
557
558 @Theory
559 public void checkMergeMergeableFilesWithTreeInIndex(MergeStrategy strategy)
560 throws Exception {
561 Git git = Git.wrap(db);
562
563 writeTrashFile("0", "orig");
564 writeTrashFile("1", "1\n2\n3");
565 git.add().addFilepattern("0").addFilepattern("1").call();
566 RevCommit first = git.commit().setMessage("added 0, 1").call();
567
568 writeTrashFile("1", "1master\n2\n3");
569 RevCommit masterCommit = git.commit().setAll(true)
570 .setMessage("modified 1 on master").call();
571
572 git.checkout().setCreateBranch(true).setStartPoint(first)
573 .setName("side").call();
574 writeTrashFile("1", "1\n2\n3side");
575 git.commit().setAll(true).setMessage("modified 1 on side").call();
576
577 git.rm().addFilepattern("0").call();
578 writeTrashFile("0/0", "modified");
579 git.add().addFilepattern("0/0").call();
580 try {
581 git.merge().setStrategy(strategy).include(masterCommit).call();
582 Assert.fail("Didn't get the expected exception");
583 } catch (CheckoutConflictException e) {
584 assertEquals(1, e.getConflictingPaths().size());
585 assertEquals("0/0", e.getConflictingPaths().get(0));
586 }
587 }
588
589
590
591
592
593
594
595
596 @Theory
597 public void checkMergeCrissCross(MergeStrategy strategy) throws Exception {
598 Git git = Git.wrap(db);
599
600 writeTrashFile("1", "1\n2\n3");
601 git.add().addFilepattern("1").call();
602 RevCommit first = git.commit().setMessage("added 1").call();
603
604 writeTrashFile("1", "1master\n2\n3");
605 RevCommit masterCommit = git.commit().setAll(true)
606 .setMessage("modified 1 on master").call();
607
608 writeTrashFile("1", "1master2\n2\n3");
609 git.commit().setAll(true)
610 .setMessage("modified 1 on master again").call();
611
612 git.checkout().setCreateBranch(true).setStartPoint(first)
613 .setName("side").call();
614 writeTrashFile("1", "1\n2\na\nb\nc\n3side");
615 RevCommit sideCommit = git.commit().setAll(true)
616 .setMessage("modified 1 on side").call();
617
618 writeTrashFile("1", "1\n2\n3side2");
619 git.commit().setAll(true)
620 .setMessage("modified 1 on side again").call();
621
622 MergeResult result = git.merge().setStrategy(strategy)
623 .include(masterCommit).call();
624 assertEquals(MergeStatus.MERGED, result.getMergeStatus());
625 result.getNewHead();
626 git.checkout().setName("master").call();
627 result = git.merge().setStrategy(strategy).include(sideCommit).call();
628 assertEquals(MergeStatus.MERGED, result.getMergeStatus());
629
630
631
632
633 try {
634 MergeResult mergeResult = git.merge().setStrategy(strategy)
635 .include(git.getRepository().exactRef("refs/heads/side"))
636 .call();
637 assertEquals(MergeStrategy.RECURSIVE, strategy);
638 assertEquals(MergeResult.MergeStatus.MERGED,
639 mergeResult.getMergeStatus());
640 assertEquals("1master2\n2\n3side2", read("1"));
641 } catch (JGitInternalException e) {
642 assertEquals(MergeStrategy.RESOLVE, strategy);
643 assertTrue(e.getCause() instanceof NoMergeBaseException);
644 assertEquals(((NoMergeBaseException) e.getCause()).getReason(),
645 MergeBaseFailureReason.MULTIPLE_MERGE_BASES_NOT_SUPPORTED);
646 }
647 }
648
649 @Theory
650 public void checkLockedFilesToBeDeleted(MergeStrategy strategy)
651 throws Exception {
652 Git git = Git.wrap(db);
653
654 writeTrashFile("a.txt", "orig");
655 writeTrashFile("b.txt", "orig");
656 git.add().addFilepattern("a.txt").addFilepattern("b.txt").call();
657 RevCommit first = git.commit().setMessage("added a.txt, b.txt").call();
658
659
660 writeTrashFile("a.txt", "master");
661 git.rm().addFilepattern("b.txt").call();
662 RevCommit masterCommit = git.commit()
663 .setMessage("modified a.txt, deleted b.txt").setAll(true)
664 .call();
665
666
667 git.checkout().setCreateBranch(true).setStartPoint(first)
668 .setName("side").call();
669 writeTrashFile("c.txt", "side");
670 git.add().addFilepattern("c.txt").call();
671 git.commit().setMessage("added c.txt").call();
672
673
674 FileInputStream fis = new FileInputStream(new File(db.getWorkTree(),
675 "b.txt"));
676 MergeResult mergeRes = git.merge().setStrategy(strategy)
677 .include(masterCommit).call();
678 if (mergeRes.getMergeStatus().equals(MergeStatus.FAILED)) {
679
680 assertEquals(1, mergeRes.getFailingPaths().size());
681 assertEquals(MergeFailureReason.COULD_NOT_DELETE, mergeRes
682 .getFailingPaths().get("b.txt"));
683 }
684 assertEquals("[a.txt, mode:100644, content:master]"
685 + "[c.txt, mode:100644, content:side]", indexState(CONTENT));
686 fis.close();
687 }
688
689 @Theory
690 public void checkForCorrectIndex(MergeStrategy strategy) throws Exception {
691 File f;
692 long lastTs4, lastTsIndex;
693 Git git = Git.wrap(db);
694 File indexFile = db.getIndexFile();
695
696
697 f = writeTrashFiles(false, "orig", "orig", "1\n2\n3", "orig", "orig");
698 lastTs4 = FS.DETECTED.lastModified(f);
699
700
701
702
703
704 fsTick(f);
705 git.add().addFilepattern(".").call();
706 RevCommit firstCommit = git.commit().setMessage("initial commit")
707 .call();
708 checkConsistentLastModified("0", "1", "2", "3", "4");
709 checkModificationTimeStampOrder("1", "2", "3", "4", "<.git/index");
710 assertEquals("Commit should not touch working tree file 4", lastTs4,
711 FS.DETECTED.lastModified(new File(db.getWorkTree(), "4")));
712 lastTsIndex = FS.DETECTED.lastModified(indexFile);
713
714
715
716 fsTick(indexFile);
717 f = writeTrashFiles(false, "master", null, "1master\n2\n3", "master",
718 null);
719 fsTick(f);
720 git.add().addFilepattern(".").call();
721 RevCommit masterCommit = git.commit().setMessage("master commit")
722 .call();
723 checkConsistentLastModified("0", "1", "2", "3", "4");
724 checkModificationTimeStampOrder("1", "4", "*" + lastTs4, "<*"
725 + lastTsIndex, "<0", "2", "3", "<.git/index");
726 lastTsIndex = FS.DETECTED.lastModified(indexFile);
727
728
729 fsTick(indexFile);
730 git.checkout().setCreateBranch(true).setStartPoint(firstCommit)
731 .setName("side").call();
732 checkConsistentLastModified("0", "1", "2", "3", "4");
733 checkModificationTimeStampOrder("1", "4", "*" + lastTs4, "<*"
734 + lastTsIndex, "<0", "2", "3", ".git/index");
735 lastTsIndex = FS.DETECTED.lastModified(indexFile);
736
737
738
739
740 assertEquals("[0, mode:100644, content:orig]"
741 + "[1, mode:100644, content:orig]"
742 + "[2, mode:100644, content:1\n2\n3]"
743 + "[3, mode:100644, content:orig]"
744 + "[4, mode:100644, content:orig]",
745 indexState(CONTENT));
746 fsTick(indexFile);
747 f = writeTrashFiles(false, "orig", "orig", "1\n2\n3", "orig", "orig");
748 lastTs4 = FS.DETECTED.lastModified(f);
749 fsTick(f);
750 git.add().addFilepattern(".").call();
751 checkConsistentLastModified("0", "1", "2", "3", "4");
752 checkModificationTimeStampOrder("*" + lastTsIndex, "<0", "1", "2", "3",
753 "4", "<.git/index");
754 lastTsIndex = FS.DETECTED.lastModified(indexFile);
755
756
757 fsTick(indexFile);
758 f = writeTrashFiles(false, null, "side", "1\n2\n3side", "side", null);
759 fsTick(f);
760 git.add().addFilepattern(".").call();
761 git.commit().setMessage("side commit").call();
762 checkConsistentLastModified("0", "1", "2", "3", "4");
763 checkModificationTimeStampOrder("0", "4", "*" + lastTs4, "<*"
764 + lastTsIndex, "<1", "2", "3", "<.git/index");
765 lastTsIndex = FS.DETECTED.lastModified(indexFile);
766
767
768 fsTick(indexFile);
769 git.merge().setStrategy(strategy).include(masterCommit).call();
770 checkConsistentLastModified("0", "1", "2", "4");
771 checkModificationTimeStampOrder("4", "*" + lastTs4, "<1", "<*"
772 + lastTsIndex, "<0", "2", "3", ".git/index");
773 assertEquals(
774 "[0, mode:100644, content:master]"
775 + "[1, mode:100644, content:side]"
776 + "[2, mode:100644, content:1master\n2\n3side]"
777 + "[3, mode:100644, stage:1, content:orig][3, mode:100644, stage:2, content:side][3, mode:100644, stage:3, content:master]"
778 + "[4, mode:100644, content:orig]",
779 indexState(CONTENT));
780 }
781
782
783
784 private void checkConsistentLastModified(String... pathes)
785 throws IOException {
786 DirCache dc = db.readDirCache();
787 File workTree = db.getWorkTree();
788 for (String path : pathes)
789 assertEquals(
790 "IndexEntry with path "
791 + path
792 + " has lastmodified with is different from the worktree file",
793 FS.DETECTED.lastModified(new File(workTree, path)), dc.getEntry(path)
794 .getLastModified());
795 }
796
797
798
799
800
801
802
803 private void checkModificationTimeStampOrder(String... pathes)
804 throws IOException {
805 long lastMod = Long.MIN_VALUE;
806 for (String p : pathes) {
807 boolean strong = p.startsWith("<");
808 boolean fixed = p.charAt(strong ? 1 : 0) == '*';
809 p = p.substring((strong ? 1 : 0) + (fixed ? 1 : 0));
810 long curMod = fixed ? Long.valueOf(p).longValue()
811 : FS.DETECTED.lastModified(new File(db.getWorkTree(), p));
812 if (strong)
813 assertTrue("path " + p + " is not younger than predecesssor",
814 curMod > lastMod);
815 else
816 assertTrue("path " + p + " is older than predecesssor",
817 curMod >= lastMod);
818 }
819 }
820 }