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
44 package org.eclipse.jgit.api;
45
46 import static org.eclipse.jgit.lib.Constants.MASTER;
47 import static org.eclipse.jgit.lib.Constants.R_HEADS;
48 import static org.junit.Assert.assertEquals;
49 import static org.junit.Assert.assertFalse;
50 import static org.junit.Assert.assertNull;
51 import static org.junit.Assert.assertTrue;
52 import static org.junit.Assert.fail;
53 import static org.junit.Assume.assumeTrue;
54
55 import java.io.File;
56 import java.util.Iterator;
57
58 import org.eclipse.jgit.api.MergeCommand.FastForwardMode;
59 import org.eclipse.jgit.api.MergeResult.MergeStatus;
60 import org.eclipse.jgit.api.errors.InvalidMergeHeadsException;
61 import org.eclipse.jgit.junit.RepositoryTestCase;
62 import org.eclipse.jgit.junit.TestRepository;
63 import org.eclipse.jgit.junit.TestRepository.BranchBuilder;
64 import org.eclipse.jgit.lib.Constants;
65 import org.eclipse.jgit.lib.Ref;
66 import org.eclipse.jgit.lib.Repository;
67 import org.eclipse.jgit.lib.RepositoryState;
68 import org.eclipse.jgit.lib.Sets;
69 import org.eclipse.jgit.merge.MergeStrategy;
70 import org.eclipse.jgit.merge.ResolveMerger.MergeFailureReason;
71 import org.eclipse.jgit.revwalk.RevCommit;
72 import org.eclipse.jgit.util.FS;
73 import org.eclipse.jgit.util.FileUtils;
74 import org.eclipse.jgit.util.GitDateFormatter;
75 import org.eclipse.jgit.util.GitDateFormatter.Format;
76 import org.junit.Before;
77 import org.junit.Test;
78 import org.junit.experimental.theories.DataPoints;
79 import org.junit.experimental.theories.Theories;
80 import org.junit.experimental.theories.Theory;
81 import org.junit.runner.RunWith;
82
83 @RunWith(Theories.class)
84 public class MergeCommandTest extends RepositoryTestCase {
85
86 public static @DataPoints
87 MergeStrategy[] mergeStrategies = MergeStrategy.get();
88
89 private GitDateFormatter dateFormatter;
90
91 @Override
92 @Before
93 public void setUp() throws Exception {
94 super.setUp();
95 dateFormatter = new GitDateFormatter(Format.DEFAULT);
96 }
97
98 @Test
99 public void testMergeInItself() throws Exception {
100 try (Git git = new Git(db)) {
101 git.commit().setMessage("initial commit").call();
102
103 MergeResult result = git.merge().include(db.exactRef(Constants.HEAD)).call();
104 assertEquals(MergeResult.MergeStatus.ALREADY_UP_TO_DATE, result.getMergeStatus());
105 }
106
107 assertEquals("commit (initial): initial commit",
108 db
109 .getReflogReader(Constants.HEAD).getLastEntry().getComment());
110 assertEquals("commit (initial): initial commit",
111 db
112 .getReflogReader(db.getBranch()).getLastEntry().getComment());
113 }
114
115 @Test
116 public void testAlreadyUpToDate() throws Exception {
117 try (Git git = new Git(db)) {
118 RevCommit first = git.commit().setMessage("initial commit").call();
119 createBranch(first, "refs/heads/branch1");
120
121 RevCommit second = git.commit().setMessage("second commit").call();
122 MergeResult result = git.merge().include(db.exactRef("refs/heads/branch1")).call();
123 assertEquals(MergeResult.MergeStatus.ALREADY_UP_TO_DATE, result.getMergeStatus());
124 assertEquals(second, result.getNewHead());
125 }
126
127 assertEquals("commit: second commit", db
128 .getReflogReader(Constants.HEAD).getLastEntry().getComment());
129 assertEquals("commit: second commit", db
130 .getReflogReader(db.getBranch()).getLastEntry().getComment());
131 }
132
133 @Test
134 public void testFastForward() throws Exception {
135 try (Git git = new Git(db)) {
136 RevCommit first = git.commit().setMessage("initial commit").call();
137 createBranch(first, "refs/heads/branch1");
138
139 RevCommit second = git.commit().setMessage("second commit").call();
140
141 checkoutBranch("refs/heads/branch1");
142
143 MergeResult result = git.merge().include(db.exactRef(R_HEADS + MASTER)).call();
144
145 assertEquals(MergeResult.MergeStatus.FAST_FORWARD, result.getMergeStatus());
146 assertEquals(second, result.getNewHead());
147 }
148 assertEquals("merge refs/heads/master: Fast-forward",
149 db.getReflogReader(Constants.HEAD).getLastEntry().getComment());
150 assertEquals("merge refs/heads/master: Fast-forward",
151 db.getReflogReader(db.getBranch()).getLastEntry().getComment());
152 }
153
154 @Test
155 public void testFastForwardNoCommit() throws Exception {
156 try (Git git = new Git(db)) {
157 RevCommit first = git.commit().setMessage("initial commit").call();
158 createBranch(first, "refs/heads/branch1");
159
160 RevCommit second = git.commit().setMessage("second commit").call();
161
162 checkoutBranch("refs/heads/branch1");
163
164 MergeResult result = git.merge().include(db.exactRef(R_HEADS + MASTER))
165 .setCommit(false).call();
166
167 assertEquals(MergeResult.MergeStatus.FAST_FORWARD,
168 result.getMergeStatus());
169 assertEquals(second, result.getNewHead());
170 }
171 assertEquals("merge refs/heads/master: Fast-forward", db
172 .getReflogReader(Constants.HEAD).getLastEntry().getComment());
173 assertEquals("merge refs/heads/master: Fast-forward", db
174 .getReflogReader(db.getBranch()).getLastEntry().getComment());
175 }
176
177 @Test
178 public void testFastForwardWithFiles() throws Exception {
179 try (Git git = new Git(db)) {
180 writeTrashFile("file1", "file1");
181 git.add().addFilepattern("file1").call();
182 RevCommit first = git.commit().setMessage("initial commit").call();
183
184 assertTrue(new File(db.getWorkTree(), "file1").exists());
185 createBranch(first, "refs/heads/branch1");
186
187 writeTrashFile("file2", "file2");
188 git.add().addFilepattern("file2").call();
189 RevCommit second = git.commit().setMessage("second commit").call();
190 assertTrue(new File(db.getWorkTree(), "file2").exists());
191
192 checkoutBranch("refs/heads/branch1");
193 assertFalse(new File(db.getWorkTree(), "file2").exists());
194
195 MergeResult result = git.merge().include(db.exactRef(R_HEADS + MASTER)).call();
196
197 assertTrue(new File(db.getWorkTree(), "file1").exists());
198 assertTrue(new File(db.getWorkTree(), "file2").exists());
199 assertEquals(MergeResult.MergeStatus.FAST_FORWARD, result.getMergeStatus());
200 assertEquals(second, result.getNewHead());
201 }
202 assertEquals("merge refs/heads/master: Fast-forward",
203 db.getReflogReader(Constants.HEAD).getLastEntry().getComment());
204 assertEquals("merge refs/heads/master: Fast-forward",
205 db.getReflogReader(db.getBranch()).getLastEntry().getComment());
206 }
207
208 @Test
209 public void testMultipleHeads() throws Exception {
210 try (Git git = new Git(db)) {
211 writeTrashFile("file1", "file1");
212 git.add().addFilepattern("file1").call();
213 RevCommit first = git.commit().setMessage("initial commit").call();
214 createBranch(first, "refs/heads/branch1");
215
216 writeTrashFile("file2", "file2");
217 git.add().addFilepattern("file2").call();
218 RevCommit second = git.commit().setMessage("second commit").call();
219
220 writeTrashFile("file3", "file3");
221 git.add().addFilepattern("file3").call();
222 git.commit().setMessage("third commit").call();
223
224 checkoutBranch("refs/heads/branch1");
225 assertFalse(new File(db.getWorkTree(), "file2").exists());
226 assertFalse(new File(db.getWorkTree(), "file3").exists());
227
228 MergeCommand merge = git.merge();
229 merge.include(second.getId());
230 merge.include(db.exactRef(R_HEADS + MASTER));
231 try {
232 merge.call();
233 fail("Expected exception not thrown when merging multiple heads");
234 } catch (InvalidMergeHeadsException e) {
235
236 }
237 }
238 }
239
240 @Theory
241 public void testMergeSuccessAllStrategies(MergeStrategy mergeStrategy)
242 throws Exception {
243 try (Git git = new Git(db)) {
244 RevCommit first = git.commit().setMessage("first").call();
245 createBranch(first, "refs/heads/side");
246
247 writeTrashFile("a", "a");
248 git.add().addFilepattern("a").call();
249 git.commit().setMessage("second").call();
250
251 checkoutBranch("refs/heads/side");
252 writeTrashFile("b", "b");
253 git.add().addFilepattern("b").call();
254 git.commit().setMessage("third").call();
255
256 MergeResult result = git.merge().setStrategy(mergeStrategy)
257 .include(db.exactRef(R_HEADS + MASTER)).call();
258 assertEquals(MergeStatus.MERGED, result.getMergeStatus());
259 }
260 assertEquals(
261 "merge refs/heads/master: Merge made by "
262 + mergeStrategy.getName() + ".",
263 db.getReflogReader(Constants.HEAD).getLastEntry().getComment());
264 assertEquals(
265 "merge refs/heads/master: Merge made by "
266 + mergeStrategy.getName() + ".",
267 db.getReflogReader(db.getBranch()).getLastEntry().getComment());
268 }
269
270 @Theory
271 public void testMergeSuccessAllStrategiesNoCommit(
272 MergeStrategy mergeStrategy) throws Exception {
273 try (Git git = new Git(db)) {
274 RevCommit first = git.commit().setMessage("first").call();
275 createBranch(first, "refs/heads/side");
276
277 writeTrashFile("a", "a");
278 git.add().addFilepattern("a").call();
279 git.commit().setMessage("second").call();
280
281 checkoutBranch("refs/heads/side");
282 writeTrashFile("b", "b");
283 git.add().addFilepattern("b").call();
284 RevCommit thirdCommit = git.commit().setMessage("third").call();
285
286 MergeResult result = git.merge().setStrategy(mergeStrategy)
287 .setCommit(false)
288 .include(db.exactRef(R_HEADS + MASTER)).call();
289 assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus());
290 assertEquals(db.exactRef(Constants.HEAD).getTarget().getObjectId(),
291 thirdCommit.getId());
292 }
293 }
294
295 @Test
296 public void testContentMerge() throws Exception {
297 try (Git git = new Git(db)) {
298 writeTrashFile("a", "1\na\n3\n");
299 writeTrashFile("b", "1\nb\n3\n");
300 writeTrashFile("c/c/c", "1\nc\n3\n");
301 git.add().addFilepattern("a").addFilepattern("b")
302 .addFilepattern("c/c/c").call();
303 RevCommit initialCommit = git.commit().setMessage("initial").call();
304
305 createBranch(initialCommit, "refs/heads/side");
306 checkoutBranch("refs/heads/side");
307
308 writeTrashFile("a", "1\na(side)\n3\n");
309 writeTrashFile("b", "1\nb(side)\n3\n");
310 git.add().addFilepattern("a").addFilepattern("b").call();
311 RevCommit secondCommit = git.commit().setMessage("side").call();
312
313 assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
314 checkoutBranch("refs/heads/master");
315 assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
316
317 writeTrashFile("a", "1\na(main)\n3\n");
318 writeTrashFile("c/c/c", "1\nc(main)\n3\n");
319 git.add().addFilepattern("a").addFilepattern("c/c/c").call();
320 git.commit().setMessage("main").call();
321
322 MergeResult result = git.merge().include(secondCommit.getId())
323 .setStrategy(MergeStrategy.RESOLVE).call();
324 assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
325
326 assertEquals(
327 "1\n<<<<<<< HEAD\na(main)\n=======\na(side)\n>>>>>>> 86503e7e397465588cc267b65d778538bffccb83\n3\n",
328 read(new File(db.getWorkTree(), "a")));
329 assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
330 assertEquals("1\nc(main)\n3\n",
331 read(new File(db.getWorkTree(), "c/c/c")));
332
333 assertEquals(1, result.getConflicts().size());
334 assertEquals(3, result.getConflicts().get("a")[0].length);
335
336 assertEquals(RepositoryState.MERGING, db.getRepositoryState());
337 }
338 }
339
340 @Test
341 public void testMergeTag() throws Exception {
342 try (Git git = new Git(db)) {
343 writeTrashFile("a", "a");
344 git.add().addFilepattern("a").call();
345 RevCommit initialCommit = git.commit().setMessage("initial").call();
346
347 createBranch(initialCommit, "refs/heads/side");
348 checkoutBranch("refs/heads/side");
349
350 writeTrashFile("b", "b");
351 git.add().addFilepattern("b").call();
352 RevCommit secondCommit = git.commit().setMessage("side").call();
353 Ref tag = git.tag().setAnnotated(true).setMessage("my tag 01")
354 .setName("tag01").setObjectId(secondCommit).call();
355
356 checkoutBranch("refs/heads/master");
357
358 writeTrashFile("a", "a2");
359 git.add().addFilepattern("a").call();
360 git.commit().setMessage("main").call();
361
362 MergeResult result = git.merge().include(tag).setStrategy(MergeStrategy.RESOLVE).call();
363 assertEquals(MergeStatus.MERGED, result.getMergeStatus());
364 }
365 }
366
367 @Test
368 public void testMergeMessage() throws Exception {
369 try (Git git = new Git(db)) {
370 writeTrashFile("a", "1\na\n3\n");
371 git.add().addFilepattern("a").call();
372 RevCommit initialCommit = git.commit().setMessage("initial").call();
373
374 createBranch(initialCommit, "refs/heads/side");
375 checkoutBranch("refs/heads/side");
376
377 writeTrashFile("a", "1\na(side)\n3\n");
378 git.add().addFilepattern("a").call();
379 git.commit().setMessage("side").call();
380
381 checkoutBranch("refs/heads/master");
382
383 writeTrashFile("a", "1\na(main)\n3\n");
384 git.add().addFilepattern("a").call();
385 git.commit().setMessage("main").call();
386
387 Ref sideBranch = db.exactRef("refs/heads/side");
388
389 git.merge().include(sideBranch)
390 .setStrategy(MergeStrategy.RESOLVE).call();
391
392 assertEquals("Merge branch 'side'\n\nConflicts:\n\ta\n",
393 db.readMergeCommitMsg());
394 }
395
396 }
397
398 @Test
399 public void testMergeNonVersionedPaths() throws Exception {
400 try (Git git = new Git(db)) {
401 writeTrashFile("a", "1\na\n3\n");
402 writeTrashFile("b", "1\nb\n3\n");
403 writeTrashFile("c/c/c", "1\nc\n3\n");
404 git.add().addFilepattern("a").addFilepattern("b")
405 .addFilepattern("c/c/c").call();
406 RevCommit initialCommit = git.commit().setMessage("initial").call();
407
408 createBranch(initialCommit, "refs/heads/side");
409 checkoutBranch("refs/heads/side");
410
411 writeTrashFile("a", "1\na(side)\n3\n");
412 writeTrashFile("b", "1\nb(side)\n3\n");
413 git.add().addFilepattern("a").addFilepattern("b").call();
414 RevCommit secondCommit = git.commit().setMessage("side").call();
415
416 assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
417 checkoutBranch("refs/heads/master");
418 assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
419
420 writeTrashFile("a", "1\na(main)\n3\n");
421 writeTrashFile("c/c/c", "1\nc(main)\n3\n");
422 git.add().addFilepattern("a").addFilepattern("c/c/c").call();
423 git.commit().setMessage("main").call();
424
425 writeTrashFile("d", "1\nd\n3\n");
426 assertTrue(new File(db.getWorkTree(), "e").mkdir());
427
428 MergeResult result = git.merge().include(secondCommit.getId())
429 .setStrategy(MergeStrategy.RESOLVE).call();
430 assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
431
432 assertEquals(
433 "1\n<<<<<<< HEAD\na(main)\n=======\na(side)\n>>>>>>> 86503e7e397465588cc267b65d778538bffccb83\n3\n",
434 read(new File(db.getWorkTree(), "a")));
435 assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
436 assertEquals("1\nc(main)\n3\n",
437 read(new File(db.getWorkTree(), "c/c/c")));
438 assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d")));
439 File dir = new File(db.getWorkTree(), "e");
440 assertTrue(dir.isDirectory());
441
442 assertEquals(1, result.getConflicts().size());
443 assertEquals(3, result.getConflicts().get("a")[0].length);
444
445 assertEquals(RepositoryState.MERGING, db.getRepositoryState());
446 }
447 }
448
449 @Test
450 public void testMultipleCreations() throws Exception {
451 try (Git git = new Git(db)) {
452 writeTrashFile("a", "1\na\n3\n");
453 git.add().addFilepattern("a").call();
454 RevCommit initialCommit = git.commit().setMessage("initial").call();
455
456 createBranch(initialCommit, "refs/heads/side");
457 checkoutBranch("refs/heads/side");
458
459 writeTrashFile("b", "1\nb(side)\n3\n");
460 git.add().addFilepattern("b").call();
461 RevCommit secondCommit = git.commit().setMessage("side").call();
462
463 checkoutBranch("refs/heads/master");
464
465 writeTrashFile("b", "1\nb(main)\n3\n");
466 git.add().addFilepattern("b").call();
467 git.commit().setMessage("main").call();
468
469 MergeResult result = git.merge().include(secondCommit.getId())
470 .setStrategy(MergeStrategy.RESOLVE).call();
471 assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
472 }
473 }
474
475 @Test
476 public void testMultipleCreationsSameContent() throws Exception {
477 try (Git git = new Git(db)) {
478 writeTrashFile("a", "1\na\n3\n");
479 git.add().addFilepattern("a").call();
480 RevCommit initialCommit = git.commit().setMessage("initial").call();
481
482 createBranch(initialCommit, "refs/heads/side");
483 checkoutBranch("refs/heads/side");
484
485 writeTrashFile("b", "1\nb(1)\n3\n");
486 git.add().addFilepattern("b").call();
487 RevCommit secondCommit = git.commit().setMessage("side").call();
488
489 checkoutBranch("refs/heads/master");
490
491 writeTrashFile("b", "1\nb(1)\n3\n");
492 git.add().addFilepattern("b").call();
493 git.commit().setMessage("main").call();
494
495 MergeResult result = git.merge().include(secondCommit.getId())
496 .setStrategy(MergeStrategy.RESOLVE).call();
497 assertEquals(MergeStatus.MERGED, result.getMergeStatus());
498 assertEquals("1\nb(1)\n3\n", read(new File(db.getWorkTree(), "b")));
499 assertEquals("merge " + secondCommit.getId().getName()
500 + ": Merge made by resolve.", db
501 .getReflogReader(Constants.HEAD)
502 .getLastEntry().getComment());
503 assertEquals("merge " + secondCommit.getId().getName()
504 + ": Merge made by resolve.", db
505 .getReflogReader(db.getBranch())
506 .getLastEntry().getComment());
507 }
508 }
509
510 @Test
511 public void testSuccessfulContentMerge() throws Exception {
512 try (Git git = new Git(db)) {
513 writeTrashFile("a", "1\na\n3\n");
514 writeTrashFile("b", "1\nb\n3\n");
515 writeTrashFile("c/c/c", "1\nc\n3\n");
516 git.add().addFilepattern("a").addFilepattern("b")
517 .addFilepattern("c/c/c").call();
518 RevCommit initialCommit = git.commit().setMessage("initial").call();
519
520 createBranch(initialCommit, "refs/heads/side");
521 checkoutBranch("refs/heads/side");
522
523 writeTrashFile("a", "1(side)\na\n3\n");
524 writeTrashFile("b", "1\nb(side)\n3\n");
525 git.add().addFilepattern("a").addFilepattern("b").call();
526 RevCommit secondCommit = git.commit().setMessage("side").call();
527
528 assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
529 checkoutBranch("refs/heads/master");
530 assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
531
532 writeTrashFile("a", "1\na\n3(main)\n");
533 writeTrashFile("c/c/c", "1\nc(main)\n3\n");
534 git.add().addFilepattern("a").addFilepattern("c/c/c").call();
535 RevCommit thirdCommit = git.commit().setMessage("main").call();
536
537 MergeResult result = git.merge().include(secondCommit.getId())
538 .setStrategy(MergeStrategy.RESOLVE).call();
539 assertEquals(MergeStatus.MERGED, result.getMergeStatus());
540
541 assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(),
542 "a")));
543 assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
544 assertEquals("1\nc(main)\n3\n", read(new File(db.getWorkTree(),
545 "c/c/c")));
546
547 assertEquals(null, result.getConflicts());
548
549 assertEquals(2, result.getMergedCommits().length);
550 assertEquals(thirdCommit, result.getMergedCommits()[0]);
551 assertEquals(secondCommit, result.getMergedCommits()[1]);
552
553 Iterator<RevCommit> it = git.log().call().iterator();
554 RevCommit newHead = it.next();
555 assertEquals(newHead, result.getNewHead());
556 assertEquals(2, newHead.getParentCount());
557 assertEquals(thirdCommit, newHead.getParent(0));
558 assertEquals(secondCommit, newHead.getParent(1));
559 assertEquals(
560 "Merge commit '3fa334456d236a92db020289fe0bf481d91777b4'",
561 newHead.getFullMessage());
562
563 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
564
565 }
566 }
567
568 @Test
569 public void testSuccessfulContentMergeNoCommit() throws Exception {
570 try (Git git = new Git(db)) {
571 writeTrashFile("a", "1\na\n3\n");
572 writeTrashFile("b", "1\nb\n3\n");
573 writeTrashFile("c/c/c", "1\nc\n3\n");
574 git.add().addFilepattern("a").addFilepattern("b")
575 .addFilepattern("c/c/c").call();
576 RevCommit initialCommit = git.commit().setMessage("initial").call();
577
578 createBranch(initialCommit, "refs/heads/side");
579 checkoutBranch("refs/heads/side");
580
581 writeTrashFile("a", "1(side)\na\n3\n");
582 writeTrashFile("b", "1\nb(side)\n3\n");
583 git.add().addFilepattern("a").addFilepattern("b").call();
584 RevCommit secondCommit = git.commit().setMessage("side").call();
585
586 assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
587 checkoutBranch("refs/heads/master");
588 assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
589
590 writeTrashFile("a", "1\na\n3(main)\n");
591 writeTrashFile("c/c/c", "1\nc(main)\n3\n");
592 git.add().addFilepattern("a").addFilepattern("c/c/c").call();
593 RevCommit thirdCommit = git.commit().setMessage("main").call();
594
595 MergeResult result = git.merge().include(secondCommit.getId())
596 .setCommit(false)
597 .setStrategy(MergeStrategy.RESOLVE).call();
598 assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus());
599 assertEquals(db.exactRef(Constants.HEAD).getTarget().getObjectId(),
600 thirdCommit.getId());
601
602 assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(),
603 "a")));
604 assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
605 assertEquals("1\nc(main)\n3\n",
606 read(new File(db.getWorkTree(), "c/c/c")));
607
608 assertEquals(null, result.getConflicts());
609
610 assertEquals(2, result.getMergedCommits().length);
611 assertEquals(thirdCommit, result.getMergedCommits()[0]);
612 assertEquals(secondCommit, result.getMergedCommits()[1]);
613 assertNull(result.getNewHead());
614 assertEquals(RepositoryState.MERGING_RESOLVED, db.getRepositoryState());
615 }
616 }
617
618 @Test
619 public void testSuccessfulContentMergeAndDirtyworkingTree()
620 throws Exception {
621 try (Git git = new Git(db)) {
622 writeTrashFile("a", "1\na\n3\n");
623 writeTrashFile("b", "1\nb\n3\n");
624 writeTrashFile("d", "1\nd\n3\n");
625 writeTrashFile("c/c/c", "1\nc\n3\n");
626 git.add().addFilepattern("a").addFilepattern("b")
627 .addFilepattern("c/c/c").addFilepattern("d").call();
628 RevCommit initialCommit = git.commit().setMessage("initial").call();
629
630 createBranch(initialCommit, "refs/heads/side");
631 checkoutBranch("refs/heads/side");
632
633 writeTrashFile("a", "1(side)\na\n3\n");
634 writeTrashFile("b", "1\nb(side)\n3\n");
635 git.add().addFilepattern("a").addFilepattern("b").call();
636 RevCommit secondCommit = git.commit().setMessage("side").call();
637
638 assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
639 checkoutBranch("refs/heads/master");
640 assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
641
642 writeTrashFile("a", "1\na\n3(main)\n");
643 writeTrashFile("c/c/c", "1\nc(main)\n3\n");
644 git.add().addFilepattern("a").addFilepattern("c/c/c").call();
645 RevCommit thirdCommit = git.commit().setMessage("main").call();
646
647 writeTrashFile("d", "--- dirty ---");
648 MergeResult result = git.merge().include(secondCommit.getId())
649 .setStrategy(MergeStrategy.RESOLVE).call();
650 assertEquals(MergeStatus.MERGED, result.getMergeStatus());
651
652 assertEquals("1(side)\na\n3(main)\n", read(new File(db.getWorkTree(),
653 "a")));
654 assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
655 assertEquals("1\nc(main)\n3\n", read(new File(db.getWorkTree(),
656 "c/c/c")));
657 assertEquals("--- dirty ---", read(new File(db.getWorkTree(), "d")));
658
659 assertEquals(null, result.getConflicts());
660
661 assertEquals(2, result.getMergedCommits().length);
662 assertEquals(thirdCommit, result.getMergedCommits()[0]);
663 assertEquals(secondCommit, result.getMergedCommits()[1]);
664
665 Iterator<RevCommit> it = git.log().call().iterator();
666 RevCommit newHead = it.next();
667 assertEquals(newHead, result.getNewHead());
668 assertEquals(2, newHead.getParentCount());
669 assertEquals(thirdCommit, newHead.getParent(0));
670 assertEquals(secondCommit, newHead.getParent(1));
671 assertEquals(
672 "Merge commit '064d54d98a4cdb0fed1802a21c656bfda67fe879'",
673 newHead.getFullMessage());
674
675 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
676 }
677 }
678
679 @Test
680 public void testSingleDeletion() throws Exception {
681 try (Git git = new Git(db)) {
682 writeTrashFile("a", "1\na\n3\n");
683 writeTrashFile("b", "1\nb\n3\n");
684 writeTrashFile("d", "1\nd\n3\n");
685 writeTrashFile("c/c/c", "1\nc\n3\n");
686 git.add().addFilepattern("a").addFilepattern("b")
687 .addFilepattern("c/c/c").addFilepattern("d").call();
688 RevCommit initialCommit = git.commit().setMessage("initial").call();
689
690 createBranch(initialCommit, "refs/heads/side");
691 checkoutBranch("refs/heads/side");
692
693 assertTrue(new File(db.getWorkTree(), "b").delete());
694 git.add().addFilepattern("b").setUpdate(true).call();
695 RevCommit secondCommit = git.commit().setMessage("side").call();
696
697 assertFalse(new File(db.getWorkTree(), "b").exists());
698 checkoutBranch("refs/heads/master");
699 assertTrue(new File(db.getWorkTree(), "b").exists());
700
701 writeTrashFile("a", "1\na\n3(main)\n");
702 writeTrashFile("c/c/c", "1\nc(main)\n3\n");
703 git.add().addFilepattern("a").addFilepattern("c/c/c").call();
704 RevCommit thirdCommit = git.commit().setMessage("main").call();
705
706
707 MergeResult result = git.merge().include(secondCommit.getId())
708 .setStrategy(MergeStrategy.RESOLVE).call();
709 assertEquals(MergeStatus.MERGED, result.getMergeStatus());
710
711 assertEquals("1\na\n3(main)\n", read(new File(db.getWorkTree(), "a")));
712 assertFalse(new File(db.getWorkTree(), "b").exists());
713 assertEquals("1\nc(main)\n3\n",
714 read(new File(db.getWorkTree(), "c/c/c")));
715 assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d")));
716
717
718
719 checkoutBranch("refs/heads/side");
720 assertFalse(new File(db.getWorkTree(), "b").exists());
721
722 result = git.merge().include(thirdCommit.getId())
723 .setStrategy(MergeStrategy.RESOLVE).call();
724 assertEquals(MergeStatus.MERGED, result.getMergeStatus());
725
726 assertEquals("1\na\n3(main)\n", read(new File(db.getWorkTree(), "a")));
727 assertFalse(new File(db.getWorkTree(), "b").exists());
728 assertEquals("1\nc(main)\n3\n",
729 read(new File(db.getWorkTree(), "c/c/c")));
730 assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d")));
731 }
732 }
733
734 @Test
735 public void testMultipleDeletions() throws Exception {
736 try (Git git = new Git(db)) {
737 writeTrashFile("a", "1\na\n3\n");
738 git.add().addFilepattern("a").call();
739 RevCommit initialCommit = git.commit().setMessage("initial").call();
740
741 createBranch(initialCommit, "refs/heads/side");
742 checkoutBranch("refs/heads/side");
743
744 assertTrue(new File(db.getWorkTree(), "a").delete());
745 git.add().addFilepattern("a").setUpdate(true).call();
746 RevCommit secondCommit = git.commit().setMessage("side").call();
747
748 assertFalse(new File(db.getWorkTree(), "a").exists());
749 checkoutBranch("refs/heads/master");
750 assertTrue(new File(db.getWorkTree(), "a").exists());
751
752 assertTrue(new File(db.getWorkTree(), "a").delete());
753 git.add().addFilepattern("a").setUpdate(true).call();
754 git.commit().setMessage("main").call();
755
756
757 MergeResult result = git.merge().include(secondCommit.getId())
758 .setStrategy(MergeStrategy.RESOLVE).call();
759 assertEquals(MergeStatus.MERGED, result.getMergeStatus());
760 }
761 }
762
763 @Test
764 public void testDeletionAndConflict() throws Exception {
765 try (Git git = new Git(db)) {
766 writeTrashFile("a", "1\na\n3\n");
767 writeTrashFile("b", "1\nb\n3\n");
768 writeTrashFile("d", "1\nd\n3\n");
769 writeTrashFile("c/c/c", "1\nc\n3\n");
770 git.add().addFilepattern("a").addFilepattern("b")
771 .addFilepattern("c/c/c").addFilepattern("d").call();
772 RevCommit initialCommit = git.commit().setMessage("initial").call();
773
774 createBranch(initialCommit, "refs/heads/side");
775 checkoutBranch("refs/heads/side");
776
777 assertTrue(new File(db.getWorkTree(), "b").delete());
778 writeTrashFile("a", "1\na\n3(side)\n");
779 git.add().addFilepattern("b").setUpdate(true).call();
780 git.add().addFilepattern("a").setUpdate(true).call();
781 RevCommit secondCommit = git.commit().setMessage("side").call();
782
783 assertFalse(new File(db.getWorkTree(), "b").exists());
784 checkoutBranch("refs/heads/master");
785 assertTrue(new File(db.getWorkTree(), "b").exists());
786
787 writeTrashFile("a", "1\na\n3(main)\n");
788 writeTrashFile("c/c/c", "1\nc(main)\n3\n");
789 git.add().addFilepattern("a").addFilepattern("c/c/c").call();
790 git.commit().setMessage("main").call();
791
792
793 MergeResult result = git.merge().include(secondCommit.getId())
794 .setStrategy(MergeStrategy.RESOLVE).call();
795 assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
796
797 assertEquals(
798 "1\na\n<<<<<<< HEAD\n3(main)\n=======\n3(side)\n>>>>>>> 54ffed45d62d252715fc20e41da92d44c48fb0ff\n",
799 read(new File(db.getWorkTree(), "a")));
800 assertFalse(new File(db.getWorkTree(), "b").exists());
801 assertEquals("1\nc(main)\n3\n",
802 read(new File(db.getWorkTree(), "c/c/c")));
803 assertEquals("1\nd\n3\n", read(new File(db.getWorkTree(), "d")));
804 }
805 }
806
807 @Test
808 public void testDeletionOnMasterConflict() throws Exception {
809 try (Git git = new Git(db)) {
810 writeTrashFile("a", "1\na\n3\n");
811 writeTrashFile("b", "1\nb\n3\n");
812 git.add().addFilepattern("a").addFilepattern("b").call();
813 RevCommit initialCommit = git.commit().setMessage("initial").call();
814
815
816 createBranch(initialCommit, "refs/heads/side");
817 checkoutBranch("refs/heads/side");
818 writeTrashFile("a", "1\na(side)\n3\n");
819 git.add().addFilepattern("a").call();
820 RevCommit secondCommit = git.commit().setMessage("side").call();
821
822
823 checkoutBranch("refs/heads/master");
824 git.rm().addFilepattern("a").call();
825 git.commit().setMessage("main").call();
826
827
828 MergeResult result = git.merge().include(secondCommit.getId())
829 .setStrategy(MergeStrategy.RESOLVE).call();
830 assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
831
832
833 assertTrue(new File(db.getWorkTree(), "a").exists());
834 assertEquals("1\na(side)\n3\n", read(new File(db.getWorkTree(), "a")));
835 assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
836 }
837 }
838
839 @Test
840 public void testDeletionOnSideConflict() throws Exception {
841 try (Git git = new Git(db)) {
842 writeTrashFile("a", "1\na\n3\n");
843 writeTrashFile("b", "1\nb\n3\n");
844 git.add().addFilepattern("a").addFilepattern("b").call();
845 RevCommit initialCommit = git.commit().setMessage("initial").call();
846
847
848 createBranch(initialCommit, "refs/heads/side");
849 checkoutBranch("refs/heads/side");
850 git.rm().addFilepattern("a").call();
851 RevCommit secondCommit = git.commit().setMessage("side").call();
852
853
854 checkoutBranch("refs/heads/master");
855 writeTrashFile("a", "1\na(main)\n3\n");
856 git.add().addFilepattern("a").call();
857 git.commit().setMessage("main").call();
858
859
860 MergeResult result = git.merge().include(secondCommit.getId())
861 .setStrategy(MergeStrategy.RESOLVE).call();
862 assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
863
864 assertTrue(new File(db.getWorkTree(), "a").exists());
865 assertEquals("1\na(main)\n3\n", read(new File(db.getWorkTree(), "a")));
866 assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
867
868 assertEquals(1, result.getConflicts().size());
869 assertEquals(3, result.getConflicts().get("a")[0].length);
870 }
871 }
872
873 @Test
874 public void testModifiedAndRenamed() throws Exception {
875
876
877
878 try (Git git = new Git(db)) {
879 writeTrashFile("x", "add x");
880 git.add().addFilepattern("x").call();
881 RevCommit initial = git.commit().setMessage("add x").call();
882
883 createBranch(initial, "refs/heads/d1");
884 createBranch(initial, "refs/heads/d2");
885
886
887 checkoutBranch("refs/heads/d1");
888 new File(db.getWorkTree(), "x")
889 .renameTo(new File(db.getWorkTree(), "y"));
890 git.rm().addFilepattern("x").call();
891 git.add().addFilepattern("y").call();
892 RevCommit d1Commit = git.commit().setMessage("d1 rename x -> y").call();
893
894 checkoutBranch("refs/heads/d2");
895 writeTrashFile("x", "d2 change");
896 git.add().addFilepattern("x").call();
897 RevCommit d2Commit = git.commit().setMessage("d2 change in x").call();
898
899 checkoutBranch("refs/heads/master");
900 MergeResult d1Merge = git.merge().include(d1Commit).call();
901 assertEquals(MergeResult.MergeStatus.FAST_FORWARD,
902 d1Merge.getMergeStatus());
903
904 MergeResult d2Merge = git.merge().include(d2Commit).call();
905 assertEquals(MergeResult.MergeStatus.CONFLICTING,
906 d2Merge.getMergeStatus());
907 assertEquals(1, d2Merge.getConflicts().size());
908 assertEquals(3, d2Merge.getConflicts().get("x")[0].length);
909 }
910 }
911
912 @Test
913 public void testMergeFailingWithDirtyWorkingTree() throws Exception {
914 try (Git git = new Git(db)) {
915 writeTrashFile("a", "1\na\n3\n");
916 writeTrashFile("b", "1\nb\n3\n");
917 git.add().addFilepattern("a").addFilepattern("b").call();
918 RevCommit initialCommit = git.commit().setMessage("initial").call();
919
920 createBranch(initialCommit, "refs/heads/side");
921 checkoutBranch("refs/heads/side");
922
923 writeTrashFile("a", "1(side)\na\n3\n");
924 writeTrashFile("b", "1\nb(side)\n3\n");
925 git.add().addFilepattern("a").addFilepattern("b").call();
926 RevCommit secondCommit = git.commit().setMessage("side").call();
927
928 assertEquals("1\nb(side)\n3\n", read(new File(db.getWorkTree(), "b")));
929 checkoutBranch("refs/heads/master");
930 assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
931
932 writeTrashFile("a", "1\na\n3(main)\n");
933 git.add().addFilepattern("a").call();
934 git.commit().setMessage("main").call();
935
936 writeTrashFile("a", "--- dirty ---");
937 MergeResult result = git.merge().include(secondCommit.getId())
938 .setStrategy(MergeStrategy.RESOLVE).call();
939
940 assertEquals(MergeStatus.FAILED, result.getMergeStatus());
941
942 assertEquals("--- dirty ---", read(new File(db.getWorkTree(), "a")));
943 assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
944
945 assertEquals(null, result.getConflicts());
946
947 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
948 }
949 }
950
951 @Test
952 public void testMergeConflictFileFolder() throws Exception {
953 try (Git git = new Git(db)) {
954 writeTrashFile("a", "1\na\n3\n");
955 writeTrashFile("b", "1\nb\n3\n");
956 git.add().addFilepattern("a").addFilepattern("b").call();
957 RevCommit initialCommit = git.commit().setMessage("initial").call();
958
959 createBranch(initialCommit, "refs/heads/side");
960 checkoutBranch("refs/heads/side");
961
962 writeTrashFile("c/c/c", "1\nc(side)\n3\n");
963 writeTrashFile("d", "1\nd(side)\n3\n");
964 git.add().addFilepattern("c/c/c").addFilepattern("d").call();
965 RevCommit secondCommit = git.commit().setMessage("side").call();
966
967 checkoutBranch("refs/heads/master");
968
969 writeTrashFile("c", "1\nc(main)\n3\n");
970 writeTrashFile("d/d/d", "1\nd(main)\n3\n");
971 git.add().addFilepattern("c").addFilepattern("d/d/d").call();
972 git.commit().setMessage("main").call();
973
974 MergeResult result = git.merge().include(secondCommit.getId())
975 .setStrategy(MergeStrategy.RESOLVE).call();
976
977 assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
978
979 assertEquals("1\na\n3\n", read(new File(db.getWorkTree(), "a")));
980 assertEquals("1\nb\n3\n", read(new File(db.getWorkTree(), "b")));
981 assertEquals("1\nc(main)\n3\n", read(new File(db.getWorkTree(), "c")));
982 assertEquals("1\nd(main)\n3\n", read(new File(db.getWorkTree(), "d/d/d")));
983
984 assertEquals(null, result.getConflicts());
985
986 assertEquals(RepositoryState.MERGING, db.getRepositoryState());
987 }
988 }
989
990 @Test
991 public void testSuccessfulMergeFailsDueToDirtyIndex() throws Exception {
992 try (Git git = new Git(db)) {
993 File fileA = writeTrashFile("a", "a");
994 RevCommit initialCommit = addAllAndCommit(git);
995
996
997 createBranch(initialCommit, "refs/heads/side");
998 checkoutBranch("refs/heads/side");
999
1000 write(fileA, "a(side)");
1001 writeTrashFile("b", "b");
1002 RevCommit sideCommit = addAllAndCommit(git);
1003
1004
1005 checkoutBranch("refs/heads/master");
1006 writeTrashFile("c", "c");
1007 addAllAndCommit(git);
1008
1009
1010 write(fileA, "a(modified)");
1011 git.add().addFilepattern("a").call();
1012
1013
1014
1015 String indexState = indexState(CONTENT);
1016
1017
1018 MergeResult result = git.merge().include(sideCommit.getId())
1019 .setStrategy(MergeStrategy.RESOLVE).call();
1020
1021 checkMergeFailedResult(result, MergeFailureReason.DIRTY_INDEX,
1022 indexState, fileA);
1023 }
1024 }
1025
1026 @Test
1027 public void testConflictingMergeFailsDueToDirtyIndex() throws Exception {
1028 try (Git git = new Git(db)) {
1029 File fileA = writeTrashFile("a", "a");
1030 RevCommit initialCommit = addAllAndCommit(git);
1031
1032
1033 createBranch(initialCommit, "refs/heads/side");
1034 checkoutBranch("refs/heads/side");
1035
1036 write(fileA, "a(side)");
1037 writeTrashFile("b", "b");
1038 RevCommit sideCommit = addAllAndCommit(git);
1039
1040
1041 checkoutBranch("refs/heads/master");
1042
1043 write(fileA, "a(master)");
1044 writeTrashFile("c", "c");
1045 addAllAndCommit(git);
1046
1047
1048 write(fileA, "a(modified)");
1049 git.add().addFilepattern("a").call();
1050
1051
1052
1053 String indexState = indexState(CONTENT);
1054
1055
1056 MergeResult result = git.merge().include(sideCommit.getId())
1057 .setStrategy(MergeStrategy.RESOLVE).call();
1058
1059 checkMergeFailedResult(result, MergeFailureReason.DIRTY_INDEX,
1060 indexState, fileA);
1061 }
1062 }
1063
1064 @Test
1065 public void testSuccessfulMergeFailsDueToDirtyWorktree() throws Exception {
1066 try (Git git = new Git(db)) {
1067 File fileA = writeTrashFile("a", "a");
1068 RevCommit initialCommit = addAllAndCommit(git);
1069
1070
1071 createBranch(initialCommit, "refs/heads/side");
1072 checkoutBranch("refs/heads/side");
1073
1074 write(fileA, "a(side)");
1075 writeTrashFile("b", "b");
1076 RevCommit sideCommit = addAllAndCommit(git);
1077
1078
1079 checkoutBranch("refs/heads/master");
1080 writeTrashFile("c", "c");
1081 addAllAndCommit(git);
1082
1083
1084 write(fileA, "a(modified)");
1085
1086
1087
1088 String indexState = indexState(CONTENT);
1089
1090
1091 MergeResult result = git.merge().include(sideCommit.getId())
1092 .setStrategy(MergeStrategy.RESOLVE).call();
1093
1094 checkMergeFailedResult(result, MergeFailureReason.DIRTY_WORKTREE,
1095 indexState, fileA);
1096 }
1097 }
1098
1099 @Test
1100 public void testConflictingMergeFailsDueToDirtyWorktree() throws Exception {
1101 try (Git git = new Git(db)) {
1102 File fileA = writeTrashFile("a", "a");
1103 RevCommit initialCommit = addAllAndCommit(git);
1104
1105
1106 createBranch(initialCommit, "refs/heads/side");
1107 checkoutBranch("refs/heads/side");
1108
1109 write(fileA, "a(side)");
1110 writeTrashFile("b", "b");
1111 RevCommit sideCommit = addAllAndCommit(git);
1112
1113
1114 checkoutBranch("refs/heads/master");
1115
1116 write(fileA, "a(master)");
1117 writeTrashFile("c", "c");
1118 addAllAndCommit(git);
1119
1120
1121 write(fileA, "a(modified)");
1122
1123
1124
1125 String indexState = indexState(CONTENT);
1126
1127
1128 MergeResult result = git.merge().include(sideCommit.getId())
1129 .setStrategy(MergeStrategy.RESOLVE).call();
1130
1131 checkMergeFailedResult(result, MergeFailureReason.DIRTY_WORKTREE,
1132 indexState, fileA);
1133 }
1134 }
1135
1136 @Test
1137 public void testMergeRemovingFolders() throws Exception {
1138 File folder1 = new File(db.getWorkTree(), "folder1");
1139 File folder2 = new File(db.getWorkTree(), "folder2");
1140 FileUtils.mkdir(folder1);
1141 FileUtils.mkdir(folder2);
1142 File file = new File(folder1, "file1.txt");
1143 write(file, "folder1--file1.txt");
1144 file = new File(folder1, "file2.txt");
1145 write(file, "folder1--file2.txt");
1146 file = new File(folder2, "file1.txt");
1147 write(file, "folder--file1.txt");
1148 file = new File(folder2, "file2.txt");
1149 write(file, "folder2--file2.txt");
1150
1151 try (Git git = new Git(db)) {
1152 git.add().addFilepattern(folder1.getName())
1153 .addFilepattern(folder2.getName()).call();
1154 RevCommit commit1 = git.commit().setMessage("adding folders").call();
1155
1156 recursiveDelete(folder1);
1157 recursiveDelete(folder2);
1158 git.rm().addFilepattern("folder1/file1.txt")
1159 .addFilepattern("folder1/file2.txt")
1160 .addFilepattern("folder2/file1.txt")
1161 .addFilepattern("folder2/file2.txt").call();
1162 RevCommit commit2 = git.commit()
1163 .setMessage("removing folders on 'branch'").call();
1164
1165 git.checkout().setName(commit1.name()).call();
1166
1167 MergeResult result = git.merge().include(commit2.getId())
1168 .setStrategy(MergeStrategy.RESOLVE).call();
1169 assertEquals(MergeResult.MergeStatus.FAST_FORWARD,
1170 result.getMergeStatus());
1171 assertEquals(commit2, result.getNewHead());
1172 assertFalse(folder1.exists());
1173 assertFalse(folder2.exists());
1174 }
1175 }
1176
1177 @Test
1178 public void testMergeRemovingFoldersWithoutFastForward() throws Exception {
1179 File folder1 = new File(db.getWorkTree(), "folder1");
1180 File folder2 = new File(db.getWorkTree(), "folder2");
1181 FileUtils.mkdir(folder1);
1182 FileUtils.mkdir(folder2);
1183 File file = new File(folder1, "file1.txt");
1184 write(file, "folder1--file1.txt");
1185 file = new File(folder1, "file2.txt");
1186 write(file, "folder1--file2.txt");
1187 file = new File(folder2, "file1.txt");
1188 write(file, "folder--file1.txt");
1189 file = new File(folder2, "file2.txt");
1190 write(file, "folder2--file2.txt");
1191
1192 try (Git git = new Git(db)) {
1193 git.add().addFilepattern(folder1.getName())
1194 .addFilepattern(folder2.getName()).call();
1195 RevCommit base = git.commit().setMessage("adding folders").call();
1196
1197 recursiveDelete(folder1);
1198 recursiveDelete(folder2);
1199 git.rm().addFilepattern("folder1/file1.txt")
1200 .addFilepattern("folder1/file2.txt")
1201 .addFilepattern("folder2/file1.txt")
1202 .addFilepattern("folder2/file2.txt").call();
1203 RevCommit other = git.commit()
1204 .setMessage("removing folders on 'branch'").call();
1205
1206 git.checkout().setName(base.name()).call();
1207
1208 file = new File(folder2, "file3.txt");
1209 write(file, "folder2--file3.txt");
1210
1211 git.add().addFilepattern(folder2.getName()).call();
1212 git.commit().setMessage("adding another file").call();
1213
1214 MergeResult result = git.merge().include(other.getId())
1215 .setStrategy(MergeStrategy.RESOLVE).call();
1216
1217 assertEquals(MergeResult.MergeStatus.MERGED,
1218 result.getMergeStatus());
1219 assertFalse(folder1.exists());
1220 }
1221 }
1222
1223 @Test
1224 public void testFileModeMerge() throws Exception {
1225
1226 assumeTrue(FS.DETECTED.supportsExecute());
1227 try (Git git = new Git(db)) {
1228 writeTrashFile("mergeableMode", "a");
1229 setExecutable(git, "mergeableMode", false);
1230 writeTrashFile("conflictingModeWithBase", "a");
1231 setExecutable(git, "conflictingModeWithBase", false);
1232 RevCommit initialCommit = addAllAndCommit(git);
1233
1234
1235 createBranch(initialCommit, "refs/heads/side");
1236 checkoutBranch("refs/heads/side");
1237 setExecutable(git, "mergeableMode", true);
1238 writeTrashFile("conflictingModeNoBase", "b");
1239 setExecutable(git, "conflictingModeNoBase", true);
1240 RevCommit sideCommit = addAllAndCommit(git);
1241
1242
1243 createBranch(initialCommit, "refs/heads/side2");
1244 checkoutBranch("refs/heads/side2");
1245 setExecutable(git, "mergeableMode", false);
1246 assertFalse(new File(git.getRepository().getWorkTree(),
1247 "conflictingModeNoBase").exists());
1248 writeTrashFile("conflictingModeNoBase", "b");
1249 setExecutable(git, "conflictingModeNoBase", false);
1250 addAllAndCommit(git);
1251
1252
1253 MergeResult result = git.merge().include(sideCommit.getId())
1254 .setStrategy(MergeStrategy.RESOLVE).call();
1255 assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
1256 assertTrue(canExecute(git, "mergeableMode"));
1257 assertFalse(canExecute(git, "conflictingModeNoBase"));
1258 }
1259 }
1260
1261 @Test
1262 public void testFileModeMergeWithDirtyWorkTree() throws Exception {
1263
1264 assumeTrue(FS.DETECTED.supportsExecute());
1265
1266 try (Git git = new Git(db)) {
1267 writeTrashFile("mergeableButDirty", "a");
1268 setExecutable(git, "mergeableButDirty", false);
1269 RevCommit initialCommit = addAllAndCommit(git);
1270
1271
1272 createBranch(initialCommit, "refs/heads/side");
1273 checkoutBranch("refs/heads/side");
1274 setExecutable(git, "mergeableButDirty", true);
1275 RevCommit sideCommit = addAllAndCommit(git);
1276
1277
1278 createBranch(initialCommit, "refs/heads/side2");
1279 checkoutBranch("refs/heads/side2");
1280 setExecutable(git, "mergeableButDirty", false);
1281 addAllAndCommit(git);
1282
1283 writeTrashFile("mergeableButDirty", "b");
1284
1285
1286 MergeResult result = git.merge().include(sideCommit.getId())
1287 .setStrategy(MergeStrategy.RESOLVE).call();
1288 assertEquals(MergeStatus.FAILED, result.getMergeStatus());
1289 assertFalse(canExecute(git, "mergeableButDirty"));
1290 }
1291 }
1292
1293 @Test
1294 public void testSquashFastForward() throws Exception {
1295 try (Git git = new Git(db)) {
1296 writeTrashFile("file1", "file1");
1297 git.add().addFilepattern("file1").call();
1298 RevCommit first = git.commit().setMessage("initial commit").call();
1299
1300 assertTrue(new File(db.getWorkTree(), "file1").exists());
1301 createBranch(first, "refs/heads/branch1");
1302 checkoutBranch("refs/heads/branch1");
1303
1304 writeTrashFile("file2", "file2");
1305 git.add().addFilepattern("file2").call();
1306 RevCommit second = git.commit().setMessage("second commit").call();
1307 assertTrue(new File(db.getWorkTree(), "file2").exists());
1308
1309 writeTrashFile("file3", "file3");
1310 git.add().addFilepattern("file3").call();
1311 RevCommit third = git.commit().setMessage("third commit").call();
1312 assertTrue(new File(db.getWorkTree(), "file3").exists());
1313
1314 checkoutBranch("refs/heads/master");
1315 assertTrue(new File(db.getWorkTree(), "file1").exists());
1316 assertFalse(new File(db.getWorkTree(), "file2").exists());
1317 assertFalse(new File(db.getWorkTree(), "file3").exists());
1318
1319 MergeResult result = git.merge()
1320 .include(db.exactRef("refs/heads/branch1"))
1321 .setSquash(true)
1322 .call();
1323
1324 assertTrue(new File(db.getWorkTree(), "file1").exists());
1325 assertTrue(new File(db.getWorkTree(), "file2").exists());
1326 assertTrue(new File(db.getWorkTree(), "file3").exists());
1327 assertEquals(MergeResult.MergeStatus.FAST_FORWARD_SQUASHED,
1328 result.getMergeStatus());
1329 assertEquals(first, result.getNewHead());
1330 assertEquals(first, db.resolve(Constants.HEAD + "^{commit}"));
1331
1332 assertEquals(
1333 "Squashed commit of the following:\n\ncommit "
1334 + third.getName()
1335 + "\nAuthor: "
1336 + third.getAuthorIdent().getName()
1337 + " <"
1338 + third.getAuthorIdent().getEmailAddress()
1339 + ">\nDate: "
1340 + dateFormatter.formatDate(third
1341 .getAuthorIdent())
1342 + "\n\n\tthird commit\n\ncommit "
1343 + second.getName()
1344 + "\nAuthor: "
1345 + second.getAuthorIdent().getName()
1346 + " <"
1347 + second.getAuthorIdent().getEmailAddress()
1348 + ">\nDate: "
1349 + dateFormatter.formatDate(second
1350 .getAuthorIdent()) + "\n\n\tsecond commit\n",
1351 db.readSquashCommitMsg());
1352 assertNull(db.readMergeCommitMsg());
1353
1354 Status stat = git.status().call();
1355 assertEquals(Sets.of("file2", "file3"), stat.getAdded());
1356 }
1357 }
1358
1359 @Test
1360 public void testSquashMerge() throws Exception {
1361 try (Git git = new Git(db)) {
1362 writeTrashFile("file1", "file1");
1363 git.add().addFilepattern("file1").call();
1364 RevCommit first = git.commit().setMessage("initial commit").call();
1365
1366 assertTrue(new File(db.getWorkTree(), "file1").exists());
1367 createBranch(first, "refs/heads/branch1");
1368
1369 writeTrashFile("file2", "file2");
1370 git.add().addFilepattern("file2").call();
1371 RevCommit second = git.commit().setMessage("second commit").call();
1372 assertTrue(new File(db.getWorkTree(), "file2").exists());
1373
1374 checkoutBranch("refs/heads/branch1");
1375
1376 writeTrashFile("file3", "file3");
1377 git.add().addFilepattern("file3").call();
1378 RevCommit third = git.commit().setMessage("third commit").call();
1379 assertTrue(new File(db.getWorkTree(), "file3").exists());
1380
1381 checkoutBranch("refs/heads/master");
1382 assertTrue(new File(db.getWorkTree(), "file1").exists());
1383 assertTrue(new File(db.getWorkTree(), "file2").exists());
1384 assertFalse(new File(db.getWorkTree(), "file3").exists());
1385
1386 MergeResult result = git.merge()
1387 .include(db.exactRef("refs/heads/branch1"))
1388 .setSquash(true)
1389 .call();
1390
1391 assertTrue(new File(db.getWorkTree(), "file1").exists());
1392 assertTrue(new File(db.getWorkTree(), "file2").exists());
1393 assertTrue(new File(db.getWorkTree(), "file3").exists());
1394 assertEquals(MergeResult.MergeStatus.MERGED_SQUASHED,
1395 result.getMergeStatus());
1396 assertEquals(second, result.getNewHead());
1397 assertEquals(second, db.resolve(Constants.HEAD + "^{commit}"));
1398
1399 assertEquals(
1400 "Squashed commit of the following:\n\ncommit "
1401 + third.getName()
1402 + "\nAuthor: "
1403 + third.getAuthorIdent().getName()
1404 + " <"
1405 + third.getAuthorIdent().getEmailAddress()
1406 + ">\nDate: "
1407 + dateFormatter.formatDate(third
1408 .getAuthorIdent()) + "\n\n\tthird commit\n",
1409 db.readSquashCommitMsg());
1410 assertNull(db.readMergeCommitMsg());
1411
1412 Status stat = git.status().call();
1413 assertEquals(Sets.of("file3"), stat.getAdded());
1414 }
1415 }
1416
1417 @Test
1418 public void testSquashMergeConflict() throws Exception {
1419 try (Git git = new Git(db)) {
1420 writeTrashFile("file1", "file1");
1421 git.add().addFilepattern("file1").call();
1422 RevCommit first = git.commit().setMessage("initial commit").call();
1423
1424 assertTrue(new File(db.getWorkTree(), "file1").exists());
1425 createBranch(first, "refs/heads/branch1");
1426
1427 writeTrashFile("file2", "master");
1428 git.add().addFilepattern("file2").call();
1429 RevCommit second = git.commit().setMessage("second commit").call();
1430 assertTrue(new File(db.getWorkTree(), "file2").exists());
1431
1432 checkoutBranch("refs/heads/branch1");
1433
1434 writeTrashFile("file2", "branch");
1435 git.add().addFilepattern("file2").call();
1436 RevCommit third = git.commit().setMessage("third commit").call();
1437 assertTrue(new File(db.getWorkTree(), "file2").exists());
1438
1439 checkoutBranch("refs/heads/master");
1440 assertTrue(new File(db.getWorkTree(), "file1").exists());
1441 assertTrue(new File(db.getWorkTree(), "file2").exists());
1442
1443 MergeResult result = git.merge()
1444 .include(db.exactRef("refs/heads/branch1"))
1445 .setSquash(true)
1446 .call();
1447
1448 assertTrue(new File(db.getWorkTree(), "file1").exists());
1449 assertTrue(new File(db.getWorkTree(), "file2").exists());
1450 assertEquals(MergeResult.MergeStatus.CONFLICTING,
1451 result.getMergeStatus());
1452 assertNull(result.getNewHead());
1453 assertEquals(second, db.resolve(Constants.HEAD + "^{commit}"));
1454
1455 assertEquals(
1456 "Squashed commit of the following:\n\ncommit "
1457 + third.getName()
1458 + "\nAuthor: "
1459 + third.getAuthorIdent().getName()
1460 + " <"
1461 + third.getAuthorIdent().getEmailAddress()
1462 + ">\nDate: "
1463 + dateFormatter.formatDate(third
1464 .getAuthorIdent()) + "\n\n\tthird commit\n",
1465 db.readSquashCommitMsg());
1466 assertEquals("\nConflicts:\n\tfile2\n", db.readMergeCommitMsg());
1467
1468 Status stat = git.status().call();
1469 assertEquals(Sets.of("file2"), stat.getConflicting());
1470 }
1471 }
1472
1473 @Test
1474 public void testFastForwardOnly() throws Exception {
1475 try (Git git = new Git(db)) {
1476 RevCommit initialCommit = git.commit().setMessage("initial commit")
1477 .call();
1478 createBranch(initialCommit, "refs/heads/branch1");
1479 git.commit().setMessage("second commit").call();
1480 checkoutBranch("refs/heads/branch1");
1481
1482 MergeCommand merge = git.merge();
1483 merge.setFastForward(FastForwardMode.FF_ONLY);
1484 merge.include(db.exactRef(R_HEADS + MASTER));
1485 MergeResult result = merge.call();
1486
1487 assertEquals(MergeStatus.FAST_FORWARD, result.getMergeStatus());
1488 }
1489 }
1490
1491 @Test
1492 public void testNoFastForward() throws Exception {
1493 try (Git git = new Git(db)) {
1494 RevCommit initialCommit = git.commit().setMessage("initial commit")
1495 .call();
1496 createBranch(initialCommit, "refs/heads/branch1");
1497 git.commit().setMessage("second commit").call();
1498 checkoutBranch("refs/heads/branch1");
1499
1500 MergeCommand merge = git.merge();
1501 merge.setFastForward(FastForwardMode.NO_FF);
1502 merge.include(db.exactRef(R_HEADS + MASTER));
1503 MergeResult result = merge.call();
1504
1505 assertEquals(MergeStatus.MERGED, result.getMergeStatus());
1506 }
1507 }
1508
1509 @Test
1510 public void testNoFastForwardNoCommit() throws Exception {
1511
1512 try (Git git = new Git(db)) {
1513 RevCommit initialCommit = git.commit().setMessage("initial commit")
1514 .call();
1515 createBranch(initialCommit, "refs/heads/branch1");
1516 RevCommit secondCommit = git.commit().setMessage("second commit")
1517 .call();
1518 checkoutBranch("refs/heads/branch1");
1519
1520
1521 MergeCommand merge = git.merge();
1522 merge.setFastForward(FastForwardMode.NO_FF);
1523 merge.include(db.exactRef(R_HEADS + MASTER));
1524 merge.setCommit(false);
1525 MergeResult result = merge.call();
1526
1527
1528 assertEquals(MergeStatus.MERGED_NOT_COMMITTED, result.getMergeStatus());
1529 assertEquals(2, result.getMergedCommits().length);
1530 assertEquals(initialCommit, result.getMergedCommits()[0]);
1531 assertEquals(secondCommit, result.getMergedCommits()[1]);
1532 assertNull(result.getNewHead());
1533 assertEquals(RepositoryState.MERGING_RESOLVED, db.getRepositoryState());
1534 }
1535 }
1536
1537 @Test
1538 public void testFastForwardOnlyNotPossible() throws Exception {
1539 try (Git git = new Git(db)) {
1540 RevCommit initialCommit = git.commit().setMessage("initial commit")
1541 .call();
1542 createBranch(initialCommit, "refs/heads/branch1");
1543 git.commit().setMessage("second commit").call();
1544 checkoutBranch("refs/heads/branch1");
1545 writeTrashFile("file1", "branch1");
1546 git.add().addFilepattern("file").call();
1547 git.commit().setMessage("second commit on branch1").call();
1548 MergeCommand merge = git.merge();
1549 merge.setFastForward(FastForwardMode.FF_ONLY);
1550 merge.include(db.exactRef(R_HEADS + MASTER));
1551 MergeResult result = merge.call();
1552
1553 assertEquals(MergeStatus.ABORTED, result.getMergeStatus());
1554 }
1555 }
1556
1557 @Test
1558 public void testRecursiveMergeWithConflict() throws Exception {
1559 TestRepository<Repository> db_t = new TestRepository<Repository>(db);
1560 BranchBuilder master = db_t.branch("master");
1561 RevCommit m0 = master.commit().add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9\n")
1562 .message("m0").create();
1563 RevCommit m1 = master.commit()
1564 .add("f", "1-master\n2\n3\n4\n5\n6\n7\n8\n9\n").message("m1")
1565 .create();
1566 db_t.getRevWalk().parseCommit(m1);
1567
1568 BranchBuilder side = db_t.branch("side");
1569 RevCommit s1 = side.commit().parent(m0)
1570 .add("f", "1\n2\n3\n4\n5\n6\n7\n8\n9-side\n").message("s1")
1571 .create();
1572 RevCommit s2 = side.commit().parent(m1)
1573 .add("f", "1-master\n2\n3\n4\n5\n6\n7-res(side)\n8\n9-side\n")
1574 .message("s2(merge)").create();
1575 master.commit().parent(s1)
1576 .add("f", "1-master\n2\n3\n4\n5\n6\n7-conflict\n8\n9-side\n")
1577 .message("m2(merge)").create();
1578
1579 Git git = Git.wrap(db);
1580 git.checkout().setName("master").call();
1581
1582 MergeResult result = git.merge().setStrategy(MergeStrategy.RECURSIVE)
1583 .include("side", s2).call();
1584 assertEquals(MergeStatus.CONFLICTING, result.getMergeStatus());
1585 }
1586
1587 @Test
1588 public void testMergeWithMessageOption() throws Exception {
1589 try (Git git = new Git(db)) {
1590 writeTrashFile("a", "1\na\n3\n");
1591 git.add().addFilepattern("a").call();
1592 RevCommit initialCommit = git.commit().setMessage("initial").call();
1593
1594 createBranch(initialCommit, "refs/heads/side");
1595 checkoutBranch("refs/heads/side");
1596
1597 writeTrashFile("b", "1\nb\n3\n");
1598 git.add().addFilepattern("b").call();
1599 git.commit().setMessage("side").call();
1600
1601 checkoutBranch("refs/heads/master");
1602
1603 writeTrashFile("c", "1\nc\n3\n");
1604 git.add().addFilepattern("c").call();
1605 git.commit().setMessage("main").call();
1606
1607 Ref sideBranch = db.exactRef("refs/heads/side");
1608
1609 git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
1610 .setMessage("user message").call();
1611
1612 assertNull(db.readMergeCommitMsg());
1613
1614 Iterator<RevCommit> it = git.log().call().iterator();
1615 RevCommit newHead = it.next();
1616 assertEquals("user message", newHead.getFullMessage());
1617 }
1618 }
1619
1620 @Test
1621 public void testMergeConflictWithMessageOption() throws Exception {
1622 try (Git git = new Git(db)) {
1623 writeTrashFile("a", "1\na\n3\n");
1624 git.add().addFilepattern("a").call();
1625 RevCommit initialCommit = git.commit().setMessage("initial").call();
1626
1627 createBranch(initialCommit, "refs/heads/side");
1628 checkoutBranch("refs/heads/side");
1629
1630 writeTrashFile("a", "1\na(side)\n3\n");
1631 git.add().addFilepattern("a").call();
1632 git.commit().setMessage("side").call();
1633
1634 checkoutBranch("refs/heads/master");
1635
1636 writeTrashFile("a", "1\na(main)\n3\n");
1637 git.add().addFilepattern("a").call();
1638 git.commit().setMessage("main").call();
1639
1640 Ref sideBranch = db.exactRef("refs/heads/side");
1641
1642 git.merge().include(sideBranch).setStrategy(MergeStrategy.RESOLVE)
1643 .setMessage("user message").call();
1644
1645 assertEquals("user message\n\nConflicts:\n\ta\n",
1646 db.readMergeCommitMsg());
1647 }
1648 }
1649
1650 private static void setExecutable(Git git, String path, boolean executable) {
1651 FS.DETECTED.setExecute(
1652 new File(git.getRepository().getWorkTree(), path), executable);
1653 }
1654
1655 private static boolean canExecute(Git git, String path) {
1656 return FS.DETECTED.canExecute(new File(git.getRepository()
1657 .getWorkTree(), path));
1658 }
1659
1660 private static RevCommit addAllAndCommit(final Git git) throws Exception {
1661 git.add().addFilepattern(".").call();
1662 return git.commit().setMessage("message").call();
1663 }
1664
1665 private void checkMergeFailedResult(final MergeResult result,
1666 final MergeFailureReason reason,
1667 final String indexState, final File fileA) throws Exception {
1668 assertEquals(MergeStatus.FAILED, result.getMergeStatus());
1669 assertEquals(reason, result.getFailingPaths().get("a"));
1670 assertEquals("a(modified)", read(fileA));
1671 assertFalse(new File(db.getWorkTree(), "b").exists());
1672 assertEquals("c", read(new File(db.getWorkTree(), "c")));
1673 assertEquals(indexState, indexState(CONTENT));
1674 assertEquals(null, result.getConflicts());
1675 assertEquals(RepositoryState.SAFE, db.getRepositoryState());
1676 }
1677 }