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