Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Git - automatically create distinct files for versions on conflict

When Git detects a conflict during merge, the default behaviour is to fill the file with <<< >>> === markers.

This is OK most of the time, but sometimes I'd like to resolve conflicts differently and I'd just like Git to create distinct files:

  • original version,
  • changed version A,
  • changed version B.

How to achieve that?


If there's no simple command to create those files in one go (which is somewhat surprising), maybe there is a way to extend Git so that it would do it? A custom mergetool or something? Just an idea.


Solution:

I've settled for a variant of @Karl Bielefeldt's answer:

savefiles.sh

#!bash
BASE=$1
LOCAL=$2
REMOTE=$3
MERGED=$4

cp "$BASE" "$MERGED.git_BASE"
cp "$LOCAL" "$MERGED.git_LOCAL"
cp "$REMOTE" "$MERGED.git_REMOTE"

# never mark the conflict as merged
exit 1 

config

mergetool.savefiles.cmd=/path/to/savefiles.sh $BASE $LOCAL $REMOTE $MERGED
mergetool.savefiles.trustexitcode=true
like image 865
Kos Avatar asked Jul 26 '11 09:07

Kos


3 Answers

Create a file called savefiles.sh with the following contents:

#!/usr/bin/bash

cp $1 /path/to/BASE
cp $2 /path/to/LOCAL
cp $3 /path/to/REMOTE

Execute the following command inside your repository:

git config mergetool.savefiles.cmd "/path/to/savefiles.sh \$BASE \$LOCAL \$REMOTE"

Add a --global if you want to change it for other than this repository.

Then to run this custom mergetool, use:

git mergetool --tool=savefiles
like image 129
Karl Bielefeldt Avatar answered Oct 20 '22 16:10

Karl Bielefeldt


If you want to go without mergetool, and just display or save the files in the states you mention, the index holds the different states of the conflicted file. You can display (and redirect to a file if you want) with:

$ git show :1:file.txt  # the file in a common ancestor of both branches
$ git show :2:file.txt  # the version from HEAD.
$ git show :3:file.txt  # the version from MERGE_HEAD.

However, using a graphical merge tool shows you a 3-pane view of the conflicted file. That's usually what people do, so just pick up your favorite tool and see how to link it with git mergetool call.

like image 29
CharlesB Avatar answered Oct 20 '22 16:10

CharlesB


Summary

git mergetool -y -t bogus <file>

Works for me with git 1.7.9.5 / Ubuntu 12.04 and msysgit 1.9.4 / Windows 7 x64.

Explanation

I'd just like Git to create distinct files

I was looking for the same thing. Case in point: when invoking git mergetool -t kdiff3, git apparently tries to outsmart me by invoking kdiff3 with a hard-coded --auto flag that instructs kdiff3 to automatically resolve conflicts and exit without showing me the GUI or allowing me to participate in the process (see also). When that happened and kdiff3 resolved the conflicts wrong, I went looking for this.

When I invoke mergetool like so (where bogus is a string that is not a valid merge tool identifier [e.g. not in the output of git mergetool --tool-help if your version of git has that]), the following happens:

  • It reports "Unknown merge tool bogus"

  • The index and file are untouched

  • The following files are generated (where {num} is an integer that is the same in all files created by this invocation):

    file.BACKUP.{num}
    file.BASE.{num}
    file.LOCAL.{num}
    file.REMOTE.{num}
    

file.BACKUP.{num} is identical to file.

Notes

I think the -y should be unnecessary if mergetool.prompt is set to false. And, according to the documentation, it looks like in newer versions of git -t implies -y.

The -t part can be further shortened, e.g. -t x or -t 0.

If you have multiple unmerged files, there doesn't appear to be any way to get this to generate these versions for more than one file at a time. E.g. if you have unmerged files files/file1 and files/file2, any of the following will still only generate these versions (backup, base, local, remote) for file1:

git mergetool -y -t x
git mergetool -y -t x files
git mergetool -y -t x files/file1 files/file2

However, if you resolve the conflicts in file1 and run git mergetool again, it'll move on to the next file.

like image 37
JMM Avatar answered Oct 20 '22 15:10

JMM