Class ResolveMerger

Direct Known Subclasses:
RecursiveMerger

public class ResolveMerger extends ThreeWayMerger
A three-way merger performing a content-merge if necessary
  • Field Details

    • tw

      protected NameConflictTreeWalk tw
      The tree walk which we'll iterate over to merge entries.
      Since:
      3.4
    • commitNames

      protected String[] commitNames
      string versions of a list of commit SHA1s
      Since:
      3.0
    • T_BASE

      protected static final int T_BASE
      Index of the base tree within the tree walk.
      Since:
      3.4
      See Also:
    • T_OURS

      protected static final int T_OURS
      Index of our tree in withthe tree walk.
      Since:
      3.4
      See Also:
    • T_THEIRS

      protected static final int T_THEIRS
      Index of their tree within the tree walk.
      Since:
      3.4
      See Also:
    • T_INDEX

      protected static final int T_INDEX
      Index of the index tree within the tree walk.
      Since:
      3.4
      See Also:
    • T_FILE

      protected static final int T_FILE
      Index of the working directory tree within the tree walk.
      Since:
      3.4
      See Also:
    • builder

      protected DirCacheBuilder builder
      Builder to update the cache during this merge.
      Since:
      3.4
    • resultTree

      protected ObjectId resultTree
      merge result as tree
      Since:
      3.0
    • unmergedPaths

      protected List<String> unmergedPaths
      Paths that could not be merged by this merger because of an unsolvable conflict.
      Since:
      3.4
    • modifiedFiles

      protected List<String> modifiedFiles
      Files modified during this merge operation.
      Since:
      3.4
    • toBeCheckedOut

      protected Map<String,DirCacheEntry> toBeCheckedOut
      If the merger has nothing to do for a file but check it out at the end of the operation, it can be added here.
      Since:
      3.4
    • toBeDeleted

      protected List<String> toBeDeleted
      Paths in this list will be deleted from the local copy at the end of the operation.
      Since:
      3.4
    • mergeResults

      protected Map<String,MergeResult<? extends Sequence>> mergeResults
      Low-level textual merge results. Will be passed on to the callers in case of conflicts.
      Since:
      3.4
    • failingPaths

      protected Map<String,ResolveMerger.MergeFailureReason> failingPaths
      Paths for which the merge failed altogether.
      Since:
      3.4
    • enterSubtree

      protected boolean enterSubtree
      Updated as we merge entries of the tree walk. Tells us whether we should recurse into the entry if it is a subtree.
      Since:
      3.4
    • inCore

      protected boolean inCore
      Set to true if this merge should work in-memory. The repos dircache and workingtree are not touched by this method. Eventually needed files are created as temporary files and a new empty, in-memory dircache will be used instead the repo's one. Often used for bare repos where the repo doesn't even have a workingtree and dircache.
      Since:
      3.0
    • implicitDirCache

      protected boolean implicitDirCache
      Set to true if this merger should use the default dircache of the repository and should handle locking and unlocking of the dircache. If this merger should work in-core or if an explicit dircache was specified during construction then this field is set to false.
      Since:
      3.0
    • dircache

      protected DirCache dircache
      Directory cache
      Since:
      3.0
    • workingTreeIterator

      protected WorkingTreeIterator workingTreeIterator
      The iterator to access the working tree. If set to null this merger will not touch the working tree.
      Since:
      3.0
    • mergeAlgorithm

      protected MergeAlgorithm mergeAlgorithm
      our merge algorithm
      Since:
      3.0
    • workingTreeOptions

      protected WorkingTreeOptions workingTreeOptions
      The WorkingTreeOptions are needed to determine line endings for merged files.
      Since:
      4.11
    • inCoreLimit

      private int inCoreLimit
      The size limit (bytes) which controls a file to be stored in Heap or LocalFile during the merge.
    • contentStrategy

      @NonNull private ContentMergeStrategy contentStrategy
      The ContentMergeStrategy to use for "resolve" and "recursive" merges.
    • checkoutMetadata

      private Map<String,DirCacheCheckout.CheckoutMetadata> checkoutMetadata
    • cleanupMetadata

      private Map<String,DirCacheCheckout.CheckoutMetadata> cleanupMetadata
    • NO_ATTRIBUTES

      private static final Attributes NO_ATTRIBUTES
  • Constructor Details

    • ResolveMerger

      protected ResolveMerger(Repository local, boolean inCore)
      Constructor for ResolveMerger.
      Parameters:
      local - the Repository.
      inCore - a boolean.
    • ResolveMerger

      protected ResolveMerger(Repository local)
      Constructor for ResolveMerger.
      Parameters:
      local - the Repository.
    • ResolveMerger

      protected ResolveMerger(ObjectInserter inserter, Config config)
      Constructor for ResolveMerger.
      Parameters:
      inserter - an ObjectInserter object.
      config - the repository configuration
      Since:
      4.8
  • Method Details

    • getMergeAlgorithm

      private static MergeAlgorithm getMergeAlgorithm(Config config)
    • getInCoreLimit

      private static int getInCoreLimit(Config config)
    • defaultCommitNames

      private static String[] defaultCommitNames()
    • getContentMergeStrategy

      @NonNull public ContentMergeStrategy getContentMergeStrategy()
      Retrieves the content merge strategy for content conflicts.
      Returns:
      the ContentMergeStrategy in effect
      Since:
      5.12
    • setContentMergeStrategy

      public void setContentMergeStrategy(ContentMergeStrategy strategy)
      Sets the content merge strategy for content conflicts.
      Parameters:
      strategy - ContentMergeStrategy to use
      Since:
      5.12
    • mergeImpl

      protected boolean mergeImpl() throws IOException
      Execute the merge.

      This method is called from Merger.merge(AnyObjectId[]) after the Merger.sourceObjects, Merger.sourceCommits and Merger.sourceTrees have been populated.

      Specified by:
      mergeImpl in class Merger
      Returns:
      true if the merge was completed without conflicts; false if the merge strategy cannot handle this merge or there were conflicts preventing it from automatically resolving all paths.
      Throws:
      IncorrectObjectTypeException - one of the input objects is not a commit, but the strategy requires it to be a commit.
      IOException - one or more sources could not be read, or outputs could not be written to the Repository.
    • checkout

      private void checkout() throws NoWorkTreeException, IOException
      Throws:
      NoWorkTreeException
      IOException
    • cleanUp

      protected void cleanUp() throws NoWorkTreeException, CorruptObjectException, IOException
      Reverts the worktree after an unsuccessful merge. We know that for all modified files the old content was in the old index and the index contained only stage 0. In case if inCore operation just clear the history of modified files.
      Throws:
      IOException
      CorruptObjectException
      NoWorkTreeException
      Since:
      3.4
    • add

      private DirCacheEntry add(byte[] path, CanonicalTreeParser p, int stage, Instant lastMod, long len)
      adds a new path with the specified stage to the index builder
      Parameters:
      path -
      p -
      stage -
      lastMod -
      len -
      Returns:
      the entry which was added to the index
    • keep

      private DirCacheEntry keep(DirCacheEntry e)
      adds a entry to the index builder which is a copy of the specified DirCacheEntry
      Parameters:
      e - the entry which should be copied
      Returns:
      the entry which was added to the index
    • addCheckoutMetadata

      protected void addCheckoutMetadata(Map<String,DirCacheCheckout.CheckoutMetadata> map, String path, Attributes attributes) throws IOException
      Remembers the DirCacheCheckout.CheckoutMetadata for the given path; it may be needed in checkout() or in cleanUp().
      Parameters:
      map - to add the metadata to
      path - of the current node
      attributes - to use for determining the metadata
      Throws:
      IOException - if the smudge filter cannot be determined
      Since:
      6.1
    • addToCheckout

      protected void addToCheckout(String path, DirCacheEntry entry, Attributes[] attributes) throws IOException
      Adds a DirCacheEntry for direct checkout and remembers its DirCacheCheckout.CheckoutMetadata.
      Parameters:
      path - of the entry
      entry - to add
      attributes - the Attributes of the trees
      Throws:
      IOException - if the DirCacheCheckout.CheckoutMetadata cannot be determined
      Since:
      6.1
    • addDeletion

      protected void addDeletion(String path, boolean isFile, Attributes attributes) throws IOException
      Remember a path for deletion, and remember its DirCacheCheckout.CheckoutMetadata in case it has to be restored in cleanUp().
      Parameters:
      path - of the entry
      isFile - whether it is a file
      attributes - to use for determining the DirCacheCheckout.CheckoutMetadata
      Throws:
      IOException - if the DirCacheCheckout.CheckoutMetadata cannot be determined
      Since:
      5.1
    • processEntry

      protected boolean processEntry(CanonicalTreeParser base, CanonicalTreeParser ours, CanonicalTreeParser theirs, DirCacheBuildIterator index, WorkingTreeIterator work, boolean ignoreConflicts, Attributes[] attributes) throws MissingObjectException, IncorrectObjectTypeException, CorruptObjectException, IOException
      Processes one path and tries to merge taking git attributes in account. This method will do all trivial (not content) merges and will also detect if a merge will fail. The merge will fail when one of the following is true
      • the index entry does not match the entry in ours. When merging one branch into the current HEAD, ours will point to HEAD and theirs will point to the other branch. It is assumed that the index matches the HEAD because it will only not match HEAD if it was populated before the merge operation. But the merge commit should not accidentally contain modifications done before the merge. Check the git read-tree documentation for further explanations.
      • A conflict was detected and the working-tree file is dirty. When a conflict is detected the content-merge algorithm will try to write a merged version into the working-tree. If the file is dirty we would override unsaved data.
      Parameters:
      base - the common base for ours and theirs
      ours - the ours side of the merge. When merging a branch into the HEAD ours will point to HEAD
      theirs - the theirs side of the merge. When merging a branch into the current HEAD theirs will point to the branch which is merged into HEAD.
      index - the index entry
      work - the file in the working tree
      ignoreConflicts - see mergeTrees(AbstractTreeIterator, RevTree, RevTree, boolean)
      attributes - the Attributes for the three trees
      Returns:
      false if the merge will fail because the index entry didn't match ours or the working-dir file was dirty and a conflict occurred
      Throws:
      MissingObjectException
      IncorrectObjectTypeException
      CorruptObjectException
      IOException
      Since:
      6.1
    • createGitLinksMergeResult

      private static MergeResult<SubmoduleConflict> createGitLinksMergeResult(CanonicalTreeParser base, CanonicalTreeParser ours, CanonicalTreeParser theirs)
    • contentMerge

      Does the content merge. The three texts base, ours and theirs are specified with CanonicalTreeParser. If any of the parsers is specified as null then an empty text will be used instead.
      Parameters:
      base -
      ours -
      theirs -
      attributes -
      strategy -
      Returns:
      the result of the content merge
      Throws:
      BinaryBlobException - if any of the blobs looks like a binary blob
      IOException
    • isIndexDirty

      private boolean isIndexDirty()
    • isWorktreeDirty

      private boolean isWorktreeDirty(WorkingTreeIterator work, DirCacheEntry ourDce) throws IOException
      Throws:
      IOException
    • updateIndex

      private void updateIndex(CanonicalTreeParser base, CanonicalTreeParser ours, CanonicalTreeParser theirs, MergeResult<RawText> result, Attributes attributes) throws FileNotFoundException, IOException
      Updates the index after a content merge has happened. If no conflict has occurred this includes persisting the merged content to the object database. In case of conflicts this method takes care to write the correct stages to the index.
      Parameters:
      base -
      ours -
      theirs -
      result -
      attributes -
      Throws:
      FileNotFoundException
      IOException
    • writeMergedFile

      private File writeMergedFile(TemporaryBuffer rawMerged, Attributes attributes) throws FileNotFoundException, IOException
      Writes merged file content to the working tree.
      Parameters:
      rawMerged - the raw merged content
      attributes - the files .gitattributes entries
      Returns:
      the working tree file to which the merged content was written.
      Throws:
      FileNotFoundException
      IOException
    • doMerge

      private TemporaryBuffer doMerge(MergeResult<RawText> result) throws IOException
      Throws:
      IOException
    • insertMergeResult

      private ObjectId insertMergeResult(TemporaryBuffer buf, Attributes attributes) throws IOException
      Throws:
      IOException
    • mergeFileModes

      private int mergeFileModes(int modeB, int modeO, int modeT)
      Try to merge filemodes. If only ours or theirs have changed the mode (compared to base) we choose that one. If ours and theirs have equal modes return that one. If also that is not the case the modes are not mergeable. Return FileMode.MISSING int that case.
      Parameters:
      modeB - filemode found in BASE
      modeO - filemode found in OURS
      modeT - filemode found in THEIRS
      Returns:
      the merged filemode or FileMode.MISSING in case of a conflict
    • getRawText

      private RawText getRawText(ObjectId id, Attributes attributes) throws IOException, BinaryBlobException
      Throws:
      IOException
      BinaryBlobException
    • nonTree

      private static boolean nonTree(int mode)
    • isGitLink

      private static boolean isGitLink(int mode)
    • getResultTreeId

      public ObjectId getResultTreeId()
      Get resulting tree.
      Specified by:
      getResultTreeId in class Merger
      Returns:
      resulting tree, if Merger.merge(AnyObjectId[]) returned true.
    • setCommitNames

      public void setCommitNames(String[] commitNames)
      Set the names of the commits as they would appear in conflict markers
      Parameters:
      commitNames - the names of the commits as they would appear in conflict markers
    • getCommitNames

      public String[] getCommitNames()
      Get the names of the commits as they would appear in conflict markers.
      Returns:
      the names of the commits as they would appear in conflict markers.
    • getUnmergedPaths

      public List<String> getUnmergedPaths()
      Get the paths with conflicts. This is a subset of the files listed by getModifiedFiles()
      Returns:
      the paths with conflicts. This is a subset of the files listed by getModifiedFiles()
    • getModifiedFiles

      public List<String> getModifiedFiles()
      Get the paths of files which have been modified by this merge.
      Returns:
      the paths of files which have been modified by this merge. A file will be modified if a content-merge works on this path or if the merge algorithm decides to take the theirs-version. This is a superset of the files listed by getUnmergedPaths().
    • getToBeCheckedOut

      public Map<String,DirCacheEntry> getToBeCheckedOut()
      Get a map which maps the paths of files which have to be checked out because the merge created new fully-merged content for this file into the index.
      Returns:
      a map which maps the paths of files which have to be checked out because the merge created new fully-merged content for this file into the index. This means: the merge wrote a new stage 0 entry for this path.
    • getMergeResults

      public Map<String,MergeResult<? extends Sequence>> getMergeResults()
      Get the mergeResults
      Returns:
      the mergeResults
    • getFailingPaths

      public Map<String,ResolveMerger.MergeFailureReason> getFailingPaths()
      Get list of paths causing this merge to fail (not stopped because of a conflict).
      Returns:
      lists paths causing this merge to fail (not stopped because of a conflict). null is returned if this merge didn't fail.
    • failed

      public boolean failed()
      Returns whether this merge failed (i.e. not stopped because of a conflict)
      Returns:
      true if a failure occurred, false otherwise
    • setDirCache

      public void setDirCache(DirCache dc)
      Sets the DirCache which shall be used by this merger. If the DirCache is not set explicitly and if this merger doesn't work in-core, this merger will implicitly get and lock a default DirCache. If the DirCache is explicitly set the caller is responsible to lock it in advance. Finally the merger will call DirCache.commit() which requires that the DirCache is locked. If the mergeImpl() returns without throwing an exception the lock will be released. In case of exceptions the caller is responsible to release the lock.
      Parameters:
      dc - the DirCache to set
    • setWorkingTreeIterator

      public void setWorkingTreeIterator(WorkingTreeIterator workingTreeIterator)
      Sets the WorkingTreeIterator to be used by this merger. If no WorkingTreeIterator is set this merger will ignore the working tree and fail if a content merge is necessary.

      TODO: enhance WorkingTreeIterator to support write operations. Then this merger will be able to merge with a different working tree abstraction.

      Parameters:
      workingTreeIterator - the workingTreeIt to set
    • mergeTrees

      protected boolean mergeTrees(AbstractTreeIterator baseTree, RevTree headTree, RevTree mergeTree, boolean ignoreConflicts) throws IOException
      The resolve conflict way of three way merging
      Parameters:
      baseTree - a AbstractTreeIterator object.
      headTree - a RevTree object.
      mergeTree - a RevTree object.
      ignoreConflicts - Controls what to do in case a content-merge is done and a conflict is detected. The default setting for this should be false. In this case the working tree file is filled with new content (containing conflict markers) and the index is filled with multiple stages containing BASE, OURS and THEIRS content. Having such non-0 stages is the sign to git tools that there are still conflicts for that path.

      If true is specified the behavior is different. In case a conflict is detected the working tree file is again filled with new content (containing conflict markers). But also stage 0 of the index is filled with that content. No other stages are filled. Means: there is no conflict on that path but the new content (including conflict markers) is stored as successful merge result. This is needed in the context of RecursiveMerger where when determining merge bases we don't want to deal with content-merge conflicts.

      Returns:
      whether the trees merged cleanly
      Throws:
      IOException
      Since:
      3.5
    • mergeTreeWalk

      protected boolean mergeTreeWalk(TreeWalk treeWalk, boolean ignoreConflicts) throws IOException
      Process the given TreeWalk's entries.
      Parameters:
      treeWalk - The walk to iterate over.
      ignoreConflicts - see mergeTrees(AbstractTreeIterator, RevTree, RevTree, boolean)
      Returns:
      Whether the trees merged cleanly.
      Throws:
      IOException
      Since:
      3.5