Skip to content
  • Elijah Newren's avatar
    merge-recursive: enforce rule that index matches head before merging · eddd1a41
    Elijah Newren authored and Junio C Hamano's avatar Junio C Hamano committed
    
    
    builtin/merge.c says that when we are about to perform a merge:
    
        ...the index must be in sync with the head commit.  The strategies are
        responsible to ensure this.
    
    merge-recursive has always relied on unpack_trees() to enforce this
    requirement, except in the case of an "Already up to date!" merge.
    unpack-trees.c does not actually enforce this requirement, though.  It
    allows for a pair of exceptions, in cases which it refers to as #14(ALT)
    and #2ALT.  Documentation/technical/trivial-merge.txt can be consulted for
    the precise meanings of the various case numbers and their meanings for
    unpack-trees.c, but we have a high-level description of the intent behind
    these two exceptions in a combined and summarized form in
    Documentation/git-merge.txt:
    
        ...[merge will] abort if there are any changes registered in the index
        relative to the `HEAD` commit.  (One exception is when the changed index
        entries are in the state that would result from the merge already.)
    
    While this high-level description does describe conditions under which it
    would be safe to allow the index to diverge from HEAD, it does not match
    what is actually implemented.  In particular, unpack-trees.c has no
    knowledge of renames, and these two exceptions were written assuming that
    no renames take place.  Once renames get into the mix, it is no longer
    safe to allow the index to not match for #2ALT.  We could modify
    unpack-trees to only allow #14(ALT) as an exception, but that would be
    more strict than required for the resolve strategy (since the resolve
    strategy doesn't handle renames at all).  Therefore, unpack_trees.c seems
    like the wrong place to fix this.
    
    Further, if someone fixes the combination of break and rename detection
    and modifies merge-recursive to take advantage of the combination, then it
    will also no longer be safe to allow the index to not match for #14(ALT)
    when the recursive strategy is in use.  Therefore, leaving one of the
    exceptions in place with the recursive merge strategy feels like we are
    just leaving a latent bug in the code for folks in the future to stumble
    across.
    
    It may be possible to fix both unpack-trees and merge-recursive in a way
    that implements the exception as stated in Documentation/git-merge.txt,
    but it would be somewhat complex, possibly also buggy at first, and
    ultimately, not all that valuable.  Instead, just enforce the requirement
    stated in builtin/merge.c; error out if the index does not match the HEAD
    commit, just like the 'ours' and 'octopus' strategies do.
    
    Some testcase fixups were in order:
      t7611: had many tests designed to show that `git merge --abort` could
    	 not always restore the index and working tree to the state they
    	 were in before the merge started.  The tests that were associated
    	 with having changes in the index before the merge started are no
             longer applicable, so they have been removed.
      t7504: had a few tests that had stray staged changes that were not
             actually part of the test under consideration
      t6044: We no longer expect stray staged changes to sometimes result
             in the merge continuing.  Also, fix a case where a merge
             didn't abort but should have.
    
    Signed-off-by: default avatarElijah Newren <newren@gmail.com>
    Signed-off-by: default avatarJunio C Hamano <gitster@pobox.com>
    eddd1a41