I would like to be able to resolve conflicts using kdiff3, when SVN notifies me about the conflict. How can I set it as a default tool for this?
How to set kdiff3 as merge tool for SVN
23.4k views Asked by gruszczy AtThere are 4 answers
A solution that is shorter and works with later versions of SVN (tested on SVN 1.7.7):
Create a script ~/svn-merge-kdiff
#!/bin/bash
# Useful when something fails
LOG=~/svn-merge-kdiff-last-run.log
echo "arguments passed to $0: $@" > $LOG
# Now, don't think you will get the $1, $2, etc... by referencing.
# At first, you have to copy it to an array
for i in $@; do
args=( ${args[@]} $i )
done
echo "parsed args" >> $LOG
for i in ${args[@]}; do
echo $i >> $LOG
done
# I keep it in case something changes
if [ "${args[1]}" == "-m" ] && [ "${args[2]}" == "-L" ] && [ "${args[3]}" == ".mine" ];then
command="kdiff3 --L1 ${args[5]} --base ${args[9]} --L2 ${args[7]} ${args[10]} --L3 ${args[3]} ${args[8]} -o merged"
$command
if [[ $? -ne 0 ]]; then
echo "$command failed" >> $LOG
exit 1
fi
# You have to do this, otherwise after the merge you will see... empty file(?)
cat merged
rm merged
exit 0
fi
exit -1
Bind it to svn in ~/.subversion/config
diff3-cmd = ~/svn-merge-kdiff
The script from yvoyer's answer works great for me, and I am using SVN 1.4. I think the previous answer from Jon Ander Ortiz Durántez works for SVN 1.5 and greater, and this script works for SVN versions prior to 1.5. It appears there were changes to --diff-cmd & --diff3-cmd for version 1.5. Compare scripts in the following 2 SVN docs to see some differences:
- svnbook.red-bean.com/en/1.4/svn.advanced.externaldifftools &
- svnbook.red-bean.com/en/1.5/svn.advanced.externaldifftools.
Michael Bradley's script is really useful since now if I get a conflict during svn update
it kicks into kdiff3 instead of barfing all over the file with the ">>>>>>>>" conflict markers which are so difficult to resolve if you have complex conficts. The diff3-cmd works for both merge and update.
I add diff3-cmd = /usr/local/bin/svndiff3
to ~/.subversion/config
(or use --diff3-cmd
on the cmdline) since I wrote my own script to send svn diff
to sdiff and is specified by --diff-cmd
.
This script is posted at yolinux, and a slightly modified version (that handles auto-merging) is posted here Jawspeak.
I found this script somewhere I can't remember. but the author is Michael Bradley.
My answer is similar to Jon Ander Ortiz Durántez's answers. So if his answer doesn't work, you have a backup. I once tried something like he suggested, but it always output some error with the parameters until I found this scripts which resolved everything.
Create a script file and set diff-cmd = /path/to/script.sh
in your ~/.subversion/config
#!/bin/bash # Return an errorcode of 0 on successful merge, 1 if unresolved conflicts # remain in the result. Any other errorcode will be treated as fatal. # Author: Michael Bradley #NOTE: all output must be redirected to stderr with "1>&2" as all stdout output is written to the output file # Must be called by subversion in "~/.subversion/config" file # Add config : "diff-cmd = /path/to/script/myKdiff3.sh" VDIFF3="kdiff3" DIFF3="diff3" DIFF="kdiff3" promptUser () { read answer case "${answer}" in "M" ) echo "" 1>&2 echo "Attempting to merge ${baseFileName} with ${DIFF}" 1>&2 $VDIFF3 $older $mine $theirs --L1 $labelOlder --L2 $labelMine --L3 $labelTheirs -o $output 1>&2 bLoop=1 if [ -f $output ]; then if [ -s $output ]; then #output succesfully written bLoop=0 fi fi if [ $bLoop = 0 ]; then cat $output rm -f $output exit 0 else echo "Merge failed, try again" 1>&2 fi ;; "m" ) echo "" 1>&2 echo "Attempting to auto-merge ${baseFileName}" 1>&2 diff3 -L $labelMine -L $labelOlder -L $labelTheirs -Em $mine $older $theirs > $output if [ $? = 1 ]; then #Can't auto merge rm -f $output $VDIFF3 $older $mine $theirs --L1 $labelOlder --L2 $labelMine --L3 $labelTheirs -o $output --auto 1>&2 bLoop=1 if [ -f $output ]; then if [ -s $output ]; then #output succesfully written bLoop=0 fi fi if [ $bLoop = 0 ]; then cat $output rm -f $output exit 0 else echo "Merge failed, try again" 1>&2 fi else #We can automerge, and we already did it cat $output rm -f $output exit 0 fi ;; "diff3" | "Diff3" | "DIFF3" ) echo "" 1>&2 echo "Diffing..." 1>&2 $VDIFF3 $older $mine $theirs --L1 $labelOlder --L2 $labelMine --L3 $labelTheirs 1>&2 ;; "diff" | "Diff" | "DIFF" ) echo "" 1>&2 echo "Diffing..." 1>&2 $DIFF $mine $theirs -L $labelMine -L $labelTheirs 1>&2 ;; "A" | "a" ) echo "" 1>&2 echo "Accepting remote version of file..." 1>&2 cat ${theirs} exit 0 ;; "I" | "i" ) echo "" 1>&2 echo "Keeping local modifications..." 1>&2 cat ${mine} exit 0 ;; "R" | "r" ) echo "" 1>&2 echo "Reverting to base..." 1>&2 cat ${older} exit 0 ;; "D" | "d" ) echo "" 1>&2 echo "Runnig diff3..." 1>&2 diff3 -L $labelMine -L $labelOlder -L $labelTheirs -Em $mine $older $theirs #Exit with return vaule of the diff3 (to write out files if necessary) exit $? ;; "S" | "s" ) echo "" 1>&2 echo "Saving for later..." 1>&2 cat ${mine} #Exit with return vaule of 1 to force writting of files exit 1 ;; "Fail" | "fail" | "FAIL" ) echo "" 1>&2 echo "Failing..." 1>&2 exit 2 ;; "H" | "h" ) echo "" 1>&2 echo "USAGE OPTIONS:" 1>&2 echo " [A]ccept Accept $labelTheirs and throw out local modifications" 1>&2 echo " [D]efault Use diff3 to merge files (same behavior as vanilla SVN)" 1>&2 echo " [Fail] Kills the command (not suggested)" 1>&2 echo " [H]elp Print this message" 1>&2 echo " [I]gnore Keep your locally modified version as is" 1>&2 echo " [M]erge Manually merge using ${VDIFF3}" 1>&2 echo " [m]erge Same as "M" but attempts to automerge if possible" 1>&2 echo " [R]evert Revert to base version (${labelOlder})" 1>&2 echo " [S]ave Same as 'I' but writes out rold, rnew, and rmine files to deal with later" 1>&2 echo " [diff] Type 'diff' to diff versions $labelMine and $labelTheirsthe before making a descision" 1>&2 echo " [diff3] Type 'diff3' to diff all three versions before making a descision" 1>&2 echo "" 1>&2 ;; * ) echo "'${answer}' is not an option, try again." 1>&2 ;; esac } if [ -z $2 ] then echo ERROR: This script expects to be called by subversion exit 1 fi if [ $2 = "-m" ] then #Setup vars labelMine=${4} labelOlder=${6} labelTheirs=${8} mine=${9} older=${10} theirs=${11} output=${9}.svnDiff3TempOutput baseFileName=`echo $mine | sed -e "s/.tmp$//"` #Prompt user for direction while [ 1 ] do echo "" 1>&2 echo "${baseFileName} requires merging." 1>&2 echo "" 1>&2 echo "What would you like to do?" 1>&2 echo "[M]erge [A]ccept [I]gnore [R]evert [D]efault [H]elp" 1>&2 promptUser done else L="-L" #Argument option for left label R="-L" #Argument option for right label label1=$3 #Left label label2=$5 #Right label file1=$6 #Left file file2=$7 #Right file $DIFF $file1 $file2 $L "$label1" $L "$label2" & #$DIFF $file1 $file2 & #wait for the command to finish wait fi exit 0
Go to the Subversion configuration file (
/etc/subversion/config
or~/.subversion/config
), and setmerge-tool-cmd
variable with your favourite tool:Although there is a problem with kdiff3 which does not support four plain arguments (SVN passes four plain arguments to kdiff3, and it does not work), so it is usually called with a simple script to translate the arguments, e.g., "kdiff3caller":
This kdiff3 problem and solution is explained here.