Gioele Barabucci <gioele@xxxxxxxxx> writes: > it seems to me that merge drivers are not called while merging commits > that touch locally modified (but uncommited) files. Is this correct? Yes. "git merge" first notices this situation and stops before it has to decide which merge driver to use. When you try to merge commit 'B' when you are at commit 'A', and have some local changes, and these two branches were forked from a common ancestor 'X', the history may look like this: 1 / X--o--A \ --o--B where '1' is a hypothetical commit that would result if you were to make a commit with all your local changes, i.e. diff(1,A) is your uncommitted changes. As usual, time flows from left to right. When you merge branch 'B' into your history, you would want to end up with this history (tentatively ignoring what is in the working tree): X--o--A--M \ / --o--B where 'M' is the merge between 'A' and 'B', and the change diff(M,A) must represent what happened between 'X' and 'B' that did not happen between 'X' and 'A'. When A and B are independent and without conflict, that is roughly the same as diff(B,X), in other words, M is roughly the same as patch(A,diff(B,X)). As you haven't committed your local changes, diff(1,A) must not participate in computing the result M of this merge. After this merge is done, the blob in M is checked out to the working tree, but doing so by overwriting the working tree files would lose your local changes, and that is the reason why you see this error message: > error: Your local changes to the following files would > be overwritten by merge: > .local/share/pw/passwords > Please, commit your changes or stash them before you can merge. What you would want at the very end with is like this: 1 2 / / X--o--A--M \ / --o--B where '2' is a hypothetical commit that would result if you were to cherry pick '1' on top of 'M', after making 'M' according to thediscussion above (i.e. ignoring the local changes you made since 'A'). But just like you did not have '1' because you were not ready to record your changes based on 'A' as a commit, you are not ready to actually make this commit '2', so you would want your head to be at 'M' and the state of '2' in your working tree, leaving diff(2,M) as the local uncommitted change. However. "git merge" does not do the "create the hypothetical commit '1'" to store away the local changes, and it does not do the "cherry pick '1' to create the hypothetical commit '2'" to forward-port the local changes on top of the merge result 'M'. This is primarily because there are two distinct steps in the above hypothetifcal "enhanced" merge. Creating 'M' may conflict and you would have to resolve it, while "git merge" somehow need to remember it has to further do the "cherry pick of '1'" on the result (but there is no facility to do so in the system). And after you resolve the conflict to help it create the merge result 'M', it has to somehow remember that it needs to "cherry-pick --no-commit '1'", and have the user resolve the conflict. As the presence of '1' is not made explicit to the user (we do not even create '1'), when the latter step of patch(M,diff(1,A)) fails in conflicts, it is hard for the user to attempt to resolve them starting from scratch, which likely leads to "I lost the local change" when in fact it is more like "I had some local change, but because the merge result was vastly different from what I had when I started the local change, I was unable to forward-port them and instead I had to redo it from scratch". It is not a good user experience. > Is it possible to configure git so that the merge driver is called also > while merging locally modified files? No. But you _can_ do that 1 2 / / X--o--A--M \ / --o--B thing manually, by following the advice you received from the error message, by creating '1' yourself. $ git merge 78d4f09 ;# should fail $ git checkout -b store-local-changes-away $ git commit -a -m 'local changes' $ git checkout @{-1} ;# come back to the original branch # at this point, "git status" would report # there is no local changes, hence ... $ git merge 78d4f09 ;# ...this should succeed $ git cherry-pick --no-commit store-local-changes-away The last step may conflict (this is what I called 'the latter step' in the explanation) but at least you have the exact state of '1' recorded and you know what branch (i.e. store-local-changes-away) contains the changes, so you can resolve the conflicts in your working tree without fearing "git reset --hard" to clear the slate in order to start and retry the conflict resolution from scratch losing your precious local modification. And after you are done, you can $ git branch -D store-local-changes-away to conclude the whole thing. You could simplify this somewhat by using "git stash save" before you run the merge and "git stash pop" after, but because using real commit and branch to store the local changes away is easier to see and understand, that is what the error message you saw suggests. -- 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