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