Edward Thomson <ethomson@xxxxxxxxxxxxx> writes: > What was surprising to me was that my merge can proceed if I stage a change > that is identical to the merge result. That is, if my merge result would > be to take the contents from "theirs", then my merge can proceed if I've > already staged the same contents: > > input result > anc ours theirs idx wd merge result idx wd > 4 A A B B B take B B B > 5 A A B B C take B B C > > This seems unexpected - is there a use-case that this enables or is > this accidental? Both are very much on purpose. The integrator may have seen the patch on the list, ran "git apply [--index]" on it to contemplate on it, and before commiting the result, saw a pull request for a branch that contains the change. The above two allow the pull from such a state to succeed without losing any information. I think we have a similar table in Documentation/technical area that explains these things, by the way. > Another surprising result was that if I have deleted a file (and staged > the deletion or not) then the merge will proceed and the file in question > will be recreated. Consider "X" to be a missing file: > > input result > anc ours theirs idx wd merge result idx wd > 6 A A B A X take B B B > 7 A A B X X take B B B I am not sure about #7, but #6 is done very much on purpose. The lower level merge machinery deliberately equates "in index but not checked out to the working tree" state and "in index and not modified in the working tree" state; this is to support a merge done in a temporary working area that starts out empty. This was designed really long time ago (read: during the first two weeks of Git development, back when there were no "stash" nor "remote tracking branches"), with a vision to make this scenario work nicely: You have checked out 'master' branch and you are working on it. You see a more urgent pull request on 'maint' branch. But your working tree for 'master' is no shape to commit, yet. Without disturbing the working area you are using to advance the 'master' branch, you could do the merge "only in the index" by doing: * Fetch the requested commit: $ git fetch $over_there refs/heads/master * Populate a temporary index with the contents of your 'maint': $ GIT_INDEX_FILE=,,temp-index GIT_DIR=$(pwd)/.git $ export GIT_INDEX_FILE GIT_DIR $ git read-tree refs/heads/maint * Create an empty temporary working area and go there: $ mkdir ,,temp-merge $ cd ,,temp-merge * Run the three-way merge between your 'maint' and the requested commit: $ MB=$(git merge-base FETCH_HEAD maint) $ git read-tree -m -u $MB maint FETCH_HEAD Notice that we start without _any_ file in that temporary working area (,,temp-merge directory). In the last step, because the merge machinery (read-tree -m -u) treats missing files as "they are unmodified by us; we didn't even bother checking them out of the index", we will see _only_ the files that are different from our 'maint' and files that needs our help to get conflicts resolved in the temporary working area after the command finishes. You inspect them, resolve conflicts and run "git update-index" on them (remember, there weren't "git add" or "git commit -a"), write the resulting index as a tree with "git write-tree" and record the tree with "git commit-tree -p maint -p FETCH_HEAD" (actually, back then "commit-tree -p" insisted on getting raw tree object names, so you had to do the equivalent of "git rev-parse maint^{tree}" there) and then update your 'maint' branch with the resulting commit. If there is no conflict to be resolved, then you essentially can run a script that does all of the above (and cleans up the temporary directory ,,temp-merge and the temporary index) to implement "Can perform a merge into a branch that is not currently checked out, without disturbing my current work" feature. And this "missing files are unmodified---I didn't even bother to check them out of the index" was done as an integral part of it. Back when we (IIRC, mostly between Linus and I) were discussing this design, it did come up that in the normal case of "I am merging in my working tree", this behaviour would lose information, but "I'm planning to remove this" is only a single bit and lossage of that was judged to be trivially small and easily recoverable compared to the benefit of being able to do a merge in an empty working tree, and that is where this behaviour comes from. We could certainly revisit this design and make the behaviour optional. When somebody wants to do the "Can perform a merge into a branch that is not currently checked out, without disturbing my current work" feature, its implementation needs to be able to turn it back on, but for doing everything else we do not have to treat a missing file as unmodified. -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html