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