View Javadoc
1   /*
2    * Copyright (C) 2010, Stefan Lay <stefan.lay@sap.com>
3    * Copyright (C) 2010-2014, Christian Halstrick <christian.halstrick@sap.com> and others
4    *
5    * This program and the accompanying materials are made available under the
6    * terms of the Eclipse Distribution License v. 1.0 which is available at
7    * https://www.eclipse.org/org/documents/edl-v10.php.
8    *
9    * SPDX-License-Identifier: BSD-3-Clause
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  		// no reflog entry written by merge
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  		// no reflog entry written by merge
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 				// expected this exception
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 			// Hmmm... there doesn't seem to be a way to figure out which files
432 			// had a binary conflict from a MergeResult...
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 			// @TODO fix me
728 			assertEquals(RepositoryState.SAFE, db.getRepositoryState());
729 			// test index state
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 			// We are merging a deletion into our branch
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 			// Do the opposite, be on a branch where we have deleted a file and
883 			// merge in a old commit where this file was not deleted
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 			// We are merging a deletion into our branch
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 			// We are merging a deletion into our branch
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 			// create side branch and modify "a"
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 			// delete a on master to generate conflict
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 				// merge side with master
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 				// result should be 'a' conflicting with workspace content from
1003 				// side
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 			// create side branch and modify "a"
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 			// delete a on master to generate conflict
1033 			checkoutBranch("refs/heads/master");
1034 			git.rm().addFilepattern("a").call();
1035 			git.commit().setMessage("main").call();
1036 
1037 			// merge side with master
1038 			MergeResult result = git.merge().include(secondCommit.getId())
1039 					.setStrategy(MergeStrategy.THEIRS)
1040 					.call();
1041 			assertEquals(MergeStatus.MERGED, result.getMergeStatus());
1042 
1043 			// result should be 'a'
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 			// create side branch and modify "a"
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 			// delete a on master to generate conflict
1068 			checkoutBranch("refs/heads/master");
1069 			git.rm().addFilepattern("a").call();
1070 			git.commit().setMessage("main").call();
1071 
1072 			// merge side with master
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 			// create side branch and delete "a"
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 			// update a on master to generate conflict
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 				// merge side with master
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 			// create side branch and delete "a"
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 			// update a on master to generate conflict
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 			// merge side with master
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 			// create side branch and delete "a"
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 			// update a on master to generate conflict
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 			// merge side with master
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 		// this test is essentially the same as testDeletionOnSideConflict,
1200 		// however if once rename support is added this test should result in a
1201 		// successful merge instead of a conflict
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 			// rename x to y on d1
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 			// switch branch
1321 			createBranch(initialCommit, "refs/heads/side");
1322 			checkoutBranch("refs/heads/side");
1323 			// modify file a
1324 			write(fileA, "a(side)");
1325 			writeTrashFile("b", "b");
1326 			RevCommit sideCommit = addAllAndCommit(git);
1327 
1328 			// switch branch
1329 			checkoutBranch("refs/heads/master");
1330 			writeTrashFile("c", "c");
1331 			addAllAndCommit(git);
1332 
1333 			// modify and add file a
1334 			write(fileA, "a(modified)");
1335 			git.add().addFilepattern("a").call();
1336 			// do not commit
1337 
1338 			// get current index state
1339 			String indexState = indexState(CONTENT);
1340 
1341 			// merge
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 			// switch branch
1357 			createBranch(initialCommit, "refs/heads/side");
1358 			checkoutBranch("refs/heads/side");
1359 			// modify file a
1360 			write(fileA, "a(side)");
1361 			writeTrashFile("b", "b");
1362 			RevCommit sideCommit = addAllAndCommit(git);
1363 
1364 			// switch branch
1365 			checkoutBranch("refs/heads/master");
1366 			// modify file a - this will cause a conflict during merge
1367 			write(fileA, "a(master)");
1368 			writeTrashFile("c", "c");
1369 			addAllAndCommit(git);
1370 
1371 			// modify and add file a
1372 			write(fileA, "a(modified)");
1373 			git.add().addFilepattern("a").call();
1374 			// do not commit
1375 
1376 			// get current index state
1377 			String indexState = indexState(CONTENT);
1378 
1379 			// merge
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 			// switch branch
1395 			createBranch(initialCommit, "refs/heads/side");
1396 			checkoutBranch("refs/heads/side");
1397 			// modify file a
1398 			write(fileA, "a(side)");
1399 			writeTrashFile("b", "b");
1400 			RevCommit sideCommit = addAllAndCommit(git);
1401 
1402 			// switch branch
1403 			checkoutBranch("refs/heads/master");
1404 			writeTrashFile("c", "c");
1405 			addAllAndCommit(git);
1406 
1407 			// modify file a
1408 			write(fileA, "a(modified)");
1409 			// do not add and commit
1410 
1411 			// get current index state
1412 			String indexState = indexState(CONTENT);
1413 
1414 			// merge
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 			// switch branch
1430 			createBranch(initialCommit, "refs/heads/side");
1431 			checkoutBranch("refs/heads/side");
1432 			// modify file a
1433 			write(fileA, "a(side)");
1434 			writeTrashFile("b", "b");
1435 			RevCommit sideCommit = addAllAndCommit(git);
1436 
1437 			// switch branch
1438 			checkoutBranch("refs/heads/master");
1439 			// modify file a - this will cause a conflict during merge
1440 			write(fileA, "a(master)");
1441 			writeTrashFile("c", "c");
1442 			addAllAndCommit(git);
1443 
1444 			// modify file a
1445 			write(fileA, "a(modified)");
1446 			// do not add and commit
1447 
1448 			// get current index state
1449 			String indexState = indexState(CONTENT);
1450 
1451 			// merge
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 		// Only Java6
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 			// switch branch
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 			// switch branch
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 			// merge
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 		// Only Java6 (or set x bit in index)
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 			// switch branch
1596 			createBranch(initialCommit, "refs/heads/side");
1597 			checkoutBranch("refs/heads/side");
1598 			setExecutable(git, "mergeableButDirty", true);
1599 			RevCommit sideCommit = addAllAndCommit(git);
1600 
1601 			// switch branch
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 			// merge
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()); // HEAD didn't move
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()); // HEAD didn't move
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 		// given
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 			// when
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 			// then
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 }