Subject: Re: Opinions on changing add/add conflict resolution?

From: Ævar Arnfjörð Bjarmason <[email-masked]>
Date: Mon, 12 Mar 2018 23:19:45 +0100

On Mon, Mar 12 2018, Elijah Newren jotted:

> Hi everyone,
>
> I'd like to change add/add conflict resolution.  Currently when such a
> conflict occurs (say at ${path}), git unconditionally does a two-way
> merge of the two files and sticks the result in the working tree at
> ${path}.
>
> I would like to make it instead first check whether the two files are
> similar; if they are, then do the two-way merge, but if they're not,
> then instead write the two files out to separate paths (${path}~HEAD
> and ${path}~$MERGE, while making sure that ${path} is removed from the
> working copy).
>
> Thoughts?
>
> I have a patch series[1] with more details and other changes, but
> wanted to especially get feedback on this issue even from folks that
> didn't have enough time to read the patches or even the cover letter.

Does this mean that e.g. in this case of merging two files, one
containing "foo" and one containing "bar":

    (
        rm -rf /tmp/test.git &&
        git init /tmp/test.git &&
        cd /tmp/test.git &&
        echo foo >README &&
        git add README &&
        git commit -mfoo &&
        git checkout --orphan trunk &&
        git reset --hard &&
        echo bar >README &&
        git add README &&
        git commit -mbar &&
        git merge --allow-unrelated-histories master;
        cat README
    )

That instead of getting:

    <<<<<<< HEAD
    bar
    =======
    foo
    >>>>>>> master

I'd now get these split into different files?

I'm assuming by similarity you're talking about the same heuristic we
apply for git diff -M, i.e. if "moving" a file would consider it
removed/added instead of moved you'd want two files instead of the
two-way merge.

I don't mind this being a configurable option if you want it, but I
don't think it should be on by default, reasons:

 1) There's lots of cases where we totally screw up the "is this
    similar?" check, in particular with small files.

    E.g. let's say you have a config file like 'fs-path "/tmp/git"' and
    in two branches you change that to 'fs-path "/opt/git"' and 'fs-path
    "/var/git"'. The rename detection will think this these have nothing
    to do with each other since they share no common lines, but to a
    human reader they're really similar, and would make sense in the
    context of resolving a bigger merge where /{opt,var}/git changes are
    conflicting.

    This is not some theoretical concern, there's lots of things that
    e.g. use small 5-10 line config files to configure some app that
    because of some combo of indentation changes and changing a couple
    of lines will make git's rename detection totally give up, but to a
    human reader they're 95% the same.

 2) This will play havoc with already established merge tools on top of
    git which a lot of users use instead of manually resolving these in
    vi or whatever.

    If we made this the default they'd need to to deal with this new
    state, and even if it's not the default we'll have some confused
    users wondering why Emacs Ediff or whatever isn't showing the right
    thing because it isn't supporting this yet.

So actually, given that last point in #2 I'm slightly negative on the
whole thing, but maybe splitting it into some new format existing tools
don't understand is compelling enough to justify the downstream breakage.

I don't think we've ever documented the format we leave the tree in
after a failed merge as equivalent to plumbing, but for the purposes of
tools that build on top of git it really is.