git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Elijah Newren <newren@gmail.com>
To: Git Mailing List <git@vger.kernel.org>
Cc: Jonathan Nieder <jrnieder@gmail.com>, Elijah Newren <newren@gmail.com>
Subject: Re: [RFC PATCH 7/7] merge: fix misleading pre-merge check documentation
Date: Wed, 6 Jun 2018 22:27:31 -0700	[thread overview]
Message-ID: <CABPp-BGZiM=9bXHw0_90x43k51rCNRisM9ccGVRVwQxWkntiBA@mail.gmail.com> (raw)
In-Reply-To: <20180603065810.23841-8-newren@gmail.com>

On Sat, Jun 2, 2018 at 11:58 PM, Elijah Newren <newren@gmail.com> wrote:
> builtin/merge.c contains this important requirement for merge strategies:
>
>     ...the index must be in sync with the head commit.  The strategies are
>     responsible to ensure this.
>
> However, Documentation/git-merge.txt says:
>
>     ...[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.)
>
> Interestingly, prior to commit c0be8aa06b85 ("Documentation/git-merge.txt:
> Partial rewrite of How Merge Works", 2008-07-19),
> Documentation/git-merge.txt said much more:
>
>     ...the index file must match the tree of `HEAD` commit...
>     [NOTE]
>     This is a bit of a lite.  In certain special cases [explained
>     in detail]...
>     Otherwise, merge will refuse to do any harm to your repository
>     (that is...your working tree...and index are left intact).
>
> So, this suggests that the exceptions existed because there were special
> cases where it would case no harm, and potentially be slightly more
> convenient for the user.  While the current text in git-merge.txt does
> list a condition under which it would be safe to proceed despite the index
> not matching HEAD, it does not match what is actually implemented, in
> three different ways:
>
>     * The exception is written to describe what unpack-trees allows.  Not
>       all merge strategies allow such an exception, though, making this
>       description misleading.  'ours' and 'octopus' merges have strictly
>       enforced index==HEAD for a while, and the commit previous to this
>       one made 'recursive' do so as well.
>
>     * If someone did a three-way content merge on a specific file using
>       versions from the relevant commits and staged it prior to running
>       merge, then that path would technically satisfy the exception listed
>       in git-merge.txt.  unpack-trees.c would still error out on the path,
>       though, because it defers the three-way content merge logic to other
>       parts of the code (resolve, octopus, or recursive) and has no way of
>       checking whether the index entry from before the merge will match
>       the end result of the merge.
>
>     * The exception as implemented in unpack-trees actually only checked
>       that the index matched the MERGE_HEAD version of the file and that
>       HEAD matched the merge base.  Assuming no renames, that would indeed
>       provide cases where the index matches the end result we'd get from a
>       merge.  But renames means unpack-trees is checking that it instead
>       matches something other than what the final result will be, risking
>       either erroring out when we shouldn't need to, or not erroring out
>       when we should and overwriting the user's staged changes.
>
> In addition to the wording behind this exception being misleading, it is
> also somewhat surprising to see how many times the code for the special
> cases were wrong or the check to make sure the index matched head was
> forgotten altogether:
>
> * Prior to commit ee6566e8d70d ("[PATCH] Rewrite read-tree", 2005-09-05),
>   there were many cases where an unclean index entry was allowed (look for
>   merged_entry_allow_dirty()); it appears that in those cases, the merge
>   would have simply overwritten staged changes with the result of the
>   merge.  Thus, the merge result would have been correct, but the user's
>   uncommitted changes could be thrown away without warning.
>
> * Prior to commit 160252f81626 ("git-merge-ours: make sure our index
>   matches HEAD", 2005-11-03), the 'ours' merge strategy did not check
>   whether the index matched HEAD.  If it didn't, the resulting merge
>   would include all the staged changes, and thus wasn't really an 'ours'
>   strategy.
>
> * Prior to commit 3ec62ad9ffba ("merge-octopus: abort if index does not
>   match HEAD", 2016-04-09), 'octopus' merges did not check whether the
>   index matched HEAD, also resulting in any staged changes from before
>   the commit silently being folded into the resulting merge.  commit
>   a6ee883b8eb5 ("t6044: new merge testcases for when index doesn't match
>   HEAD", 2016-04-09) was also added at the same time to try to test to
>   make sure all strategies did the necessary checking for the requirement
>   that the index match HEAD.  Sadly, it didn't catch all the cases, as
>   evidenced by the remainder of this list...
>
> * Prior to commit 65170c07d466 ("merge-recursive: avoid incorporating
>   uncommitted changes in a merge", 2017-12-21), merge-recursive simply
>   relied on unpack_trees() to do the necessary check, but in one special
>   case it avoided calling unpack_trees() entirely and accidentally ended
>   up silently including any staged changes from before the merge in the
>   resulting merge commit.
>
> * The commit immediately before this one in this series noted that the
>   exceptions were written in a way that assumed no renames, making it
>   unsafe for merge-recursive to use.  merge-recursive was modified to
>   use its own check to enforce that index==HEAD.
>
> This history makes it very tempting to go into builtin/merge.c and replace
> the comment that strategies must enforce that index matches HEAD with code
> that just enforces it.  At this point, that would only affect the
> 'resolve' strategy; all other strategies have each been modified to
> manually enforce it.

I'm curious if anyone has comments on this last paragraph above.
Would anyone object to strictly enforcing index matches HEAD before
all types of merges?

  reply	other threads:[~2018-06-07  5:27 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-06-03  6:58 [RFC PATCH 0/7] merge requirement: index matches head Elijah Newren
2018-06-03  6:58 ` [RFC PATCH 1/7] t6044: verify that merges expected to abort actually abort Elijah Newren
2018-06-03  6:58 ` [RFC PATCH 2/7] t6044: add a testcase for index matching head, when head doesn't match HEAD Elijah Newren
2018-06-03  6:58 ` [RFC PATCH 3/7] merge-recursive: make sure when we say we abort that we actually abort Elijah Newren
2018-06-03  6:58 ` [RFC PATCH 4/7] merge-recursive: fix assumption that head tree being merged is HEAD Elijah Newren
2018-06-03 13:52   ` Ramsay Jones
2018-06-03 23:37     ` brian m. carlson
2018-06-04  2:26       ` Ramsay Jones
2018-06-04  3:19   ` Junio C Hamano
2018-06-05  7:14     ` Elijah Newren
2018-06-11 16:15       ` Elijah Newren
2018-06-03  6:58 ` [RFC PATCH 5/7] t6044: add more testcases with staged changes before a merge is invoked Elijah Newren
2018-06-03  6:58 ` [RFC PATCH 6/7] merge-recursive: enforce rule that index matches head before merging Elijah Newren
2018-06-03  6:58 ` [RFC PATCH 7/7] merge: fix misleading pre-merge check documentation Elijah Newren
2018-06-07  5:27   ` Elijah Newren [this message]
2018-07-01  1:24 ` [PATCH v2 0/9] Fix merge issues with index not matching HEAD Elijah Newren
2018-07-01  1:24   ` [PATCH v2 1/9] read-cache.c: move index_has_changes() from merge.c Elijah Newren
2018-07-01  1:24   ` [PATCH v2 2/9] index_has_changes(): avoid assuming operating on the_index Elijah Newren
2018-07-03 19:44     ` Junio C Hamano
2018-07-01  1:24   ` [PATCH v2 3/9] t6044: verify that merges expected to abort actually abort Elijah Newren
2018-07-01  1:24   ` [PATCH v2 4/9] t6044: add a testcase for index matching head, when head doesn't match HEAD Elijah Newren
2018-07-10 20:39     ` SZEDER Gábor
2018-07-11  3:09       ` [RFC PATCH 2/7] " Elijah Newren
2018-07-01  1:24   ` [PATCH v2 5/9] merge-recursive: make sure when we say we abort that we actually abort Elijah Newren
2018-07-01  1:25   ` [PATCH v2 6/9] merge-recursive: fix assumption that head tree being merged is HEAD Elijah Newren
2018-07-03 19:57     ` Junio C Hamano
2018-07-01  1:25   ` [PATCH v2 7/9] t6044: add more testcases with staged changes before a merge is invoked Elijah Newren
2018-07-01  1:25   ` [PATCH v2 8/9] merge-recursive: enforce rule that index matches head before merging Elijah Newren
2018-07-03 20:05     ` Junio C Hamano
2018-07-01  1:25   ` [PATCH v2 9/9] merge: fix misleading pre-merge check documentation Elijah Newren

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CABPp-BGZiM=9bXHw0_90x43k51rCNRisM9ccGVRVwQxWkntiBA@mail.gmail.com' \
    --to=newren@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=jrnieder@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).