Search code examples
gitmergepre-commit

Find files that were conflicting or locally edited during git merge commit


Background: I'm working on a pre-commit tool. As a developer it can be quite frustrating to pull another developer's branch and have the pre-commit hook complain loudly about files that I haven't even touched.

What I'd like to be able to do in my implementation is in a merge-commit case only run the hooks on files that were either conflicting or manually edited by me locally during the merge conflict.

What I've tried so far:

  • git diff --staged - This is what the current solution does and isn't correct because it contains all of the files including the ones that merged cleanly.
  • git diff MERGE_HEAD - This is pretty close, but if the branch I am merging in branched from master after I did, this contains all of the changes from master that I haven't yet merged.
  • .git/MERGE_MSG contains the list of conflicting files. This seems like a good starting point but does not contain locally edited files.
  • After committing, git show --name-only gets me exactly what I want. But that's too late (I'm implementing pre-commit after all :D)

Solution

  • I believe the solution is git diff -m. I found the doc on this very confusing, so here's my summary. Given the command git diff -m child parent1 parent2 .... you'll see a multi-parent diff that shows how to get from each parent to the child. parent1 represented in the first column of [ +-] and so on. The major roadblock here is that the child in your question has no referenceable name. git write-tree comes to the rescue here; it creates a name for the currently-staged files, and prints it out.

    Note that write-tree will fail if there are any unmerged files, which is probably what you want, but you'll need to make sure your system does something intelligible in that case.

    $ CURRENTLY_ADDED=`git write-tree`
    $ git diff -m $CURRENTLY_ADDED HEAD MERGE_HEAD
    diff --cc README
    index 2ef4a65,8e2e466..be3d46e
    --- a/README
    +++ b/README
    @@@ -1,10 -1,5 +1,10 @@@
     -deleted only in <theirs>
     +added only in <theirs>
    - deleted only in <ours>
    + added only in <ours>
    --deleted during merge
    ++added during merge