ResolveMerger.java

  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, Thomas Wolf <thomas.wolf@paranor.ch> 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. import static java.nio.charset.StandardCharsets.UTF_8;
  16. import static java.time.Instant.EPOCH;
  17. import static org.eclipse.jgit.diff.DiffAlgorithm.SupportedAlgorithm.HISTOGRAM;
  18. import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_DIFF_SECTION;
  19. import static org.eclipse.jgit.lib.ConfigConstants.CONFIG_KEY_ALGORITHM;
  20. import static org.eclipse.jgit.lib.Constants.OBJ_BLOB;

  21. import java.io.BufferedOutputStream;
  22. import java.io.File;
  23. import java.io.FileNotFoundException;
  24. import java.io.FileOutputStream;
  25. import java.io.IOException;
  26. import java.io.InputStream;
  27. import java.io.OutputStream;
  28. import java.time.Instant;
  29. import java.util.ArrayList;
  30. import java.util.Arrays;
  31. import java.util.Collections;
  32. import java.util.HashMap;
  33. import java.util.Iterator;
  34. import java.util.LinkedList;
  35. import java.util.List;
  36. import java.util.Map;

  37. import org.eclipse.jgit.attributes.Attributes;
  38. import org.eclipse.jgit.diff.DiffAlgorithm;
  39. import org.eclipse.jgit.diff.DiffAlgorithm.SupportedAlgorithm;
  40. import org.eclipse.jgit.diff.RawText;
  41. import org.eclipse.jgit.diff.RawTextComparator;
  42. import org.eclipse.jgit.diff.Sequence;
  43. import org.eclipse.jgit.dircache.DirCache;
  44. import org.eclipse.jgit.dircache.DirCacheBuildIterator;
  45. import org.eclipse.jgit.dircache.DirCacheBuilder;
  46. import org.eclipse.jgit.dircache.DirCacheCheckout;
  47. import org.eclipse.jgit.dircache.DirCacheCheckout.CheckoutMetadata;
  48. import org.eclipse.jgit.dircache.DirCacheEntry;
  49. import org.eclipse.jgit.errors.BinaryBlobException;
  50. import org.eclipse.jgit.errors.CorruptObjectException;
  51. import org.eclipse.jgit.errors.IncorrectObjectTypeException;
  52. import org.eclipse.jgit.errors.IndexWriteException;
  53. import org.eclipse.jgit.errors.MissingObjectException;
  54. import org.eclipse.jgit.errors.NoWorkTreeException;
  55. import org.eclipse.jgit.lib.Config;
  56. import org.eclipse.jgit.lib.ConfigConstants;
  57. import org.eclipse.jgit.lib.Constants;
  58. import org.eclipse.jgit.lib.CoreConfig.EolStreamType;
  59. import org.eclipse.jgit.lib.FileMode;
  60. import org.eclipse.jgit.lib.ObjectId;
  61. import org.eclipse.jgit.lib.ObjectInserter;
  62. import org.eclipse.jgit.lib.ObjectLoader;
  63. import org.eclipse.jgit.lib.Repository;
  64. import org.eclipse.jgit.revwalk.RevTree;
  65. import org.eclipse.jgit.storage.pack.PackConfig;
  66. import org.eclipse.jgit.submodule.SubmoduleConflict;
  67. import org.eclipse.jgit.treewalk.AbstractTreeIterator;
  68. import org.eclipse.jgit.treewalk.CanonicalTreeParser;
  69. import org.eclipse.jgit.treewalk.NameConflictTreeWalk;
  70. import org.eclipse.jgit.treewalk.TreeWalk;
  71. import org.eclipse.jgit.treewalk.TreeWalk.OperationType;
  72. import org.eclipse.jgit.treewalk.WorkingTreeIterator;
  73. import org.eclipse.jgit.treewalk.WorkingTreeOptions;
  74. import org.eclipse.jgit.treewalk.filter.TreeFilter;
  75. import org.eclipse.jgit.util.FS;
  76. import org.eclipse.jgit.util.LfsFactory;
  77. import org.eclipse.jgit.util.LfsFactory.LfsInputStream;
  78. import org.eclipse.jgit.util.TemporaryBuffer;
  79. import org.eclipse.jgit.util.io.EolStreamTypeUtil;

  80. /**
  81.  * A three-way merger performing a content-merge if necessary
  82.  */
  83. public class ResolveMerger extends ThreeWayMerger {
  84.     /**
  85.      * If the merge fails (means: not stopped because of unresolved conflicts)
  86.      * this enum is used to explain why it failed
  87.      */
  88.     public enum MergeFailureReason {
  89.         /** the merge failed because of a dirty index */
  90.         DIRTY_INDEX,
  91.         /** the merge failed because of a dirty workingtree */
  92.         DIRTY_WORKTREE,
  93.         /** the merge failed because of a file could not be deleted */
  94.         COULD_NOT_DELETE
  95.     }

  96.     /**
  97.      * The tree walk which we'll iterate over to merge entries.
  98.      *
  99.      * @since 3.4
  100.      */
  101.     protected NameConflictTreeWalk tw;

  102.     /**
  103.      * string versions of a list of commit SHA1s
  104.      *
  105.      * @since 3.0
  106.      */
  107.     protected String[] commitNames;

  108.     /**
  109.      * Index of the base tree within the {@link #tw tree walk}.
  110.      *
  111.      * @since 3.4
  112.      */
  113.     protected static final int T_BASE = 0;

  114.     /**
  115.      * Index of our tree in withthe {@link #tw tree walk}.
  116.      *
  117.      * @since 3.4
  118.      */
  119.     protected static final int T_OURS = 1;

  120.     /**
  121.      * Index of their tree within the {@link #tw tree walk}.
  122.      *
  123.      * @since 3.4
  124.      */
  125.     protected static final int T_THEIRS = 2;

  126.     /**
  127.      * Index of the index tree within the {@link #tw tree walk}.
  128.      *
  129.      * @since 3.4
  130.      */
  131.     protected static final int T_INDEX = 3;

  132.     /**
  133.      * Index of the working directory tree within the {@link #tw tree walk}.
  134.      *
  135.      * @since 3.4
  136.      */
  137.     protected static final int T_FILE = 4;

  138.     /**
  139.      * Builder to update the cache during this merge.
  140.      *
  141.      * @since 3.4
  142.      */
  143.     protected DirCacheBuilder builder;

  144.     /**
  145.      * merge result as tree
  146.      *
  147.      * @since 3.0
  148.      */
  149.     protected ObjectId resultTree;

  150.     /**
  151.      * Paths that could not be merged by this merger because of an unsolvable
  152.      * conflict.
  153.      *
  154.      * @since 3.4
  155.      */
  156.     protected List<String> unmergedPaths = new ArrayList<>();

  157.     /**
  158.      * Files modified during this merge operation.
  159.      *
  160.      * @since 3.4
  161.      */
  162.     protected List<String> modifiedFiles = new LinkedList<>();

  163.     /**
  164.      * If the merger has nothing to do for a file but check it out at the end of
  165.      * the operation, it can be added here.
  166.      *
  167.      * @since 3.4
  168.      */
  169.     protected Map<String, DirCacheEntry> toBeCheckedOut = new HashMap<>();

  170.     /**
  171.      * Paths in this list will be deleted from the local copy at the end of the
  172.      * operation.
  173.      *
  174.      * @since 3.4
  175.      */
  176.     protected List<String> toBeDeleted = new ArrayList<>();

  177.     /**
  178.      * Low-level textual merge results. Will be passed on to the callers in case
  179.      * of conflicts.
  180.      *
  181.      * @since 3.4
  182.      */
  183.     protected Map<String, MergeResult<? extends Sequence>> mergeResults = new HashMap<>();

  184.     /**
  185.      * Paths for which the merge failed altogether.
  186.      *
  187.      * @since 3.4
  188.      */
  189.     protected Map<String, MergeFailureReason> failingPaths = new HashMap<>();

  190.     /**
  191.      * Updated as we merge entries of the tree walk. Tells us whether we should
  192.      * recurse into the entry if it is a subtree.
  193.      *
  194.      * @since 3.4
  195.      */
  196.     protected boolean enterSubtree;

  197.     /**
  198.      * Set to true if this merge should work in-memory. The repos dircache and
  199.      * workingtree are not touched by this method. Eventually needed files are
  200.      * created as temporary files and a new empty, in-memory dircache will be
  201.      * used instead the repo's one. Often used for bare repos where the repo
  202.      * doesn't even have a workingtree and dircache.
  203.      * @since 3.0
  204.      */
  205.     protected boolean inCore;

  206.     /**
  207.      * Set to true if this merger should use the default dircache of the
  208.      * repository and should handle locking and unlocking of the dircache. If
  209.      * this merger should work in-core or if an explicit dircache was specified
  210.      * during construction then this field is set to false.
  211.      * @since 3.0
  212.      */
  213.     protected boolean implicitDirCache;

  214.     /**
  215.      * Directory cache
  216.      * @since 3.0
  217.      */
  218.     protected DirCache dircache;

  219.     /**
  220.      * The iterator to access the working tree. If set to <code>null</code> this
  221.      * merger will not touch the working tree.
  222.      * @since 3.0
  223.      */
  224.     protected WorkingTreeIterator workingTreeIterator;

  225.     /**
  226.      * our merge algorithm
  227.      * @since 3.0
  228.      */
  229.     protected MergeAlgorithm mergeAlgorithm;

  230.     /**
  231.      * The {@link WorkingTreeOptions} are needed to determine line endings for
  232.      * merged files.
  233.      *
  234.      * @since 4.11
  235.      */
  236.     protected WorkingTreeOptions workingTreeOptions;

  237.     /**
  238.      * The size limit (bytes) which controls a file to be stored in {@code Heap}
  239.      * or {@code LocalFile} during the merge.
  240.      */
  241.     private int inCoreLimit;

  242.     /**
  243.      * Keeps {@link CheckoutMetadata} for {@link #checkout()} and
  244.      * {@link #cleanUp()}.
  245.      */
  246.     private Map<String, CheckoutMetadata> checkoutMetadata;

  247.     private static MergeAlgorithm getMergeAlgorithm(Config config) {
  248.         SupportedAlgorithm diffAlg = config.getEnum(
  249.                 CONFIG_DIFF_SECTION, null, CONFIG_KEY_ALGORITHM,
  250.                 HISTOGRAM);
  251.         return new MergeAlgorithm(DiffAlgorithm.getAlgorithm(diffAlg));
  252.     }

  253.     private static int getInCoreLimit(Config config) {
  254.         return config.getInt(
  255.                 ConfigConstants.CONFIG_MERGE_SECTION, ConfigConstants.CONFIG_KEY_IN_CORE_LIMIT, 10 << 20);
  256.     }

  257.     private static String[] defaultCommitNames() {
  258.         return new String[] { "BASE", "OURS", "THEIRS" }; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
  259.     }

  260.     private static final Attributes NO_ATTRIBUTES = new Attributes();

  261.     /**
  262.      * Constructor for ResolveMerger.
  263.      *
  264.      * @param local
  265.      *            the {@link org.eclipse.jgit.lib.Repository}.
  266.      * @param inCore
  267.      *            a boolean.
  268.      */
  269.     protected ResolveMerger(Repository local, boolean inCore) {
  270.         super(local);
  271.         Config config = local.getConfig();
  272.         mergeAlgorithm = getMergeAlgorithm(config);
  273.         inCoreLimit = getInCoreLimit(config);
  274.         commitNames = defaultCommitNames();
  275.         this.inCore = inCore;

  276.         if (inCore) {
  277.             implicitDirCache = false;
  278.             dircache = DirCache.newInCore();
  279.         } else {
  280.             implicitDirCache = true;
  281.             workingTreeOptions = local.getConfig().get(WorkingTreeOptions.KEY);
  282.         }
  283.     }

  284.     /**
  285.      * Constructor for ResolveMerger.
  286.      *
  287.      * @param local
  288.      *            the {@link org.eclipse.jgit.lib.Repository}.
  289.      */
  290.     protected ResolveMerger(Repository local) {
  291.         this(local, false);
  292.     }

  293.     /**
  294.      * Constructor for ResolveMerger.
  295.      *
  296.      * @param inserter
  297.      *            an {@link org.eclipse.jgit.lib.ObjectInserter} object.
  298.      * @param config
  299.      *            the repository configuration
  300.      * @since 4.8
  301.      */
  302.     protected ResolveMerger(ObjectInserter inserter, Config config) {
  303.         super(inserter);
  304.         mergeAlgorithm = getMergeAlgorithm(config);
  305.         commitNames = defaultCommitNames();
  306.         inCore = true;
  307.         implicitDirCache = false;
  308.         dircache = DirCache.newInCore();
  309.     }

  310.     /** {@inheritDoc} */
  311.     @Override
  312.     protected boolean mergeImpl() throws IOException {
  313.         if (implicitDirCache) {
  314.             dircache = nonNullRepo().lockDirCache();
  315.         }
  316.         if (!inCore) {
  317.             checkoutMetadata = new HashMap<>();
  318.         }
  319.         try {
  320.             return mergeTrees(mergeBase(), sourceTrees[0], sourceTrees[1],
  321.                     false);
  322.         } finally {
  323.             checkoutMetadata = null;
  324.             if (implicitDirCache) {
  325.                 dircache.unlock();
  326.             }
  327.         }
  328.     }

  329.     private void checkout() throws NoWorkTreeException, IOException {
  330.         // Iterate in reverse so that "folder/file" is deleted before
  331.         // "folder". Otherwise this could result in a failing path because
  332.         // of a non-empty directory, for which delete() would fail.
  333.         for (int i = toBeDeleted.size() - 1; i >= 0; i--) {
  334.             String fileName = toBeDeleted.get(i);
  335.             File f = new File(nonNullRepo().getWorkTree(), fileName);
  336.             if (!f.delete())
  337.                 if (!f.isDirectory())
  338.                     failingPaths.put(fileName,
  339.                             MergeFailureReason.COULD_NOT_DELETE);
  340.             modifiedFiles.add(fileName);
  341.         }
  342.         for (Map.Entry<String, DirCacheEntry> entry : toBeCheckedOut
  343.                 .entrySet()) {
  344.             DirCacheEntry cacheEntry = entry.getValue();
  345.             if (cacheEntry.getFileMode() == FileMode.GITLINK) {
  346.                 new File(nonNullRepo().getWorkTree(), entry.getKey()).mkdirs();
  347.             } else {
  348.                 DirCacheCheckout.checkoutEntry(db, cacheEntry, reader, false,
  349.                         checkoutMetadata.get(entry.getKey()));
  350.                 modifiedFiles.add(entry.getKey());
  351.             }
  352.         }
  353.     }

  354.     /**
  355.      * Reverts the worktree after an unsuccessful merge. We know that for all
  356.      * modified files the old content was in the old index and the index
  357.      * contained only stage 0. In case if inCore operation just clear the
  358.      * history of modified files.
  359.      *
  360.      * @throws java.io.IOException
  361.      * @throws org.eclipse.jgit.errors.CorruptObjectException
  362.      * @throws org.eclipse.jgit.errors.NoWorkTreeException
  363.      * @since 3.4
  364.      */
  365.     protected void cleanUp() throws NoWorkTreeException,
  366.             CorruptObjectException,
  367.             IOException {
  368.         if (inCore) {
  369.             modifiedFiles.clear();
  370.             return;
  371.         }

  372.         DirCache dc = nonNullRepo().readDirCache();
  373.         Iterator<String> mpathsIt=modifiedFiles.iterator();
  374.         while(mpathsIt.hasNext()) {
  375.             String mpath = mpathsIt.next();
  376.             DirCacheEntry entry = dc.getEntry(mpath);
  377.             if (entry != null) {
  378.                 DirCacheCheckout.checkoutEntry(db, entry, reader, false,
  379.                         checkoutMetadata.get(mpath));
  380.             }
  381.             mpathsIt.remove();
  382.         }
  383.     }

  384.     /**
  385.      * adds a new path with the specified stage to the index builder
  386.      *
  387.      * @param path
  388.      * @param p
  389.      * @param stage
  390.      * @param lastMod
  391.      * @param len
  392.      * @return the entry which was added to the index
  393.      */
  394.     private DirCacheEntry add(byte[] path, CanonicalTreeParser p, int stage,
  395.             Instant lastMod, long len) {
  396.         if (p != null && !p.getEntryFileMode().equals(FileMode.TREE)) {
  397.             DirCacheEntry e = new DirCacheEntry(path, stage);
  398.             e.setFileMode(p.getEntryFileMode());
  399.             e.setObjectId(p.getEntryObjectId());
  400.             e.setLastModified(lastMod);
  401.             e.setLength(len);
  402.             builder.add(e);
  403.             return e;
  404.         }
  405.         return null;
  406.     }

  407.     /**
  408.      * adds a entry to the index builder which is a copy of the specified
  409.      * DirCacheEntry
  410.      *
  411.      * @param e
  412.      *            the entry which should be copied
  413.      *
  414.      * @return the entry which was added to the index
  415.      */
  416.     private DirCacheEntry keep(DirCacheEntry e) {
  417.         DirCacheEntry newEntry = new DirCacheEntry(e.getRawPath(),
  418.                 e.getStage());
  419.         newEntry.setFileMode(e.getFileMode());
  420.         newEntry.setObjectId(e.getObjectId());
  421.         newEntry.setLastModified(e.getLastModifiedInstant());
  422.         newEntry.setLength(e.getLength());
  423.         builder.add(newEntry);
  424.         return newEntry;
  425.     }

  426.     /**
  427.      * Remembers the {@link CheckoutMetadata} for the given path; it may be
  428.      * needed in {@link #checkout()} or in {@link #cleanUp()}.
  429.      *
  430.      * @param path
  431.      *            of the current node
  432.      * @param attributes
  433.      *            for the current node
  434.      * @throws IOException
  435.      *             if the smudge filter cannot be determined
  436.      * @since 5.1
  437.      */
  438.     protected void addCheckoutMetadata(String path, Attributes attributes)
  439.             throws IOException {
  440.         if (checkoutMetadata != null) {
  441.             EolStreamType eol = EolStreamTypeUtil.detectStreamType(
  442.                     OperationType.CHECKOUT_OP, workingTreeOptions, attributes);
  443.             CheckoutMetadata data = new CheckoutMetadata(eol,
  444.                     tw.getFilterCommand(Constants.ATTR_FILTER_TYPE_SMUDGE));
  445.             checkoutMetadata.put(path, data);
  446.         }
  447.     }

  448.     /**
  449.      * Adds a {@link DirCacheEntry} for direct checkout and remembers its
  450.      * {@link CheckoutMetadata}.
  451.      *
  452.      * @param path
  453.      *            of the entry
  454.      * @param entry
  455.      *            to add
  456.      * @param attributes
  457.      *            for the current entry
  458.      * @throws IOException
  459.      *             if the {@link CheckoutMetadata} cannot be determined
  460.      * @since 5.1
  461.      */
  462.     protected void addToCheckout(String path, DirCacheEntry entry,
  463.             Attributes attributes) throws IOException {
  464.         toBeCheckedOut.put(path, entry);
  465.         addCheckoutMetadata(path, attributes);
  466.     }

  467.     /**
  468.      * Remember a path for deletion, and remember its {@link CheckoutMetadata}
  469.      * in case it has to be restored in {@link #cleanUp()}.
  470.      *
  471.      * @param path
  472.      *            of the entry
  473.      * @param isFile
  474.      *            whether it is a file
  475.      * @param attributes
  476.      *            for the entry
  477.      * @throws IOException
  478.      *             if the {@link CheckoutMetadata} cannot be determined
  479.      * @since 5.1
  480.      */
  481.     protected void addDeletion(String path, boolean isFile,
  482.             Attributes attributes) throws IOException {
  483.         toBeDeleted.add(path);
  484.         if (isFile) {
  485.             addCheckoutMetadata(path, attributes);
  486.         }
  487.     }

  488.     /**
  489.      * Processes one path and tries to merge taking git attributes in account.
  490.      * This method will do all trivial (not content) merges and will also detect
  491.      * if a merge will fail. The merge will fail when one of the following is
  492.      * true
  493.      * <ul>
  494.      * <li>the index entry does not match the entry in ours. When merging one
  495.      * branch into the current HEAD, ours will point to HEAD and theirs will
  496.      * point to the other branch. It is assumed that the index matches the HEAD
  497.      * because it will only not match HEAD if it was populated before the merge
  498.      * operation. But the merge commit should not accidentally contain
  499.      * modifications done before the merge. Check the <a href=
  500.      * "http://www.kernel.org/pub/software/scm/git/docs/git-read-tree.html#_3_way_merge"
  501.      * >git read-tree</a> documentation for further explanations.</li>
  502.      * <li>A conflict was detected and the working-tree file is dirty. When a
  503.      * conflict is detected the content-merge algorithm will try to write a
  504.      * merged version into the working-tree. If the file is dirty we would
  505.      * override unsaved data.</li>
  506.      * </ul>
  507.      *
  508.      * @param base
  509.      *            the common base for ours and theirs
  510.      * @param ours
  511.      *            the ours side of the merge. When merging a branch into the
  512.      *            HEAD ours will point to HEAD
  513.      * @param theirs
  514.      *            the theirs side of the merge. When merging a branch into the
  515.      *            current HEAD theirs will point to the branch which is merged
  516.      *            into HEAD.
  517.      * @param index
  518.      *            the index entry
  519.      * @param work
  520.      *            the file in the working tree
  521.      * @param ignoreConflicts
  522.      *            see
  523.      *            {@link org.eclipse.jgit.merge.ResolveMerger#mergeTrees(AbstractTreeIterator, RevTree, RevTree, boolean)}
  524.      * @param attributes
  525.      *            the attributes defined for this entry
  526.      * @return <code>false</code> if the merge will fail because the index entry
  527.      *         didn't match ours or the working-dir file was dirty and a
  528.      *         conflict occurred
  529.      * @throws org.eclipse.jgit.errors.MissingObjectException
  530.      * @throws org.eclipse.jgit.errors.IncorrectObjectTypeException
  531.      * @throws org.eclipse.jgit.errors.CorruptObjectException
  532.      * @throws java.io.IOException
  533.      * @since 4.9
  534.      */
  535.     protected boolean processEntry(CanonicalTreeParser base,
  536.             CanonicalTreeParser ours, CanonicalTreeParser theirs,
  537.             DirCacheBuildIterator index, WorkingTreeIterator work,
  538.             boolean ignoreConflicts, Attributes attributes)
  539.             throws MissingObjectException, IncorrectObjectTypeException,
  540.             CorruptObjectException, IOException {
  541.         enterSubtree = true;
  542.         final int modeO = tw.getRawMode(T_OURS);
  543.         final int modeT = tw.getRawMode(T_THEIRS);
  544.         final int modeB = tw.getRawMode(T_BASE);
  545.         boolean gitLinkMerging = isGitLink(modeO) || isGitLink(modeT)
  546.                 || isGitLink(modeB);
  547.         if (modeO == 0 && modeT == 0 && modeB == 0)
  548.             // File is either untracked or new, staged but uncommitted
  549.             return true;

  550.         if (isIndexDirty())
  551.             return false;

  552.         DirCacheEntry ourDce = null;

  553.         if (index == null || index.getDirCacheEntry() == null) {
  554.             // create a fake DCE, but only if ours is valid. ours is kept only
  555.             // in case it is valid, so a null ourDce is ok in all other cases.
  556.             if (nonTree(modeO)) {
  557.                 ourDce = new DirCacheEntry(tw.getRawPath());
  558.                 ourDce.setObjectId(tw.getObjectId(T_OURS));
  559.                 ourDce.setFileMode(tw.getFileMode(T_OURS));
  560.             }
  561.         } else {
  562.             ourDce = index.getDirCacheEntry();
  563.         }

  564.         if (nonTree(modeO) && nonTree(modeT) && tw.idEqual(T_OURS, T_THEIRS)) {
  565.             // OURS and THEIRS have equal content. Check the file mode
  566.             if (modeO == modeT) {
  567.                 // content and mode of OURS and THEIRS are equal: it doesn't
  568.                 // matter which one we choose. OURS is chosen. Since the index
  569.                 // is clean (the index matches already OURS) we can keep the existing one
  570.                 keep(ourDce);
  571.                 // no checkout needed!
  572.                 return true;
  573.             }
  574.             // same content but different mode on OURS and THEIRS.
  575.             // Try to merge the mode and report an error if this is
  576.             // not possible.
  577.             int newMode = mergeFileModes(modeB, modeO, modeT);
  578.             if (newMode != FileMode.MISSING.getBits()) {
  579.                 if (newMode == modeO) {
  580.                     // ours version is preferred
  581.                     keep(ourDce);
  582.                 } else {
  583.                     // the preferred version THEIRS has a different mode
  584.                     // than ours. Check it out!
  585.                     if (isWorktreeDirty(work, ourDce)) {
  586.                         return false;
  587.                     }
  588.                     // we know about length and lastMod only after we have
  589.                     // written the new content.
  590.                     // This will happen later. Set these values to 0 for know.
  591.                     DirCacheEntry e = add(tw.getRawPath(), theirs,
  592.                             DirCacheEntry.STAGE_0, EPOCH, 0);
  593.                     addToCheckout(tw.getPathString(), e, attributes);
  594.                 }
  595.                 return true;
  596.             }
  597.             // FileModes are not mergeable. We found a conflict on modes.
  598.             // For conflicting entries we don't know lastModified and
  599.             // length.
  600.             add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
  601.             add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0);
  602.             add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH, 0);
  603.             unmergedPaths.add(tw.getPathString());
  604.             mergeResults.put(tw.getPathString(),
  605.                     new MergeResult<>(Collections.<RawText> emptyList()));
  606.             return true;
  607.         }

  608.         if (modeB == modeT && tw.idEqual(T_BASE, T_THEIRS)) {
  609.             // THEIRS was not changed compared to BASE. All changes must be in
  610.             // OURS. OURS is chosen. We can keep the existing entry.
  611.             if (ourDce != null)
  612.                 keep(ourDce);
  613.             // no checkout needed!
  614.             return true;
  615.         }

  616.         if (modeB == modeO && tw.idEqual(T_BASE, T_OURS)) {
  617.             // OURS was not changed compared to BASE. All changes must be in
  618.             // THEIRS. THEIRS is chosen.

  619.             // Check worktree before checking out THEIRS
  620.             if (isWorktreeDirty(work, ourDce))
  621.                 return false;
  622.             if (nonTree(modeT)) {
  623.                 // we know about length and lastMod only after we have written
  624.                 // the new content.
  625.                 // This will happen later. Set these values to 0 for know.
  626.                 DirCacheEntry e = add(tw.getRawPath(), theirs,
  627.                         DirCacheEntry.STAGE_0, EPOCH, 0);
  628.                 if (e != null) {
  629.                     addToCheckout(tw.getPathString(), e, attributes);
  630.                 }
  631.                 return true;
  632.             }
  633.             // we want THEIRS ... but THEIRS contains a folder or the
  634.             // deletion of the path. Delete what's in the working tree,
  635.             // which we know to be clean.
  636.             if (tw.getTreeCount() > T_FILE && tw.getRawMode(T_FILE) == 0) {
  637.                 // Not present in working tree, so nothing to delete
  638.                 return true;
  639.             }
  640.             if (modeT != 0 && modeT == modeB) {
  641.                 // Base, ours, and theirs all contain a folder: don't delete
  642.                 return true;
  643.             }
  644.             addDeletion(tw.getPathString(), nonTree(modeO), attributes);
  645.             return true;
  646.         }

  647.         if (tw.isSubtree()) {
  648.             // file/folder conflicts: here I want to detect only file/folder
  649.             // conflict between ours and theirs. file/folder conflicts between
  650.             // base/index/workingTree and something else are not relevant or
  651.             // detected later
  652.             if (nonTree(modeO) != nonTree(modeT)) {
  653.                 if (ignoreConflicts) {
  654.                     // In case of merge failures, ignore this path instead of reporting unmerged, so
  655.                     // a caller can use virtual commit. This will not result in files with conflict
  656.                     // markers in the index/working tree. The actual diff on the path will be
  657.                     // computed directly on children.
  658.                     enterSubtree = false;
  659.                     return true;
  660.                 }
  661.                 if (nonTree(modeB))
  662.                     add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
  663.                 if (nonTree(modeO))
  664.                     add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0);
  665.                 if (nonTree(modeT))
  666.                     add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH, 0);
  667.                 unmergedPaths.add(tw.getPathString());
  668.                 enterSubtree = false;
  669.                 return true;
  670.             }

  671.             // ours and theirs are both folders or both files (and treewalk
  672.             // tells us we are in a subtree because of index or working-dir).
  673.             // If they are both folders no content-merge is required - we can
  674.             // return here.
  675.             if (!nonTree(modeO))
  676.                 return true;

  677.             // ours and theirs are both files, just fall out of the if block
  678.             // and do the content merge
  679.         }

  680.         if (nonTree(modeO) && nonTree(modeT)) {
  681.             // Check worktree before modifying files
  682.             boolean worktreeDirty = isWorktreeDirty(work, ourDce);
  683.             if (!attributes.canBeContentMerged() && worktreeDirty) {
  684.                 return false;
  685.             }

  686.             if (gitLinkMerging && ignoreConflicts) {
  687.                 // Always select 'ours' in case of GITLINK merge failures so
  688.                 // a caller can use virtual commit.
  689.                 add(tw.getRawPath(), ours, DirCacheEntry.STAGE_0, EPOCH, 0);
  690.                 return true;
  691.             } else if (gitLinkMerging) {
  692.                 add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
  693.                 add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0);
  694.                 add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH, 0);
  695.                 MergeResult<SubmoduleConflict> result = createGitLinksMergeResult(
  696.                         base, ours, theirs);
  697.                 result.setContainsConflicts(true);
  698.                 mergeResults.put(tw.getPathString(), result);
  699.                 unmergedPaths.add(tw.getPathString());
  700.                 return true;
  701.             } else if (!attributes.canBeContentMerged()) {
  702.                 add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
  703.                 add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0);
  704.                 add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH, 0);

  705.                 // attribute merge issues are conflicts but not failures
  706.                 unmergedPaths.add(tw.getPathString());
  707.                 return true;
  708.             }

  709.             // Check worktree before modifying files
  710.             if (worktreeDirty) {
  711.                 return false;
  712.             }

  713.             MergeResult<RawText> result = contentMerge(base, ours, theirs,
  714.                     attributes);
  715.             if (ignoreConflicts) {
  716.                 result.setContainsConflicts(false);
  717.             }
  718.             updateIndex(base, ours, theirs, result, attributes);
  719.             String currentPath = tw.getPathString();
  720.             if (result.containsConflicts() && !ignoreConflicts) {
  721.                 unmergedPaths.add(currentPath);
  722.             }
  723.             modifiedFiles.add(currentPath);
  724.             addCheckoutMetadata(currentPath, attributes);
  725.         } else if (modeO != modeT) {
  726.             // OURS or THEIRS has been deleted
  727.             if (((modeO != 0 && !tw.idEqual(T_BASE, T_OURS)) || (modeT != 0 && !tw
  728.                     .idEqual(T_BASE, T_THEIRS)))) {
  729.                 if (gitLinkMerging && ignoreConflicts) {
  730.                     add(tw.getRawPath(), ours, DirCacheEntry.STAGE_0, EPOCH, 0);
  731.                 } else if (gitLinkMerging) {
  732.                     add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
  733.                     add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0);
  734.                     add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH, 0);
  735.                     MergeResult<SubmoduleConflict> result = createGitLinksMergeResult(
  736.                             base, ours, theirs);
  737.                     result.setContainsConflicts(true);
  738.                     mergeResults.put(tw.getPathString(), result);
  739.                     unmergedPaths.add(tw.getPathString());
  740.                 } else {
  741.                     MergeResult<RawText> result = contentMerge(base, ours,
  742.                             theirs, attributes);

  743.                     if (ignoreConflicts) {
  744.                         // In case a conflict is detected the working tree file
  745.                         // is again filled with new content (containing conflict
  746.                         // markers). But also stage 0 of the index is filled
  747.                         // with that content.
  748.                         result.setContainsConflicts(false);
  749.                         updateIndex(base, ours, theirs, result, attributes);
  750.                     } else {
  751.                         add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH,
  752.                                 0);
  753.                         add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH,
  754.                                 0);
  755.                         DirCacheEntry e = add(tw.getRawPath(), theirs,
  756.                                 DirCacheEntry.STAGE_3, EPOCH, 0);

  757.                         // OURS was deleted checkout THEIRS
  758.                         if (modeO == 0) {
  759.                             // Check worktree before checking out THEIRS
  760.                             if (isWorktreeDirty(work, ourDce)) {
  761.                                 return false;
  762.                             }
  763.                             if (nonTree(modeT)) {
  764.                                 if (e != null) {
  765.                                     addToCheckout(tw.getPathString(), e,
  766.                                             attributes);
  767.                                 }
  768.                             }
  769.                         }

  770.                         unmergedPaths.add(tw.getPathString());

  771.                         // generate a MergeResult for the deleted file
  772.                         mergeResults.put(tw.getPathString(), result);
  773.                     }
  774.                 }
  775.             }
  776.         }
  777.         return true;
  778.     }

  779.     private static MergeResult<SubmoduleConflict> createGitLinksMergeResult(
  780.             CanonicalTreeParser base, CanonicalTreeParser ours,
  781.             CanonicalTreeParser theirs) {
  782.         return new MergeResult<>(Arrays.asList(
  783.                 new SubmoduleConflict(
  784.                         base == null ? null : base.getEntryObjectId()),
  785.                 new SubmoduleConflict(
  786.                         ours == null ? null : ours.getEntryObjectId()),
  787.                 new SubmoduleConflict(
  788.                         theirs == null ? null : theirs.getEntryObjectId())));
  789.     }

  790.     /**
  791.      * Does the content merge. The three texts base, ours and theirs are
  792.      * specified with {@link CanonicalTreeParser}. If any of the parsers is
  793.      * specified as <code>null</code> then an empty text will be used instead.
  794.      *
  795.      * @param base
  796.      * @param ours
  797.      * @param theirs
  798.      * @param attributes
  799.      *
  800.      * @return the result of the content merge
  801.      * @throws IOException
  802.      */
  803.     private MergeResult<RawText> contentMerge(CanonicalTreeParser base,
  804.             CanonicalTreeParser ours, CanonicalTreeParser theirs,
  805.             Attributes attributes)
  806.             throws IOException {
  807.         RawText baseText;
  808.         RawText ourText;
  809.         RawText theirsText;

  810.         try {
  811.             baseText = base == null ? RawText.EMPTY_TEXT : getRawText(
  812.                             base.getEntryObjectId(), attributes);
  813.             ourText = ours == null ? RawText.EMPTY_TEXT : getRawText(
  814.                             ours.getEntryObjectId(), attributes);
  815.             theirsText = theirs == null ? RawText.EMPTY_TEXT : getRawText(
  816.                             theirs.getEntryObjectId(), attributes);
  817.         } catch (BinaryBlobException e) {
  818.             MergeResult<RawText> r = new MergeResult<>(Collections.<RawText>emptyList());
  819.             r.setContainsConflicts(true);
  820.             return r;
  821.         }
  822.         return (mergeAlgorithm.merge(RawTextComparator.DEFAULT, baseText,
  823.                 ourText, theirsText));
  824.     }

  825.     private boolean isIndexDirty() {
  826.         if (inCore)
  827.             return false;

  828.         final int modeI = tw.getRawMode(T_INDEX);
  829.         final int modeO = tw.getRawMode(T_OURS);

  830.         // Index entry has to match ours to be considered clean
  831.         final boolean isDirty = nonTree(modeI)
  832.                 && !(modeO == modeI && tw.idEqual(T_INDEX, T_OURS));
  833.         if (isDirty)
  834.             failingPaths
  835.                     .put(tw.getPathString(), MergeFailureReason.DIRTY_INDEX);
  836.         return isDirty;
  837.     }

  838.     private boolean isWorktreeDirty(WorkingTreeIterator work,
  839.             DirCacheEntry ourDce) throws IOException {
  840.         if (work == null)
  841.             return false;

  842.         final int modeF = tw.getRawMode(T_FILE);
  843.         final int modeO = tw.getRawMode(T_OURS);

  844.         // Worktree entry has to match ours to be considered clean
  845.         boolean isDirty;
  846.         if (ourDce != null)
  847.             isDirty = work.isModified(ourDce, true, reader);
  848.         else {
  849.             isDirty = work.isModeDifferent(modeO);
  850.             if (!isDirty && nonTree(modeF))
  851.                 isDirty = !tw.idEqual(T_FILE, T_OURS);
  852.         }

  853.         // Ignore existing empty directories
  854.         if (isDirty && modeF == FileMode.TYPE_TREE
  855.                 && modeO == FileMode.TYPE_MISSING)
  856.             isDirty = false;
  857.         if (isDirty)
  858.             failingPaths.put(tw.getPathString(),
  859.                     MergeFailureReason.DIRTY_WORKTREE);
  860.         return isDirty;
  861.     }

  862.     /**
  863.      * Updates the index after a content merge has happened. If no conflict has
  864.      * occurred this includes persisting the merged content to the object
  865.      * database. In case of conflicts this method takes care to write the
  866.      * correct stages to the index.
  867.      *
  868.      * @param base
  869.      * @param ours
  870.      * @param theirs
  871.      * @param result
  872.      * @param attributes
  873.      * @throws FileNotFoundException
  874.      * @throws IOException
  875.      */
  876.     private void updateIndex(CanonicalTreeParser base,
  877.             CanonicalTreeParser ours, CanonicalTreeParser theirs,
  878.             MergeResult<RawText> result, Attributes attributes)
  879.             throws FileNotFoundException,
  880.             IOException {
  881.         TemporaryBuffer rawMerged = null;
  882.         try {
  883.             rawMerged = doMerge(result);
  884.             File mergedFile = inCore ? null
  885.                     : writeMergedFile(rawMerged, attributes);
  886.             if (result.containsConflicts()) {
  887.                 // A conflict occurred, the file will contain conflict markers
  888.                 // the index will be populated with the three stages and the
  889.                 // workdir (if used) contains the halfway merged content.
  890.                 add(tw.getRawPath(), base, DirCacheEntry.STAGE_1, EPOCH, 0);
  891.                 add(tw.getRawPath(), ours, DirCacheEntry.STAGE_2, EPOCH, 0);
  892.                 add(tw.getRawPath(), theirs, DirCacheEntry.STAGE_3, EPOCH, 0);
  893.                 mergeResults.put(tw.getPathString(), result);
  894.                 return;
  895.             }

  896.             // No conflict occurred, the file will contain fully merged content.
  897.             // The index will be populated with the new merged version.
  898.             DirCacheEntry dce = new DirCacheEntry(tw.getPathString());

  899.             // Set the mode for the new content. Fall back to REGULAR_FILE if
  900.             // we can't merge modes of OURS and THEIRS.
  901.             int newMode = mergeFileModes(tw.getRawMode(0), tw.getRawMode(1),
  902.                     tw.getRawMode(2));
  903.             dce.setFileMode(newMode == FileMode.MISSING.getBits()
  904.                     ? FileMode.REGULAR_FILE : FileMode.fromBits(newMode));
  905.             if (mergedFile != null) {
  906.                 dce.setLastModified(
  907.                         nonNullRepo().getFS().lastModifiedInstant(mergedFile));
  908.                 dce.setLength((int) mergedFile.length());
  909.             }
  910.             dce.setObjectId(insertMergeResult(rawMerged, attributes));
  911.             builder.add(dce);
  912.         } finally {
  913.             if (rawMerged != null) {
  914.                 rawMerged.destroy();
  915.             }
  916.         }
  917.     }

  918.     /**
  919.      * Writes merged file content to the working tree.
  920.      *
  921.      * @param rawMerged
  922.      *            the raw merged content
  923.      * @param attributes
  924.      *            the files .gitattributes entries
  925.      * @return the working tree file to which the merged content was written.
  926.      * @throws FileNotFoundException
  927.      * @throws IOException
  928.      */
  929.     private File writeMergedFile(TemporaryBuffer rawMerged,
  930.             Attributes attributes)
  931.             throws FileNotFoundException, IOException {
  932.         File workTree = nonNullRepo().getWorkTree();
  933.         FS fs = nonNullRepo().getFS();
  934.         File of = new File(workTree, tw.getPathString());
  935.         File parentFolder = of.getParentFile();
  936.         if (!fs.exists(parentFolder)) {
  937.             parentFolder.mkdirs();
  938.         }
  939.         EolStreamType streamType = EolStreamTypeUtil.detectStreamType(
  940.                 OperationType.CHECKOUT_OP, workingTreeOptions,
  941.                 attributes);
  942.         try (OutputStream os = EolStreamTypeUtil.wrapOutputStream(
  943.                 new BufferedOutputStream(new FileOutputStream(of)),
  944.                 streamType)) {
  945.             rawMerged.writeTo(os, null);
  946.         }
  947.         return of;
  948.     }

  949.     private TemporaryBuffer doMerge(MergeResult<RawText> result)
  950.             throws IOException {
  951.         TemporaryBuffer.LocalFile buf = new TemporaryBuffer.LocalFile(
  952.                 db != null ? nonNullRepo().getDirectory() : null, inCoreLimit);
  953.         boolean success = false;
  954.         try {
  955.             new MergeFormatter().formatMerge(buf, result,
  956.                     Arrays.asList(commitNames), UTF_8);
  957.             buf.close();
  958.             success = true;
  959.         } finally {
  960.             if (!success) {
  961.                 buf.destroy();
  962.             }
  963.         }
  964.         return buf;
  965.     }

  966.     private ObjectId insertMergeResult(TemporaryBuffer buf,
  967.             Attributes attributes) throws IOException {
  968.         InputStream in = buf.openInputStream();
  969.         try (LfsInputStream is = LfsFactory.getInstance().applyCleanFilter(
  970.                 getRepository(), in,
  971.                 buf.length(), attributes.get(Constants.ATTR_MERGE))) {
  972.             return getObjectInserter().insert(OBJ_BLOB, is.getLength(), is);
  973.         }
  974.     }

  975.     /**
  976.      * Try to merge filemodes. If only ours or theirs have changed the mode
  977.      * (compared to base) we choose that one. If ours and theirs have equal
  978.      * modes return that one. If also that is not the case the modes are not
  979.      * mergeable. Return {@link FileMode#MISSING} int that case.
  980.      *
  981.      * @param modeB
  982.      *            filemode found in BASE
  983.      * @param modeO
  984.      *            filemode found in OURS
  985.      * @param modeT
  986.      *            filemode found in THEIRS
  987.      *
  988.      * @return the merged filemode or {@link FileMode#MISSING} in case of a
  989.      *         conflict
  990.      */
  991.     private int mergeFileModes(int modeB, int modeO, int modeT) {
  992.         if (modeO == modeT)
  993.             return modeO;
  994.         if (modeB == modeO)
  995.             // Base equal to Ours -> chooses Theirs if that is not missing
  996.             return (modeT == FileMode.MISSING.getBits()) ? modeO : modeT;
  997.         if (modeB == modeT)
  998.             // Base equal to Theirs -> chooses Ours if that is not missing
  999.             return (modeO == FileMode.MISSING.getBits()) ? modeT : modeO;
  1000.         return FileMode.MISSING.getBits();
  1001.     }

  1002.     private RawText getRawText(ObjectId id,
  1003.             Attributes attributes)
  1004.             throws IOException, BinaryBlobException {
  1005.         if (id.equals(ObjectId.zeroId()))
  1006.             return new RawText(new byte[] {});

  1007.         ObjectLoader loader = LfsFactory.getInstance().applySmudgeFilter(
  1008.                 getRepository(), reader.open(id, OBJ_BLOB),
  1009.                 attributes.get(Constants.ATTR_MERGE));
  1010.         int threshold = PackConfig.DEFAULT_BIG_FILE_THRESHOLD;
  1011.         return RawText.load(loader, threshold);
  1012.     }

  1013.     private static boolean nonTree(int mode) {
  1014.         return mode != 0 && !FileMode.TREE.equals(mode);
  1015.     }

  1016.     private static boolean isGitLink(int mode) {
  1017.         return FileMode.GITLINK.equals(mode);
  1018.     }

  1019.     /** {@inheritDoc} */
  1020.     @Override
  1021.     public ObjectId getResultTreeId() {
  1022.         return (resultTree == null) ? null : resultTree.toObjectId();
  1023.     }

  1024.     /**
  1025.      * Set the names of the commits as they would appear in conflict markers
  1026.      *
  1027.      * @param commitNames
  1028.      *            the names of the commits as they would appear in conflict
  1029.      *            markers
  1030.      */
  1031.     public void setCommitNames(String[] commitNames) {
  1032.         this.commitNames = commitNames;
  1033.     }

  1034.     /**
  1035.      * Get the names of the commits as they would appear in conflict markers.
  1036.      *
  1037.      * @return the names of the commits as they would appear in conflict
  1038.      *         markers.
  1039.      */
  1040.     public String[] getCommitNames() {
  1041.         return commitNames;
  1042.     }

  1043.     /**
  1044.      * Get the paths with conflicts. This is a subset of the files listed by
  1045.      * {@link #getModifiedFiles()}
  1046.      *
  1047.      * @return the paths with conflicts. This is a subset of the files listed by
  1048.      *         {@link #getModifiedFiles()}
  1049.      */
  1050.     public List<String> getUnmergedPaths() {
  1051.         return unmergedPaths;
  1052.     }

  1053.     /**
  1054.      * Get the paths of files which have been modified by this merge.
  1055.      *
  1056.      * @return the paths of files which have been modified by this merge. A file
  1057.      *         will be modified if a content-merge works on this path or if the
  1058.      *         merge algorithm decides to take the theirs-version. This is a
  1059.      *         superset of the files listed by {@link #getUnmergedPaths()}.
  1060.      */
  1061.     public List<String> getModifiedFiles() {
  1062.         return modifiedFiles;
  1063.     }

  1064.     /**
  1065.      * Get a map which maps the paths of files which have to be checked out
  1066.      * because the merge created new fully-merged content for this file into the
  1067.      * index.
  1068.      *
  1069.      * @return a map which maps the paths of files which have to be checked out
  1070.      *         because the merge created new fully-merged content for this file
  1071.      *         into the index. This means: the merge wrote a new stage 0 entry
  1072.      *         for this path.
  1073.      */
  1074.     public Map<String, DirCacheEntry> getToBeCheckedOut() {
  1075.         return toBeCheckedOut;
  1076.     }

  1077.     /**
  1078.      * Get the mergeResults
  1079.      *
  1080.      * @return the mergeResults
  1081.      */
  1082.     public Map<String, MergeResult<? extends Sequence>> getMergeResults() {
  1083.         return mergeResults;
  1084.     }

  1085.     /**
  1086.      * Get list of paths causing this merge to fail (not stopped because of a
  1087.      * conflict).
  1088.      *
  1089.      * @return lists paths causing this merge to fail (not stopped because of a
  1090.      *         conflict). <code>null</code> is returned if this merge didn't
  1091.      *         fail.
  1092.      */
  1093.     public Map<String, MergeFailureReason> getFailingPaths() {
  1094.         return failingPaths.isEmpty() ? null : failingPaths;
  1095.     }

  1096.     /**
  1097.      * Returns whether this merge failed (i.e. not stopped because of a
  1098.      * conflict)
  1099.      *
  1100.      * @return <code>true</code> if a failure occurred, <code>false</code>
  1101.      *         otherwise
  1102.      */
  1103.     public boolean failed() {
  1104.         return !failingPaths.isEmpty();
  1105.     }

  1106.     /**
  1107.      * Sets the DirCache which shall be used by this merger. If the DirCache is
  1108.      * not set explicitly and if this merger doesn't work in-core, this merger
  1109.      * will implicitly get and lock a default DirCache. If the DirCache is
  1110.      * explicitly set the caller is responsible to lock it in advance. Finally
  1111.      * the merger will call {@link org.eclipse.jgit.dircache.DirCache#commit()}
  1112.      * which requires that the DirCache is locked. If the {@link #mergeImpl()}
  1113.      * returns without throwing an exception the lock will be released. In case
  1114.      * of exceptions the caller is responsible to release the lock.
  1115.      *
  1116.      * @param dc
  1117.      *            the DirCache to set
  1118.      */
  1119.     public void setDirCache(DirCache dc) {
  1120.         this.dircache = dc;
  1121.         implicitDirCache = false;
  1122.     }

  1123.     /**
  1124.      * Sets the WorkingTreeIterator to be used by this merger. If no
  1125.      * WorkingTreeIterator is set this merger will ignore the working tree and
  1126.      * fail if a content merge is necessary.
  1127.      * <p>
  1128.      * TODO: enhance WorkingTreeIterator to support write operations. Then this
  1129.      * merger will be able to merge with a different working tree abstraction.
  1130.      *
  1131.      * @param workingTreeIterator
  1132.      *            the workingTreeIt to set
  1133.      */
  1134.     public void setWorkingTreeIterator(WorkingTreeIterator workingTreeIterator) {
  1135.         this.workingTreeIterator = workingTreeIterator;
  1136.     }


  1137.     /**
  1138.      * The resolve conflict way of three way merging
  1139.      *
  1140.      * @param baseTree
  1141.      *            a {@link org.eclipse.jgit.treewalk.AbstractTreeIterator}
  1142.      *            object.
  1143.      * @param headTree
  1144.      *            a {@link org.eclipse.jgit.revwalk.RevTree} object.
  1145.      * @param mergeTree
  1146.      *            a {@link org.eclipse.jgit.revwalk.RevTree} object.
  1147.      * @param ignoreConflicts
  1148.      *            Controls what to do in case a content-merge is done and a
  1149.      *            conflict is detected. The default setting for this should be
  1150.      *            <code>false</code>. In this case the working tree file is
  1151.      *            filled with new content (containing conflict markers) and the
  1152.      *            index is filled with multiple stages containing BASE, OURS and
  1153.      *            THEIRS content. Having such non-0 stages is the sign to git
  1154.      *            tools that there are still conflicts for that path.
  1155.      *            <p>
  1156.      *            If <code>true</code> is specified the behavior is different.
  1157.      *            In case a conflict is detected the working tree file is again
  1158.      *            filled with new content (containing conflict markers). But
  1159.      *            also stage 0 of the index is filled with that content. No
  1160.      *            other stages are filled. Means: there is no conflict on that
  1161.      *            path but the new content (including conflict markers) is
  1162.      *            stored as successful merge result. This is needed in the
  1163.      *            context of {@link org.eclipse.jgit.merge.RecursiveMerger}
  1164.      *            where when determining merge bases we don't want to deal with
  1165.      *            content-merge conflicts.
  1166.      * @return whether the trees merged cleanly
  1167.      * @throws java.io.IOException
  1168.      * @since 3.5
  1169.      */
  1170.     protected boolean mergeTrees(AbstractTreeIterator baseTree,
  1171.             RevTree headTree, RevTree mergeTree, boolean ignoreConflicts)
  1172.             throws IOException {

  1173.         builder = dircache.builder();
  1174.         DirCacheBuildIterator buildIt = new DirCacheBuildIterator(builder);

  1175.         tw = new NameConflictTreeWalk(db, reader);
  1176.         tw.addTree(baseTree);
  1177.         tw.addTree(headTree);
  1178.         tw.addTree(mergeTree);
  1179.         int dciPos = tw.addTree(buildIt);
  1180.         if (workingTreeIterator != null) {
  1181.             tw.addTree(workingTreeIterator);
  1182.             workingTreeIterator.setDirCacheIterator(tw, dciPos);
  1183.         } else {
  1184.             tw.setFilter(TreeFilter.ANY_DIFF);
  1185.         }

  1186.         if (!mergeTreeWalk(tw, ignoreConflicts)) {
  1187.             return false;
  1188.         }

  1189.         if (!inCore) {
  1190.             // No problem found. The only thing left to be done is to
  1191.             // checkout all files from "theirs" which have been selected to
  1192.             // go into the new index.
  1193.             checkout();

  1194.             // All content-merges are successfully done. If we can now write the
  1195.             // new index we are on quite safe ground. Even if the checkout of
  1196.             // files coming from "theirs" fails the user can work around such
  1197.             // failures by checking out the index again.
  1198.             if (!builder.commit()) {
  1199.                 cleanUp();
  1200.                 throw new IndexWriteException();
  1201.             }
  1202.             builder = null;

  1203.         } else {
  1204.             builder.finish();
  1205.             builder = null;
  1206.         }

  1207.         if (getUnmergedPaths().isEmpty() && !failed()) {
  1208.             resultTree = dircache.writeTree(getObjectInserter());
  1209.             return true;
  1210.         }
  1211.         resultTree = null;
  1212.         return false;
  1213.     }

  1214.     /**
  1215.      * Process the given TreeWalk's entries.
  1216.      *
  1217.      * @param treeWalk
  1218.      *            The walk to iterate over.
  1219.      * @param ignoreConflicts
  1220.      *            see
  1221.      *            {@link org.eclipse.jgit.merge.ResolveMerger#mergeTrees(AbstractTreeIterator, RevTree, RevTree, boolean)}
  1222.      * @return Whether the trees merged cleanly.
  1223.      * @throws java.io.IOException
  1224.      * @since 3.5
  1225.      */
  1226.     protected boolean mergeTreeWalk(TreeWalk treeWalk, boolean ignoreConflicts)
  1227.             throws IOException {
  1228.         boolean hasWorkingTreeIterator = tw.getTreeCount() > T_FILE;
  1229.         boolean hasAttributeNodeProvider = treeWalk
  1230.                 .getAttributesNodeProvider() != null;
  1231.         while (treeWalk.next()) {
  1232.             if (!processEntry(
  1233.                     treeWalk.getTree(T_BASE, CanonicalTreeParser.class),
  1234.                     treeWalk.getTree(T_OURS, CanonicalTreeParser.class),
  1235.                     treeWalk.getTree(T_THEIRS, CanonicalTreeParser.class),
  1236.                     treeWalk.getTree(T_INDEX, DirCacheBuildIterator.class),
  1237.                     hasWorkingTreeIterator ? treeWalk.getTree(T_FILE,
  1238.                             WorkingTreeIterator.class) : null,
  1239.                     ignoreConflicts, hasAttributeNodeProvider
  1240.                             ? treeWalk.getAttributes()
  1241.                             : NO_ATTRIBUTES)) {
  1242.                 cleanUp();
  1243.                 return false;
  1244.             }
  1245.             if (treeWalk.isSubtree() && enterSubtree)
  1246.                 treeWalk.enterSubtree();
  1247.         }
  1248.         return true;
  1249.     }
  1250. }