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