2

I have a project that has some files that are fragile in a sense that slight errors may cause security problems even if full program seems to work okay. As a result, I'd like git to always verify the result of any automatic modification during merge.

If I've understood correctly, a custom merge driver is pretty much what I want. The best I've figured out is to use git-merge-file in a custom merge driver to get the normal merge result and just exit 1 to mark the result as conflicting always. This way git will stop during merge and I can inspect the merge result before completing the merge.

However, the expected changes to that file are very small and the best way would be able to run something similar to "git add -i" and selecting "patch" and applying one hunk at a time.

Is there a simple way to write a merge driver that behaves like "git add -i" for all merges to that file (where the possible hunk to apply is the result of automatic merge)?

In addition, if I've understood correctly, the merge driver will be called only for file level conflicts. Is it possible to request similar manual verification for specially marked files? I'm thinking marking a new file as "fragile" in gitattributes before doing the merge and then some git merge magic (or filter magic) would request me to verify that the new special file is okay for the merged branch.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
Mikko Rantalainen
  • 14,132
  • 10
  • 74
  • 112
  • Why don't you simply review the merge's diff? – Mat Mar 16 '12 at 07:15
  • I'd like to have an automatic reminder when such a merge happens. Usually merge results can be tested with automated testing and/or building but for fragile stuff an additional review is needed to be sure. I'd like to force such review any time any team member merges anything that touches any such special file. – Mikko Rantalainen Mar 16 '12 at 09:22

1 Answers1

0

I'm adding my current solution here because this is better than nothing but still short from the interactive solution I'm looking for. The solution consists of three parts:

  1. create file bin/merge-and-verify with following contents:

    #!/bin/bash
    # git merge driver that does normal merge but marks the result as conflicting
    
    # make a copy of original version
    cp "${1}" "${1}.tmp"
    ORIG_HASH=$(git hash-object "${1}")
    WORKFILE=$(git ls-tree -r HEAD | fgrep "$ORIG_HASH" | cut -b54-)
    git merge-file -L "My version (working directory)" -L "Base (common ancestor)" -L "Merge head (remote change)" "${1}" "${2}" "${3}"
    # display changes made
    echo "-----------------------------------------------------"
    echo "Making following changes automatically:"
    echo "(Confirm changes with 'git add $WORKFILE')"
    echo "-----------------------------------------------------"
    diff -u --label "Original" "${1}.tmp" --label "Automatically modified" "${1}"
    echo "-------------------------------------------------"
    # remove our extra copy
    rm -f "${1}.tmp"
    exit 1
    
  2. create/modify file `.gitattributes as follows:

    [attr]FRAGILE merge=merge-and-verify
    
    relative/path/to/fragile.file FRAGILE
    
  3. run following command to activate the driver in the working directory

    git config merge.merge-and-verify.driver "./bin/merge-and-verify %A %O %B"
    

Now any modification to any file marked FRAGILE will result in usual automatic merge where the result of automatic merge will be displayed in the console with a hint about how to confirm the changes (git add relative/path/to/fragile.file) if changes look sane. If you don't need the verbose output to console during the merge, you just need the git merge-file and exit 1 in the driver.

Missing pieces: due to the git internal behavior, the merge driver is not called if there's no conflict in the history of the file. For example, if a new FRAGILE file has been added in another branch which is merged into the master the merge driver will not be called because there's no need to merge any files (as far as git knows, in this case merging the branch just adds a new file which does not conflict with anything so there's no need for merge driver).

Mikko Rantalainen
  • 14,132
  • 10
  • 74
  • 112
  • It seems that somebody else had already figured out the same thing. Unfortunately, I didn't know about that before I did pretty much the same work by myself. See http://stackoverflow.com/questions/5074452/git-how-to-force-merge-conflict-and-manual-merge-on-selected-file?lq=1 for details. – Mikko Rantalainen Apr 29 '13 at 05:28