As it turns out, I've been working on my own script, git-mergetool, to deal with conflicts, and while it isn't quite ready for prime time yet (no documentation, doesn't deal with filenames with spaces yet, etc.) it does fire up the GUI merge tools and it does update the index afterwards. My intention is to polish this up and submit this into a patch to git.
The goal is to have similar functionality to what Bitkeeper and Mercurial have as far as GUI merge tools are concerned. Once I am done polishing git-mergetool, I'll likely submit a patch to enable a config option which will cause "git merge" to automatically fire up "git mergetool" if there are any conflicts.
The patch doesn't current fall back to firing up an editor, but in order to subsume Johannes' script's functionality, I will probably add that functionality with code that looks for merge markers and which only does the "git add" if the merge markers are completely gone.
It currently uses a hard-wired preference order for the GUI merge tools, based on the current functionality of said merge tools, but the plan is to add options parsing and a config option to allow a user-specified override.
Any comments, suggestions?
- Ted
#!/bin/sh # # This program resolves merge conflicts in git #
KDIFF3="kdiff3" TKDIFF="tkdiff" MELD="meld"
type "$KDIFF3" >/dev/null 2>&1 || KDIFF3= type "$TKDIFF" >/dev/null 2>&1 || TKDIFF= type "$MELD" >/dev/null 2>&1 || MELD=
if test -z "$KDIFF3" -a -z "$TKDIFF" -a -z "$MELD" ; then
echo "No available GUI merge tools available."
exit 1
fi
merge_file () {
path="$1" if test ! -f "$path" ; then
echo "$path: file not found"
exit 1
fi
f=`git-ls-files -u "$path"`
if test -z "$f" ; then
echo "$path: file does not need merging"
exit 1
fi
BACKUP="$path.BACKUP.$$"
LOCAL="$path.LOCAL.$$"
REMOTE="$path.REMOTE.$$"
BASE="$path.BASE.$$"
CHGTEST="$LOCAL.chg.$RAND"
mv $path $BACKUP
cp $BACKUP $path
git show :1:$path > "$BASE"
git show :2:$path > "$LOCAL"
git show :3:$path > "$REMOTE"
if test -n "$KDIFF3" ; then
kdiff3 --auto "$BASE" "$LOCAL" "$REMOTE" -o "$path"
status=$?
elif test -n "$TKDIFF" ; then
tkdiff "$LOCAL" "$REMOTE" -a "$BASE" -o "$path"
status=$?
elif test -n "$MELD" ; then
meld "$LOCAL" "$path" "$REMOTE"
if test "$path" -nt "$BACKUP" ; then
status=0;
else
while true; do
echo "$path seems unchanged."
echo -n "Was the merge successful? [y/n] "
read answer
case "$answer" in
y*|Y*) status=0; break ;;
n*|N*) status=1; break ;;
esac
done
fi
fi
rm -f "$LOCAL" "$REMOTE" "$BASE"
if test $status != 0 ; then
echo "merge of $path failed" 1>&2
mv "$BACKUP" $path
exit 1
fi
git add $path
}
if test $# -eq 0 ; then
files=`git ls-files -u --abbrev=8 | colrm 1 24 | sort -u`
if test -z "$files" ; then
echo "No files need merging"
exit 0
fi
echo Merging the files: $files
for i in `git ls-files -u --abbrev=8 | colrm 1 24 | sort -u`
do
merge_file "$i"
done
else
while test $# -gt 0; do
merge_file "$1"
shift
done
fi
exit 0