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