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