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