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