View Javadoc
1   /*
2    * Copyright (C) 2010, Christian Halstrick <christian.halstrick@sap.com>,
3    * Copyright (C) 2010-2012, Matthias Sohn <matthias.sohn@sap.com>
4    * Copyright (C) 2012, Research In Motion Limited
5    * Copyright (C) 2017, Obeo (mathieu.cartaud@obeo.fr)
6    * Copyright (C) 2018, 2022 Thomas Wolf <twolf@apache.org> and others
7    *
8    * This program and the accompanying materials are made available under the
9    * terms of the Eclipse Distribution License v. 1.0 which is available at
10   * https://www.eclipse.org/org/documents/edl-v10.php.
11   *
12   * SPDX-License-Identifier: BSD-3-Clause
13   */
14  package org.eclipse.jgit.merge;
15  
16  import static java.nio.charset.StandardCharsets.UTF_8;
17  import static java.time.Instant.EPOCH;
18  import static org.eclipse.jgit.diff.DiffAlgorithm.SupportedAlgorithm.HISTOGRAM;
19  import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFF_SECTION;
20  import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_ALGORITHM;
21  import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;
22  
23  import java.io.File;
24  import java.io.IOException;
25  import java.time.Instant;
26  import java.util.ArrayList;
27  import java.util.Arrays;
28  import java.util.Collections;
29  import java.util.HashMap;
30  import java.util.List;
31  import java.util.Map;
32  import org.eclipse.jgit.annotations.NonNull;
33  import org.eclipse.jgit.attributes.Attributes;
34  import org.eclipse.jgit.diff.DiffAlgorithm;
35  import org.eclipse.jgit.diff.DiffAlgorithm.SupportedAlgorithm;
36  import org.eclipse.jgit.diff.RawText;
37  import org.eclipse.jgit.diff.RawTextComparator;
38  import org.eclipse.jgit.diff.Sequence;
39  import org.eclipse.jgit.dircache.DirCache;
40  import org.eclipse.jgit.dircache.DirCacheBuildIterator;
41  import org.eclipse.jgit.dircache.DirCacheCheckout.CheckoutMetadata;
42  import org.eclipse.jgit.dircache.DirCacheEntry;
43  import org.eclipse.jgit.errors.BinaryBlobException;
44  import org.eclipse.jgit.lib.Config;
45  import org.eclipse.jgit.lib.Constants;
46  import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
47  import org.eclipse.jgit.lib.FileMode;
48  import org.eclipse.jgit.lib.ObjectId;
49  import org.eclipse.jgit.lib.ObjectInserter;
50  import org.eclipse.jgit.lib.ObjectLoader;
51  import org.eclipse.jgit.lib.Repository;
52  import org.eclipse.jgit.revwalk.RevTree;
53  import org.eclipse.jgit.storage.pack.PackConfig;
54  import org.eclipse.jgit.submodule.SubmoduleConflict;
55  import org.eclipse.jgit.treewalk.AbstractTreeIterator;
56  import org.eclipse.jgit.treewalk.CanonicalTreeParser;
57  import org.eclipse.jgit.treewalk.NameConflictTreeWalk;
58  import org.eclipse.jgit.treewalk.TreeWalk;
59  import org.eclipse.jgit.treewalk.WorkingTreeIterator;
60  import org.eclipse.jgit.treewalk.filter.TreeFilter;
61  import org.eclipse.jgit.util.FS;
62  import org.eclipse.jgit.util.LfsFactory;
63  import org.eclipse.jgit.util.TemporaryBuffer;
64  
65  /**
66   * A three-way merger performing a content-merge if necessary
67   */
68  public class ResolveMerger extends ThreeWayMerger {
69  
70  	/**
71  	 * If the merge fails (means: not stopped because of unresolved conflicts)
72  	 * this enum is used to explain why it failed
73  	 */
74  	public enum MergeFailureReason {
75  		/** the merge failed because of a dirty index */
76  		DIRTY_INDEX,
77  		/** the merge failed because of a dirty workingtree */
78  		DIRTY_WORKTREE,
79  		/** the merge failed because of a file could not be deleted */
80  		COULD_NOT_DELETE
81  	}
82  
83  	/**
84  	 * The tree walk which we'll iterate over to merge entries.
85  	 *
86  	 * @since 3.4
87  	 */
88  	protected NameConflictTreeWalk tw;
89  
90  	/**
91  	 * string versions of a list of commit SHA1s
92  	 *
93  	 * @since 3.0
94  	 */
95  	protected String[] commitNames;
96  
97  	/**
98  	 * Index of the base tree within the {@link #tw tree walk}.
99  	 *
100 	 * @since 3.4
101 	 */
102 	protected static final int T_BASE = 0;
103 
104 	/**
105 	 * Index of our tree in withthe {@link #tw tree walk}.
106 	 *
107 	 * @since 3.4
108 	 */
109 	protected static final int T_OURS = 1;
110 
111 	/**
112 	 * Index of their tree within the {@link #tw tree walk}.
113 	 *
114 	 * @since 3.4
115 	 */
116 	protected static final int T_THEIRS = 2;
117 
118 	/**
119 	 * Index of the index tree within the {@link #tw tree walk}.
120 	 *
121 	 * @since 3.4
122 	 */
123 	protected static final int T_INDEX = 3;
124 
125 	/**
126 	 * Index of the working directory tree within the {@link #tw tree walk}.
127 	 *
128 	 * @since 3.4
129 	 */
130 	protected static final int T_FILE = 4;
131 
132 	/**
133 	 * Handler for repository I/O actions.
134 	 *
135 	 * @since 6.3
136 	 */
137 	protected WorkTreeUpdater workTreeUpdater;
138 
139 	/**
140 	 * merge result as tree
141 	 *
142 	 * @since 3.0
143 	 */
144 	protected ObjectId resultTree;
145 
146 	/**
147 	 * Files modified during this operation. Note this list is only updated after a successful write.
148 	 */
149 	protected List<String> modifiedFiles = new ArrayList<>();
150 
151 	/**
152 	 * Paths that could not be merged by this merger because of an unsolvable
153 	 * conflict.
154 	 *
155 	 * @since 3.4
156 	 */
157 	protected List<String> unmergedPaths = new ArrayList<>();
158 
159 	/**
160 	 * Low-level textual merge results. Will be passed on to the callers in case
161 	 * of conflicts.
162 	 *
163 	 * @since 3.4
164 	 */
165 	protected Map<String, MergeResult<? extends Sequence>> mergeResults = new HashMap<>();
166 
167 	/**
168 	 * Paths for which the merge failed altogether.
169 	 *
170 	 * @since 3.4
171 	 */
172 	protected Map<String, MergeFailureReason> failingPaths = new HashMap<>();
173 
174 	/**
175 	 * Updated as we merge entries of the tree walk. Tells us whether we should
176 	 * recurse into the entry if it is a subtree.
177 	 *
178 	 * @since 3.4
179 	 */
180 	protected boolean enterSubtree;
181 
182 	/**
183 	 * Set to true if this merge should work in-memory. The repos dircache and
184 	 * workingtree are not touched by this method. Eventually needed files are
185 	 * created as temporary files and a new empty, in-memory dircache will be
186 	 * used instead the repo's one. Often used for bare repos where the repo
187 	 * doesn't even have a workingtree and dircache.
188 	 * @since 3.0
189 	 */
190 	protected boolean inCore;
191 
192 	/**
193 	 * Directory cache
194 	 * @since 3.0
195 	 */
196 	protected DirCache dircache;
197 
198 	/**
199 	 * The iterator to access the working tree. If set to <code>null</code> this
200 	 * merger will not touch the working tree.
201 	 * @since 3.0
202 	 */
203 	protected WorkingTreeIterator workingTreeIterator;
204 
205 	/**
206 	 * our merge algorithm
207 	 * @since 3.0
208 	 */
209 	protected MergeAlgorithm mergeAlgorithm;
210 
211 	/**
212 	 * The {@link ContentMergeStrategy} to use for "resolve" and "recursive"
213 	 * merges.
214 	 */
215 	@NonNull
216 	private ContentMergeStrategy contentStrategy = ContentMergeStrategy.CONFLICT;
217 
218 	private static MergeAlgorithm getMergeAlgorithm(Config config) {
219 		SupportedAlgorithm diffAlg = config.getEnum(
220 				CONFIG_DIFF_SECTION, null, CONFIG_KEY_ALGORITHM,
221 				HISTOGRAM);
222 		return new MergeAlgorithm(DiffAlgorithm.getAlgorithm(diffAlg));
223 	}
224 
225 	private static String[] defaultCommitNames() {
226 		return new String[]{"BASE", "OURS", "THEIRS"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
227 	}
228 
229 	private static final Attributes NO_ATTRIBUTES = new Attributes();
230 
231 	/**
232 	 * Constructor for ResolveMerger.
233 	 *
234 	 * @param local
235 	 *            the {@link org.eclipse.jgit.lib.Repository}.
236 	 * @param inCore
237 	 *            a boolean.
238 	 */
239 	protected ResolveMerger(Repository local, boolean inCore) {
240 		super(local);
241 		Config config = local.getConfig();
242 		mergeAlgorithm = getMergeAlgorithm(config);
243 		commitNames = defaultCommitNames();
244 		this.inCore = inCore;
245 	}
246 
247 	/**
248 	 * Constructor for ResolveMerger.
249 	 *
250 	 * @param local
251 	 *            the {@link org.eclipse.jgit.lib.Repository}.
252 	 */
253 	protected ResolveMerger(Repository local) {
254 		this(local, false);
255 	}
256 
257 	/**
258 	 * Constructor for ResolveMerger.
259 	 *
260 	 * @param inserter
261 	 *            an {@link org.eclipse.jgit.lib.ObjectInserter} object.
262 	 * @param config
263 	 *            the repository configuration
264 	 * @since 4.8
265 	 */
266 	protected ResolveMerger(ObjectInserter inserter, Config config) {
267 		super(inserter);
268 		mergeAlgorithm = getMergeAlgorithm(config);
269 		commitNames = defaultCommitNames();
270 		inCore = true;
271 	}
272 
273 	/**
274 	 * Retrieves the content merge strategy for content conflicts.
275 	 *
276 	 * @return the {@link ContentMergeStrategy} in effect
277 	 * @since 5.12
278 	 */
279 	@NonNull
280 	public ContentMergeStrategy getContentMergeStrategy() {
281 		return contentStrategy;
282 	}
283 
284 	/**
285 	 * Sets the content merge strategy for content conflicts.
286 	 *
287 	 * @param strategy
288 	 *            {@link ContentMergeStrategy} to use
289 	 * @since 5.12
290 	 */
291 	public void setContentMergeStrategy(ContentMergeStrategy strategy) {
292 		contentStrategy = strategy == null ? ContentMergeStrategy.CONFLICT
293 				: strategy;
294 	}
295 
296 	/** {@inheritDoc} */
297 	@Override
298 	protected boolean mergeImpl() throws IOException {
299 		return mergeTrees(mergeBase(), sourceTrees[0], sourceTrees[1],
300 				false);
301 	}
302 
303 	/**
304 	 * adds a new path with the specified stage to the index builder
305 	 *
306 	 * @param path
307 	 * @param p
308 	 * @param stage
309 	 * @param lastMod
310 	 * @param len
311 	 * @return the entry which was added to the index
312 	 */
313 	private DirCacheEntry add(byte[] path, CanonicalTreeParser p, int stage,
314 			Instant lastMod, long len) {
315 		if (p != null && !p.getEntryFileMode().equals(FileMode.TREE)) {
316 			return workTreeUpdater.addExistingToIndex(p.getEntryObjectId(), path,
317 					p.getEntryFileMode(), stage,
318 					lastMod, (int) len);
319 		}
320 		return null;
321 	}
322 
323 	/**
324 	 * Adds the conflict stages for the current path of {@link #tw} to the index
325 	 * builder and returns the "theirs" stage; if present.
326 	 *
327 	 * @param base
328 	 *            of the conflict
329 	 * @param ours
330 	 *            of the conflict
331 	 * @param theirs
332 	 *            of the conflict
333 	 * @return the {@link DirCacheEntry} for the "theirs" stage, or {@code null}
334 	 */
335 	private DirCacheEntry addConflict(CanonicalTreeParser base,
336 			CanonicalTreeParser ours, CanonicalTreeParser theirs) {
337 		add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
338 		add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0);
339 		return add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH, 0);
340 	}
341 
342 	/**
343 	 * adds a entry to the index builder which is a copy of the specified
344 	 * DirCacheEntry
345 	 *
346 	 * @param e
347 	 *            the entry which should be copied
348 	 *
349 	 * @return the entry which was added to the index
350 	 */
351 	private DirCacheEntry keep(DirCacheEntry e) {
352 		return workTreeUpdater.addExistingToIndex(e.getObjectId(), e.getRawPath(), e.getFileMode(),
353 				e.getStage(), e.getLastModifiedInstant(), e.getLength());
354 	}
355 
356 	/**
357 	 * Adds a {@link DirCacheEntry} for direct checkout and remembers its
358 	 * {@link CheckoutMetadata}.
359 	 *
360 	 * @param path
361 	 *            of the entry
362 	 * @param entry
363 	 *            to add
364 	 * @param attributes
365 	 *            the {@link Attributes} of the trees
366 	 * @throws IOException
367 	 *             if the {@link CheckoutMetadata} cannot be determined
368 	 * @since 6.1
369 	 */
370 	protected void addToCheckout(String path, DirCacheEntry entry,
371 			Attributes[] attributes)
372 			throws IOException {
373 		EolStreamType cleanupStreamType = workTreeUpdater.detectCheckoutStreamType(attributes[T_OURS]);
374 		String cleanupSmudgeCommand = tw.getSmudgeCommand(attributes[T_OURS]);
375 		EolStreamType checkoutStreamType = workTreeUpdater.detectCheckoutStreamType(attributes[T_THEIRS]);
376 		String checkoutSmudgeCommand = tw.getSmudgeCommand(attributes[T_THEIRS]);
377 		workTreeUpdater.addToCheckout(path, entry, cleanupStreamType, cleanupSmudgeCommand,
378 				checkoutStreamType, checkoutSmudgeCommand);
379 	}
380 
381 	/**
382 	 * Remember a path for deletion, and remember its {@link CheckoutMetadata}
383 	 * in case it has to be restored in the cleanUp.
384 	 *
385 	 * @param path
386 	 *            of the entry
387 	 * @param isFile
388 	 *            whether it is a file
389 	 * @param attributes
390 	 *            to use for determining the {@link CheckoutMetadata}
391 	 * @throws IOException
392 	 *             if the {@link CheckoutMetadata} cannot be determined
393 	 * @since 5.1
394 	 */
395 	protected void addDeletion(String path, boolean isFile,
396 			Attributes attributes) throws IOException {
397 		if (db == null || nonNullRepo().isBare() || !isFile)
398 			return;
399 
400 		File file = new File(nonNullRepo().getWorkTree(), path);
401 		EolStreamType streamType = workTreeUpdater.detectCheckoutStreamType(attributes);
402 		String smudgeCommand = tw.getSmudgeCommand(attributes);
403 		workTreeUpdater.deleteFile(path, file, streamType, smudgeCommand);
404 	}
405 
406 	/**
407 	 * Processes one path and tries to merge taking git attributes in account.
408 	 * This method will do all trivial (not content) merges and will also detect
409 	 * if a merge will fail. The merge will fail when one of the following is
410 	 * true
411 	 * <ul>
412 	 * <li>the index entry does not match the entry in ours. When merging one
413 	 * branch into the current HEAD, ours will point to HEAD and theirs will
414 	 * point to the other branch. It is assumed that the index matches the HEAD
415 	 * because it will only not match HEAD if it was populated before the merge
416 	 * operation. But the merge commit should not accidentally contain
417 	 * modifications done before the merge. Check the <a href=
418 	 * "http://www.kernel.org/pub/software/scm/git/docs/git-read-tree.html#_3_way_merge"
419 	 * >git read-tree</a> documentation for further explanations.</li>
420 	 * <li>A conflict was detected and the working-tree file is dirty. When a
421 	 * conflict is detected the content-merge algorithm will try to write a
422 	 * merged version into the working-tree. If the file is dirty we would
423 	 * override unsaved data.</li>
424 	 * </ul>
425 	 *
426 	 * @param base
427 	 *            the common base for ours and theirs
428 	 * @param ours
429 	 *            the ours side of the merge. When merging a branch into the
430 	 *            HEAD ours will point to HEAD
431 	 * @param theirs
432 	 *            the theirs side of the merge. When merging a branch into the
433 	 *            current HEAD theirs will point to the branch which is merged
434 	 *            into HEAD.
435 	 * @param index
436 	 *            the index entry
437 	 * @param work
438 	 *            the file in the working tree
439 	 * @param ignoreConflicts
440 	 *            see
441 	 *            {@link org.eclipse.jgit.merge.ResolveMerger#mergeTrees(AbstractTreeIterator, RevTree, RevTree, boolean)}
442 	 * @param attributes
443 	 *            the {@link Attributes} for the three trees
444 	 * @return <code>false</code> if the merge will fail because the index entry
445 	 *         didn't match ours or the working-dir file was dirty and a
446 	 *         conflict occurred
447 	 * @throws java.io.IOException
448 	 * @since 6.1
449 	 */
450 	protected boolean processEntry(CanonicalTreeParser base,
451 			CanonicalTreeParser ours, CanonicalTreeParser theirs,
452 			DirCacheBuildIterator index, WorkingTreeIterator work,
453 			boolean ignoreConflicts, Attributes[] attributes)
454 			throws IOException {
455 		enterSubtree = true;
456 		final int modeO = tw.getRawMode(T_OURS);
457 		final int modeT = tw.getRawMode(T_THEIRS);
458 		final int modeB = tw.getRawMode(T_BASE);
459 		boolean gitLinkMerging = isGitLink(modeO) || isGitLink(modeT)
460 				|| isGitLink(modeB);
461 		if (modeO == 0 && modeT == 0 && modeB == 0) {
462 			// File is either untracked or new, staged but uncommitted
463 			return true;
464 		}
465 
466 		if (isIndexDirty()) {
467 			return false;
468 		}
469 
470 		DirCacheEntry ourDce = null;
471 
472 		if (index == null || index.getDirCacheEntry() == null) {
473 			// create a fake DCE, but only if ours is valid. ours is kept only
474 			// in case it is valid, so a null ourDce is ok in all other cases.
475 			if (nonTree(modeO)) {
476 				ourDce = new DirCacheEntry(tw.getRawPath());
477 				ourDce.setObjectId(tw.getObjectId(T_OURS));
478 				ourDce.setFileMode(tw.getFileMode(T_OURS));
479 			}
480 		} else {
481 			ourDce = index.getDirCacheEntry();
482 		}
483 
484 		if (nonTree(modeO) && nonTree(modeT) && tw.idEqual(T_OURS, T_THEIRS)) {
485 			// OURS and THEIRS have equal content. Check the file mode
486 			if (modeO == modeT) {
487 				// content and mode of OURS and THEIRS are equal: it doesn't
488 				// matter which one we choose. OURS is chosen. Since the index
489 				// is clean (the index matches already OURS) we can keep the existing one
490 				keep(ourDce);
491 				// no checkout needed!
492 				return true;
493 			}
494 			// same content but different mode on OURS and THEIRS.
495 			// Try to merge the mode and report an error if this is
496 			// not possible.
497 			int newMode = mergeFileModes(modeB, modeO, modeT);
498 			if (newMode != FileMode.MISSING.getBits()) {
499 				if (newMode == modeO) {
500 					// ours version is preferred
501 					keep(ourDce);
502 				} else {
503 					// the preferred version THEIRS has a different mode
504 					// than ours. Check it out!
505 					if (isWorktreeDirty(work, ourDce)) {
506 						return false;
507 					}
508 					// we know about length and lastMod only after we have
509 					// written the new content.
510 					// This will happen later. Set these values to 0 for know.
511 					DirCacheEntry e = add(tw.getRawPath(), theirs,
512 							DirCacheEntry.STAGE_0, EPOCH, 0);
513 					addToCheckout(tw.getPathString(), e, attributes);
514 				}
515 				return true;
516 			}
517 			if (!ignoreConflicts) {
518 				// FileModes are not mergeable. We found a conflict on modes.
519 				// For conflicting entries we don't know lastModified and
520 				// length.
521 				// This path can be skipped on ignoreConflicts, so the caller
522 				// could use virtual commit.
523 				addConflict(base, ours, theirs);
524 				unmergedPaths.add(tw.getPathString());
525 				mergeResults.put(tw.getPathString(),
526 						new MergeResult<>(Collections.emptyList()));
527 			}
528 			return true;
529 		}
530 
531 		if (modeB == modeT && tw.idEqual(T_BASE, T_THEIRS)) {
532 			// THEIRS was not changed compared to BASE. All changes must be in
533 			// OURS. OURS is chosen. We can keep the existing entry.
534 			if (ourDce != null) {
535 				keep(ourDce);
536 			}
537 			// no checkout needed!
538 			return true;
539 		}
540 
541 		if (modeB == modeO && tw.idEqual(T_BASE, T_OURS)) {
542 			// OURS was not changed compared to BASE. All changes must be in
543 			// THEIRS. THEIRS is chosen.
544 
545 			// Check worktree before checking out THEIRS
546 			if (isWorktreeDirty(work, ourDce)) {
547 				return false;
548 			}
549 			if (nonTree(modeT)) {
550 				// we know about length and lastMod only after we have written
551 				// the new content.
552 				// This will happen later. Set these values to 0 for know.
553 				DirCacheEntry e = add(tw.getRawPath(), theirs,
554 						DirCacheEntry.STAGE_0, EPOCH, 0);
555 				if (e != null) {
556 					addToCheckout(tw.getPathString(), e, attributes);
557 				}
558 				return true;
559 			}
560 			// we want THEIRS ... but THEIRS contains a folder or the
561 			// deletion of the path. Delete what's in the working tree,
562 			// which we know to be clean.
563 			if (tw.getTreeCount() > T_FILE && tw.getRawMode(T_FILE) == 0) {
564 				// Not present in working tree, so nothing to delete
565 				return true;
566 			}
567 			if (modeT != 0 && modeT == modeB) {
568 				// Base, ours, and theirs all contain a folder: don't delete
569 				return true;
570 			}
571 			addDeletion(tw.getPathString(), nonTree(modeO), attributes[T_OURS]);
572 			return true;
573 		}
574 
575 		if (tw.isSubtree()) {
576 			// file/folder conflicts: here I want to detect only file/folder
577 			// conflict between ours and theirs. file/folder conflicts between
578 			// base/index/workingTree and something else are not relevant or
579 			// detected later
580 			if (nonTree(modeO) != nonTree(modeT)) {
581 				if (ignoreConflicts) {
582 					// In case of merge failures, ignore this path instead of reporting unmerged, so
583 					// a caller can use virtual commit. This will not result in files with conflict
584 					// markers in the index/working tree. The actual diff on the path will be
585 					// computed directly on children.
586 					enterSubtree = false;
587 					return true;
588 				}
589 				if (nonTree(modeB)) {
590 					add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
591 				}
592 				if (nonTree(modeO)) {
593 					add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0);
594 				}
595 				if (nonTree(modeT)) {
596 					add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH, 0);
597 				}
598 				unmergedPaths.add(tw.getPathString());
599 				enterSubtree = false;
600 				return true;
601 			}
602 
603 			// ours and theirs are both folders or both files (and treewalk
604 			// tells us we are in a subtree because of index or working-dir).
605 			// If they are both folders no content-merge is required - we can
606 			// return here.
607 			if (!nonTree(modeO)) {
608 				return true;
609 			}
610 
611 			// ours and theirs are both files, just fall out of the if block
612 			// and do the content merge
613 		}
614 
615 		if (nonTree(modeO) && nonTree(modeT)) {
616 			// Check worktree before modifying files
617 			boolean worktreeDirty = isWorktreeDirty(work, ourDce);
618 			if (!attributes[T_OURS].canBeContentMerged() && worktreeDirty) {
619 				return false;
620 			}
621 
622 			if (gitLinkMerging && ignoreConflicts) {
623 				// Always select 'ours' in case of GITLINK merge failures so
624 				// a caller can use virtual commit.
625 				add(tw.getRawPath(), ours, DirCacheEntry.STAGE_0, EPOCH, 0);
626 				return true;
627 			} else if (gitLinkMerging) {
628 				addConflict(base, ours, theirs);
629 				MergeResult<SubmoduleConflict> result = createGitLinksMergeResult(
630 						base, ours, theirs);
631 				result.setContainsConflicts(true);
632 				mergeResults.put(tw.getPathString(), result);
633 				unmergedPaths.add(tw.getPathString());
634 				return true;
635 			} else if (!attributes[T_OURS].canBeContentMerged()) {
636 				// File marked as binary
637 				switch (getContentMergeStrategy()) {
638 					case OURS:
639 						keep(ourDce);
640 						return true;
641 					case THEIRS:
642 						DirCacheEntry theirEntry = add(tw.getRawPath(), theirs,
643 								DirCacheEntry.STAGE_0, EPOCH, 0);
644 						addToCheckout(tw.getPathString(), theirEntry, attributes);
645 						return true;
646 					default:
647 						break;
648 				}
649 				addConflict(base, ours, theirs);
650 
651 				// attribute merge issues are conflicts but not failures
652 				unmergedPaths.add(tw.getPathString());
653 				return true;
654 			}
655 
656 			// Check worktree before modifying files
657 			if (worktreeDirty) {
658 				return false;
659 			}
660 
661 			MergeResult<RawText> result = null;
662 			boolean hasSymlink = FileMode.SYMLINK.equals(modeO)
663 					|| FileMode.SYMLINK.equals(modeT);
664 			if (!hasSymlink) {
665 				try {
666 					result = contentMerge(base, ours, theirs, attributes,
667 							getContentMergeStrategy());
668 				} catch (BinaryBlobException e) {
669 					// result == null
670 				}
671 			}
672 			if (result == null) {
673 				switch (getContentMergeStrategy()) {
674 				case OURS:
675 					keep(ourDce);
676 					return true;
677 				case THEIRS:
678 					DirCacheEntry e = add(tw.getRawPath(), theirs,
679 							DirCacheEntry.STAGE_0, EPOCH, 0);
680 					if (e != null) {
681 						addToCheckout(tw.getPathString(), e, attributes);
682 					}
683 					return true;
684 				default:
685 					result = new MergeResult<>(Collections.emptyList());
686 					result.setContainsConflicts(true);
687 					break;
688 				}
689 			}
690 			if (ignoreConflicts) {
691 				result.setContainsConflicts(false);
692 			}
693 			String currentPath = tw.getPathString();
694 			if (hasSymlink) {
695 				if (ignoreConflicts) {
696 					if (((modeT & FileMode.TYPE_MASK) == FileMode.TYPE_FILE)) {
697 						DirCacheEntry e = add(tw.getRawPath(), theirs,
698 								DirCacheEntry.STAGE_0, EPOCH, 0);
699 						addToCheckout(currentPath, e, attributes);
700 					} else {
701 						keep(ourDce);
702 					}
703 				} else {
704 					// Record the conflict
705 					DirCacheEntry e = addConflict(base, ours, theirs);
706 					mergeResults.put(currentPath, result);
707 					// If theirs is a file, check it out. In link/file
708 					// conflicts, C git prefers the file.
709 					if (((modeT & FileMode.TYPE_MASK) == FileMode.TYPE_FILE)
710 							&& e != null) {
711 						addToCheckout(currentPath, e, attributes);
712 					}
713 				}
714 			} else {
715 				updateIndex(base, ours, theirs, result, attributes[T_OURS]);
716 			}
717 			if (result.containsConflicts() && !ignoreConflicts) {
718 				unmergedPaths.add(currentPath);
719 			}
720 			workTreeUpdater.markAsModified(currentPath);
721 			// Entry is null - only adds the metadata.
722 			addToCheckout(currentPath, null, attributes);
723 		} else if (modeO != modeT) {
724 			// OURS or THEIRS has been deleted
725 			if (((modeO != 0 && !tw.idEqual(T_BASE, T_OURS)) || (modeT != 0 && !tw
726 					.idEqual(T_BASE, T_THEIRS)))) {
727 				if (gitLinkMerging && ignoreConflicts) {
728 					add(tw.getRawPath(), ours, DirCacheEntry.STAGE_0, EPOCH, 0);
729 				} else if (gitLinkMerging) {
730 					addConflict(base, ours, theirs);
731 					MergeResult<SubmoduleConflict> result = createGitLinksMergeResult(
732 							base, ours, theirs);
733 					result.setContainsConflicts(true);
734 					mergeResults.put(tw.getPathString(), result);
735 					unmergedPaths.add(tw.getPathString());
736 				} else {
737 					boolean isSymLink = ((modeO | modeT)
738 							& FileMode.TYPE_MASK) == FileMode.TYPE_SYMLINK;
739 					// Content merge strategy does not apply to delete-modify
740 					// conflicts!
741 					MergeResult<RawText> result;
742 					if (isSymLink) {
743 						// No need to do a content merge
744 						result = new MergeResult<>(Collections.emptyList());
745 						result.setContainsConflicts(true);
746 					} else {
747 						try {
748 							result = contentMerge(base, ours, theirs,
749 									attributes, ContentMergeStrategy.CONFLICT);
750 						} catch (BinaryBlobException e) {
751 							result = new MergeResult<>(Collections.emptyList());
752 							result.setContainsConflicts(true);
753 						}
754 					}
755 					if (ignoreConflicts) {
756 						result.setContainsConflicts(false);
757 						if (isSymLink) {
758 							if (modeO != 0) {
759 								keep(ourDce);
760 							} else {
761 								// Check out theirs
762 								if (isWorktreeDirty(work, ourDce)) {
763 									return false;
764 								}
765 								DirCacheEntry e = add(tw.getRawPath(), theirs,
766 										DirCacheEntry.STAGE_0, EPOCH, 0);
767 								if (e != null) {
768 									addToCheckout(tw.getPathString(), e,
769 											attributes);
770 								}
771 							}
772 						} else {
773 							// In case a conflict is detected the working tree
774 							// file is again filled with new content (containing
775 							// conflict markers). But also stage 0 of the index
776 							// is filled with that content.
777 							updateIndex(base, ours, theirs, result,
778 									attributes[T_OURS]);
779 						}
780 					} else {
781 						DirCacheEntry e = addConflict(base, ours, theirs);
782 
783 						// OURS was deleted checkout THEIRS
784 						if (modeO == 0) {
785 							// Check worktree before checking out THEIRS
786 							if (isWorktreeDirty(work, ourDce)) {
787 								return false;
788 							}
789 							if (nonTree(modeT) && e != null) {
790 								addToCheckout(tw.getPathString(), e,
791 										attributes);
792 							}
793 						}
794 
795 						unmergedPaths.add(tw.getPathString());
796 
797 						// generate a MergeResult for the deleted file
798 						mergeResults.put(tw.getPathString(), result);
799 					}
800 				}
801 			}
802 		}
803 		return true;
804 	}
805 
806 	private static MergeResult<SubmoduleConflict> createGitLinksMergeResult(
807 			CanonicalTreeParser base, CanonicalTreeParser ours,
808 			CanonicalTreeParser theirs) {
809 		return new MergeResult<>(Arrays.asList(
810 				new SubmoduleConflict(
811 						base == null ? null : base.getEntryObjectId()),
812 				new SubmoduleConflict(
813 						ours == null ? null : ours.getEntryObjectId()),
814 				new SubmoduleConflict(
815 						theirs == null ? null : theirs.getEntryObjectId())));
816 	}
817 
818 	/**
819 	 * Does the content merge. The three texts base, ours and theirs are
820 	 * specified with {@link CanonicalTreeParser}. If any of the parsers is
821 	 * specified as <code>null</code> then an empty text will be used instead.
822 	 *
823 	 * @param base
824 	 * @param ours
825 	 * @param theirs
826 	 * @param attributes
827 	 * @param strategy
828 	 *
829 	 * @return the result of the content merge
830 	 * @throws BinaryBlobException
831 	 *             if any of the blobs looks like a binary blob
832 	 * @throws IOException
833 	 */
834 	private MergeResult<RawText> contentMerge(CanonicalTreeParser base,
835 			CanonicalTreeParser ours, CanonicalTreeParser theirs,
836 			Attributes[] attributes, ContentMergeStrategy strategy)
837 			throws BinaryBlobException, IOException {
838 		// TW: The attributes here are used to determine the LFS smudge filter.
839 		// Is doing a content merge on LFS items really a good idea??
840 		RawText baseText = base == null ? RawText.EMPTY_TEXT
841 				: getRawText(base.getEntryObjectId(), attributes[T_BASE]);
842 		RawText ourText = ours == null ? RawText.EMPTY_TEXT
843 				: getRawText(ours.getEntryObjectId(), attributes[T_OURS]);
844 		RawText theirsText = theirs == null ? RawText.EMPTY_TEXT
845 				: getRawText(theirs.getEntryObjectId(), attributes[T_THEIRS]);
846 		mergeAlgorithm.setContentMergeStrategy(strategy);
847 		return mergeAlgorithm.merge(RawTextComparator.DEFAULT, baseText,
848 				ourText, theirsText);
849 	}
850 
851 	private boolean isIndexDirty() {
852 		if (inCore) {
853 			return false;
854 		}
855 
856 		final int modeI = tw.getRawMode(T_INDEX);
857 		final int modeO = tw.getRawMode(T_OURS);
858 
859 		// Index entry has to match ours to be considered clean
860 		final boolean isDirty = nonTree(modeI)
861 				&& !(modeO == modeI && tw.idEqual(T_INDEX, T_OURS));
862 		if (isDirty) {
863 			failingPaths
864 					.put(tw.getPathString(), MergeFailureReason.DIRTY_INDEX);
865 		}
866 		return isDirty;
867 	}
868 
869 	private boolean isWorktreeDirty(WorkingTreeIterator work,
870 			DirCacheEntry ourDce) throws IOException {
871 		if (work == null) {
872 			return false;
873 		}
874 
875 		final int modeF = tw.getRawMode(T_FILE);
876 		final int modeO = tw.getRawMode(T_OURS);
877 
878 		// Worktree entry has to match ours to be considered clean
879 		boolean isDirty;
880 		if (ourDce != null) {
881 			isDirty = work.isModified(ourDce, true, reader);
882 		} else {
883 			isDirty = work.isModeDifferent(modeO);
884 			if (!isDirty && nonTree(modeF)) {
885 				isDirty = !tw.idEqual(T_FILE, T_OURS);
886 			}
887 		}
888 
889 		// Ignore existing empty directories
890 		if (isDirty && modeF == FileMode.TYPE_TREE
891 				&& modeO == FileMode.TYPE_MISSING) {
892 			isDirty = false;
893 		}
894 		if (isDirty) {
895 			failingPaths.put(tw.getPathString(),
896 					MergeFailureReason.DIRTY_WORKTREE);
897 		}
898 		return isDirty;
899 	}
900 
901 	/**
902 	 * Updates the index after a content merge has happened. If no conflict has
903 	 * occurred this includes persisting the merged content to the object
904 	 * database. In case of conflicts this method takes care to write the
905 	 * correct stages to the index.
906 	 *
907 	 * @param base
908 	 * @param ours
909 	 * @param theirs
910 	 * @param result
911 	 * @param attributes
912 	 * @throws IOException
913 	 */
914 	private void updateIndex(CanonicalTreeParser base,
915 			CanonicalTreeParser ours, CanonicalTreeParser theirs,
916 			MergeResult<RawText> result, Attributes attributes)
917 			throws IOException {
918 		TemporaryBuffer rawMerged = null;
919 		try {
920 			rawMerged = doMerge(result);
921 			File mergedFile = inCore ? null
922 					: writeMergedFile(rawMerged, attributes);
923 			if (result.containsConflicts()) {
924 				// A conflict occurred, the file will contain conflict markers
925 				// the index will be populated with the three stages and the
926 				// workdir (if used) contains the halfway merged content.
927 				addConflict(base, ours, theirs);
928 				mergeResults.put(tw.getPathString(), result);
929 				return;
930 			}
931 
932 			// No conflict occurred, the file will contain fully merged content.
933 			// The index will be populated with the new merged version.
934 			Instant lastModified = mergedFile == null ? null
935 					: nonNullRepo().getFS().lastModifiedInstant(mergedFile);
936 			// Set the mode for the new content. Fall back to REGULAR_FILE if
937 			// we can't merge modes of OURS and THEIRS.
938 			int newMode = mergeFileModes(tw.getRawMode(0), tw.getRawMode(1),
939 					tw.getRawMode(2));
940 			FileMode mode = newMode == FileMode.MISSING.getBits()
941 					? FileMode.REGULAR_FILE : FileMode.fromBits(newMode);
942 			workTreeUpdater.insertToIndex(rawMerged.openInputStream(),
943 					tw.getPathString().getBytes(UTF_8), mode,
944 					DirCacheEntry.STAGE_0, lastModified,
945 					(int) rawMerged.length(),
946 					attributes.get(Constants.ATTR_MERGE));
947 		} finally {
948 			if (rawMerged != null) {
949 				rawMerged.destroy();
950 			}
951 		}
952 	}
953 
954 	/**
955 	 * Writes merged file content to the working tree.
956 	 *
957 	 * @param rawMerged
958 	 *            the raw merged content
959 	 * @param attributes
960 	 *            the files .gitattributes entries
961 	 * @return the working tree file to which the merged content was written.
962 	 * @throws IOException
963 	 */
964 	private File writeMergedFile(TemporaryBuffer rawMerged,
965 			Attributes attributes)
966 			throws IOException {
967 		File workTree = nonNullRepo().getWorkTree();
968 		FS fs = nonNullRepo().getFS();
969 		File of = new File(workTree, tw.getPathString());
970 		File parentFolder = of.getParentFile();
971 		EolStreamType eol = workTreeUpdater.detectCheckoutStreamType(attributes);
972 		if (!fs.exists(parentFolder)) {
973 			parentFolder.mkdirs();
974 		}
975 		workTreeUpdater.updateFileWithContent(rawMerged::openInputStream,
976 				eol, tw.getSmudgeCommand(attributes), of.getPath(), of);
977 		return of;
978 	}
979 
980 	private TemporaryBuffer doMerge(MergeResult<RawText> result)
981 			throws IOException {
982 		TemporaryBuffer.LocalFile buf = new TemporaryBuffer.LocalFile(
983 				db != null ? nonNullRepo().getDirectory() : null, workTreeUpdater.getInCoreFileSizeLimit());
984 		boolean success = false;
985 		try {
986 			new MergeFormatter().formatMerge(buf, result,
987 					Arrays.asList(commitNames), UTF_8);
988 			buf.close();
989 			success = true;
990 		} finally {
991 			if (!success) {
992 				buf.destroy();
993 			}
994 		}
995 		return buf;
996 	}
997 
998 	/**
999 	 * Try to merge filemodes. If only ours or theirs have changed the mode
1000 	 * (compared to base) we choose that one. If ours and theirs have equal
1001 	 * modes return that one. If also that is not the case the modes are not
1002 	 * mergeable. Return {@link FileMode#MISSING} int that case.
1003 	 *
1004 	 * @param modeB
1005 	 *            filemode found in BASE
1006 	 * @param modeO
1007 	 *            filemode found in OURS
1008 	 * @param modeT
1009 	 *            filemode found in THEIRS
1010 	 *
1011 	 * @return the merged filemode or {@link FileMode#MISSING} in case of a
1012 	 *         conflict
1013 	 */
1014 	private int mergeFileModes(int modeB, int modeO, int modeT) {
1015 		if (modeO == modeT) {
1016 			return modeO;
1017 		}
1018 		if (modeB == modeO) {
1019 			// Base equal to Ours -> chooses Theirs if that is not missing
1020 			return (modeT == FileMode.MISSING.getBits()) ? modeO : modeT;
1021 		}
1022 		if (modeB == modeT) {
1023 			// Base equal to Theirs -> chooses Ours if that is not missing
1024 			return (modeO == FileMode.MISSING.getBits()) ? modeT : modeO;
1025 		}
1026 		return FileMode.MISSING.getBits();
1027 	}
1028 
1029 	private RawText getRawText(ObjectId id,
1030 			Attributes attributes)
1031 			throws IOException, BinaryBlobException {
1032 		if (id.equals(ObjectId.zeroId())) {
1033 			return new RawText(new byte[]{});
1034 		}
1035 
1036 		ObjectLoader loader = LfsFactory.getInstance().applySmudgeFilter(
1037 				getRepository(), reader.open(id, OBJ_BLOB),
1038 				attributes.get(Constants.ATTR_MERGE));
1039 		int threshold = PackConfig.DEFAULT_BIG_FILE_THRESHOLD;
1040 		return RawText.load(loader, threshold);
1041 	}
1042 
1043 	private static boolean nonTree(int mode) {
1044 		return mode != 0 && !FileMode.TREE.equals(mode);
1045 	}
1046 
1047 	private static boolean isGitLink(int mode) {
1048 		return FileMode.GITLINK.equals(mode);
1049 	}
1050 
1051 	/** {@inheritDoc} */
1052 	@Override
1053 	public ObjectId getResultTreeId() {
1054 		return (resultTree == null) ? null : resultTree.toObjectId();
1055 	}
1056 
1057 	/**
1058 	 * Set the names of the commits as they would appear in conflict markers
1059 	 *
1060 	 * @param commitNames
1061 	 *            the names of the commits as they would appear in conflict
1062 	 *            markers
1063 	 */
1064 	public void setCommitNames(String[] commitNames) {
1065 		this.commitNames = commitNames;
1066 	}
1067 
1068 	/**
1069 	 * Get the names of the commits as they would appear in conflict markers.
1070 	 *
1071 	 * @return the names of the commits as they would appear in conflict
1072 	 *         markers.
1073 	 */
1074 	public String[] getCommitNames() {
1075 		return commitNames;
1076 	}
1077 
1078 	/**
1079 	 * Get the paths with conflicts. This is a subset of the files listed by
1080 	 * {@link #getModifiedFiles()}
1081 	 *
1082 	 * @return the paths with conflicts. This is a subset of the files listed by
1083 	 *         {@link #getModifiedFiles()}
1084 	 */
1085 	public List<String> getUnmergedPaths() {
1086 		return unmergedPaths;
1087 	}
1088 
1089 	/**
1090 	 * Get the paths of files which have been modified by this merge.
1091 	 *
1092 	 * @return the paths of files which have been modified by this merge. A file
1093 	 *         will be modified if a content-merge works on this path or if the
1094 	 *         merge algorithm decides to take the theirs-version. This is a
1095 	 *         superset of the files listed by {@link #getUnmergedPaths()}.
1096 	 */
1097 	public List<String> getModifiedFiles() {
1098 		return workTreeUpdater != null ? workTreeUpdater.getModifiedFiles() : modifiedFiles;
1099 	}
1100 
1101 	/**
1102 	 * Get a map which maps the paths of files which have to be checked out
1103 	 * because the merge created new fully-merged content for this file into the
1104 	 * index.
1105 	 *
1106 	 * @return a map which maps the paths of files which have to be checked out
1107 	 *         because the merge created new fully-merged content for this file
1108 	 *         into the index. This means: the merge wrote a new stage 0 entry
1109 	 *         for this path.
1110 	 */
1111 	public Map<String, DirCacheEntry> getToBeCheckedOut() {
1112 		return workTreeUpdater.getToBeCheckedOut();
1113 	}
1114 
1115 	/**
1116 	 * Get the mergeResults
1117 	 *
1118 	 * @return the mergeResults
1119 	 */
1120 	public Map<String, MergeResult<? extends Sequence>> getMergeResults() {
1121 		return mergeResults;
1122 	}
1123 
1124 	/**
1125 	 * Get list of paths causing this merge to fail (not stopped because of a
1126 	 * conflict).
1127 	 *
1128 	 * @return lists paths causing this merge to fail (not stopped because of a
1129 	 *         conflict). <code>null</code> is returned if this merge didn't
1130 	 *         fail.
1131 	 */
1132 	public Map<String, MergeFailureReason> getFailingPaths() {
1133 		return failingPaths.isEmpty() ? null : failingPaths;
1134 	}
1135 
1136 	/**
1137 	 * Returns whether this merge failed (i.e. not stopped because of a
1138 	 * conflict)
1139 	 *
1140 	 * @return <code>true</code> if a failure occurred, <code>false</code>
1141 	 *         otherwise
1142 	 */
1143 	public boolean failed() {
1144 		return !failingPaths.isEmpty();
1145 	}
1146 
1147 	/**
1148 	 * Sets the DirCache which shall be used by this merger. If the DirCache is
1149 	 * not set explicitly and if this merger doesn't work in-core, this merger
1150 	 * will implicitly get and lock a default DirCache. If the DirCache is
1151 	 * explicitly set the caller is responsible to lock it in advance. Finally
1152 	 * the merger will call {@link org.eclipse.jgit.dircache.DirCache#commit()}
1153 	 * which requires that the DirCache is locked. If the {@link #mergeImpl()}
1154 	 * returns without throwing an exception the lock will be released. In case
1155 	 * of exceptions the caller is responsible to release the lock.
1156 	 *
1157 	 * @param dc
1158 	 *            the DirCache to set
1159 	 */
1160 	public void setDirCache(DirCache dc) {
1161 		this.dircache = dc;
1162 	}
1163 
1164 	/**
1165 	 * Sets the WorkingTreeIterator to be used by this merger. If no
1166 	 * WorkingTreeIterator is set this merger will ignore the working tree and
1167 	 * fail if a content merge is necessary.
1168 	 * <p>
1169 	 * TODO: enhance WorkingTreeIterator to support write operations. Then this
1170 	 * merger will be able to merge with a different working tree abstraction.
1171 	 *
1172 	 * @param workingTreeIterator
1173 	 *            the workingTreeIt to set
1174 	 */
1175 	public void setWorkingTreeIterator(WorkingTreeIterator workingTreeIterator) {
1176 		this.workingTreeIterator = workingTreeIterator;
1177 	}
1178 
1179 
1180 	/**
1181 	 * The resolve conflict way of three way merging
1182 	 *
1183 	 * @param baseTree
1184 	 *            a {@link org.eclipse.jgit.treewalk.AbstractTreeIterator}
1185 	 *            object.
1186 	 * @param headTree
1187 	 *            a {@link org.eclipse.jgit.revwalk.RevTree} object.
1188 	 * @param mergeTree
1189 	 *            a {@link org.eclipse.jgit.revwalk.RevTree} object.
1190 	 * @param ignoreConflicts
1191 	 *            Controls what to do in case a content-merge is done and a
1192 	 *            conflict is detected. The default setting for this should be
1193 	 *            <code>false</code>. In this case the working tree file is
1194 	 *            filled with new content (containing conflict markers) and the
1195 	 *            index is filled with multiple stages containing BASE, OURS and
1196 	 *            THEIRS content. Having such non-0 stages is the sign to git
1197 	 *            tools that there are still conflicts for that path.
1198 	 *            <p>
1199 	 *            If <code>true</code> is specified the behavior is different.
1200 	 *            In case a conflict is detected the working tree file is again
1201 	 *            filled with new content (containing conflict markers). But
1202 	 *            also stage 0 of the index is filled with that content. No
1203 	 *            other stages are filled. Means: there is no conflict on that
1204 	 *            path but the new content (including conflict markers) is
1205 	 *            stored as successful merge result. This is needed in the
1206 	 *            context of {@link org.eclipse.jgit.merge.RecursiveMerger}
1207 	 *            where when determining merge bases we don't want to deal with
1208 	 *            content-merge conflicts.
1209 	 * @return whether the trees merged cleanly
1210 	 * @throws java.io.IOException
1211 	 * @since 3.5
1212 	 */
1213 	protected boolean mergeTrees(AbstractTreeIterator baseTree,
1214 			RevTree headTree, RevTree mergeTree, boolean ignoreConflicts)
1215 			throws IOException {
1216 		try {
1217 			workTreeUpdater = inCore ?
1218 					WorkTreeUpdater.createInCoreWorkTreeUpdater(db, dircache, getObjectInserter()) :
1219 					WorkTreeUpdater.createWorkTreeUpdater(db, dircache);
1220 			dircache = workTreeUpdater.getLockedDirCache();
1221 			tw = new NameConflictTreeWalk(db, reader);
1222 
1223 			tw.addTree(baseTree);
1224 			tw.setHead(tw.addTree(headTree));
1225 			tw.addTree(mergeTree);
1226 			DirCacheBuildIterator buildIt = workTreeUpdater.createDirCacheBuildIterator();
1227 			int dciPos = tw.addTree(buildIt);
1228 			if (workingTreeIterator != null) {
1229 				tw.addTree(workingTreeIterator);
1230 				workingTreeIterator.setDirCacheIterator(tw, dciPos);
1231 			} else {
1232 				tw.setFilter(TreeFilter.ANY_DIFF);
1233 			}
1234 
1235 			if (!mergeTreeWalk(tw, ignoreConflicts)) {
1236 				return false;
1237 			}
1238 
1239 			workTreeUpdater.writeWorkTreeChanges(true);
1240 			if (getUnmergedPaths().isEmpty() && !failed()) {
1241 				WorkTreeUpdater.Result result = workTreeUpdater.writeIndexChanges();
1242 				resultTree = result.getTreeId();
1243 				modifiedFiles = result.getModifiedFiles();
1244 				for (String f : result.getFailedToDelete()) {
1245 					failingPaths.put(f, MergeFailureReason.COULD_NOT_DELETE);
1246 				}
1247 				return result.getFailedToDelete().isEmpty();
1248 			}
1249 			resultTree = null;
1250 			return false;
1251 		} finally {
1252 			if(modifiedFiles.isEmpty()) {
1253 				modifiedFiles = workTreeUpdater.getModifiedFiles();
1254 			}
1255 			workTreeUpdater.close();
1256 			workTreeUpdater = null;
1257 		}
1258 	}
1259 
1260 	/**
1261 	 * Process the given TreeWalk's entries.
1262 	 *
1263 	 * @param treeWalk
1264 	 *            The walk to iterate over.
1265 	 * @param ignoreConflicts
1266 	 *            see
1267 	 *            {@link org.eclipse.jgit.merge.ResolveMerger#mergeTrees(AbstractTreeIterator, RevTree, RevTree, boolean)}
1268 	 * @return Whether the trees merged cleanly.
1269 	 * @throws java.io.IOException
1270 	 * @since 3.5
1271 	 */
1272 	protected boolean mergeTreeWalk(TreeWalk treeWalk, boolean ignoreConflicts)
1273 			throws IOException {
1274 		boolean hasWorkingTreeIterator = tw.getTreeCount() > T_FILE;
1275 		boolean hasAttributeNodeProvider = treeWalk
1276 				.getAttributesNodeProvider() != null;
1277 		while (treeWalk.next()) {
1278 			Attributes[] attributes = {NO_ATTRIBUTES, NO_ATTRIBUTES,
1279 					NO_ATTRIBUTES};
1280 			if (hasAttributeNodeProvider) {
1281 				attributes[T_BASE] = treeWalk.getAttributes(T_BASE);
1282 				attributes[T_OURS] = treeWalk.getAttributes(T_OURS);
1283 				attributes[T_THEIRS] = treeWalk.getAttributes(T_THEIRS);
1284 			}
1285 			if (!processEntry(
1286 					treeWalk.getTree(T_BASE, CanonicalTreeParser.class),
1287 					treeWalk.getTree(T_OURS, CanonicalTreeParser.class),
1288 					treeWalk.getTree(T_THEIRS, CanonicalTreeParser.class),
1289 					treeWalk.getTree(T_INDEX, DirCacheBuildIterator.class),
1290 					hasWorkingTreeIterator ? treeWalk.getTree(T_FILE,
1291 							WorkingTreeIterator.class) : null,
1292 					ignoreConflicts, attributes)) {
1293 				workTreeUpdater.revertModifiedFiles();
1294 				return false;
1295 			}
1296 			if (treeWalk.isSubtree() && enterSubtree) {
1297 				treeWalk.enterSubtree();
1298 			}
1299 		}
1300 		return true;
1301 	}
1302 }