For about six month I’m using Git as my preferred Source Control Management system. That is, while my colleagues at work still work with Subversion and TortoiseSVN, I am leveraging the powers of Git behind the scenes. That is, I work on local (Git) feature branches that I commit to our SVN trunk every once in a while, typically after I finished working on a feature.
If you want to get started with Git, I recommend watching the GitCasts and try one of the Windows distributions, msysgit or Cygwin. (I switched to Cygwin after the msysgit team dropped SVN integration in their 1.6 release.)
Git heavily relies on the command line, and UI tools like gitk and TortoiseGit are not quite there yet. Using a CLI might be something a lot of Windows developers do not look forward to, but you still can configure support for some UI tools. For example, file diffs and merges can be customized to work with any tool (UI and CLI-based). I use SourceGear DiffMerge (free) as my primary diff and merge tool. It’s far better that what comes with TortoiseSVN or Git itself (again CLI-based).
I could only find sparse documentation on how to make DiffMerge work with Git, so I dove into the world of Shell programming and created a couple of simple scripts. Here is what I came up with.
diffmerge-diff.sh
#!/bin/sh
path="$(cygpath $1)"
old="$(cygpath --mixed --absolute "$2")"
new="$(cygpath --mixed --absolute "$5")"
#echo -e "path\n$path"
#echo -e "old\n$old"
#echo -e "new\n$new"
"/cygdrive/C/Tools/DiffMerge/diffmerge.exe" "$old" "$new" --title1="Old" --title2="New $path"
diffmerge-merge.sh
#!/bin/sh
localPath="$(cygpath --mixed --absolute "$2")"
basePath="$(cygpath --mixed --absolute "$1")"
remotePath="$(cygpath --mixed --absolute "$3")"
resultPath="$(cygpath --mixed --absolute "$4")"
if [ ! -f $basePath ]
then
basePath="$(cygpath --mixed --absolute ~/diffmerge-empty)"
fi
#echo -ne "local\n$localPath\n"
#echo -ne "base\n$basePath\n"
#echo -ne "remote\n$remotePath\n"
#echo -ne "result\n$resultPath\n"
"/cygdrive/C/Tools/DiffMerge/diffmerge.exe" --merge --result="$resultPath" "$localPath" "$basePath" "$remotePath" --title1="Mine" --title2="Merged: $4" --title3="Theirs"
Setting up Git
- Put the files above in your home directory, either C:\Cygwin\home\<username> (Cygwin) or C:\Users\<username> (msysgit). Make sure the line endings are LF-only (UNIX style) and the file is saved without the UTF byte-order mark (BOM).
- Create an empty file named diffmerge-empty in the same directory.
- Modify the scripts to point to the correct location of DiffMerge (see the last lines). Some more modifications will be needed if you’re from the msysgit crowd, as the cygpath utility is not available there.
- Open a Git CLI and enter the following commands:
git config --global merge.tool diffmerge
git config --global mergetool.diffmerge.cmd "~/diffmerge-merge.sh \"\$BASE\" \"\$LOCAL\" \"\$REMOTE\" \"\$MERGED\""
git config --global mergetool.diffmerge.trustExitCode false
git config --global diff.external "C:/Cygwin/home/<username>/diffmerge-diff.sh"
This should add the following lines to your .gitconfig:
[merge]
tool = diffmerge
[mergetool "diffmerge"]
cmd = ~/diffmerge-merge.sh \"$BASE\" \"$LOCAL\" \"$REMOTE\" \"$MERGED\"
trustExitCode = false
[diff]
external = C:/Cygwin/home/<username>/diffmerge-diff.sh
Using DiffMerge
Using DiffMerge is pretty easy, the normal git diff and git mergetool commands work as usual, but will now spawn DiffMerge instead of vi (which is the default). If anything does not work as expected, uncomment the #echo lines and use a tool like Process Monitor and Process Explorer to see where things go wrong.
Happy diffing!