use Winmerge inside of Git to file diff
Asked Answered
W

9

118

Is there a way to use Winmerge inside of git to do Diffs?

Wagram answered 10/12, 2009 at 15:8 Comment(2)
See stackoverflow.com/questions/636253/…Orestes
Related post - How to configure a diff tool in Git in general.Silicic
E
130

Update June 2015, 6 years later:

As detailed in "git mergetool winmerge", a simple git config diff.tool winmerge will be enough.

Git 2.5+ (Q2, 2015) is now aware of Winmerge as a diff or merge tool!


Original answer (2009-2012)

(msysgit, 1.6.5, DOS session)

The first part (using winmerge) is described in "How do I view ‘git diff’ output with visual diff program?"

C:\myGitRepo>git config --replace --global diff.tool winmerge
C:\myGitRepo>git config --replace --global difftool.winmerge.cmd "winmerge.sh \"$LOCAL\" \"$REMOTE\""
C:\myGitRepo>git config --replace --global difftool.prompt false

With winmerge.sh stored in a directory part of your PATH:

#!/bin/sh
echo Launching WinMergeU.exe: $1 $2
"$PROGRAMFILES/WinMerge/WinMergeU.exe" -e -u -dl "Local" -dr "Remote" "$1" "$2"

(see WinMerge Command-line options)

git difftool

will now launch WinMerge.
If you want git diff to launch WinMerge, just set:

set GIT_EXTERNAL_DIFF=winmerge.sh

But the real added value comes from the ability to use that same diff tool to present all differences in one batch instead of presenting them sequentially, forcing you to close the diff tool windows one file at a time.

Update June 2012 (2-and-a-half years later):

Comparing directories instead of file-by-file will be available soon:
See [ANNOUNCE] Git 1.7.11.rc1:

"git difftool" learned the "--dir-diff" option to spawn external diff tools that can compare two directory hierarchies at a time after populating two temporary directories, instead of running an instance of the external tool once per a file pair.

See "Patch difftool: teach difftool to handle directory diffs", and the answer "Directory comparison of Git branches" for more details.


Original difftool by directories script (December 2009)

As Seba Illingworth mentions in his answer, a script git-diffall.sh (also put in the path) can do just that:

#!/bin/sh
git diff --name-only "$@" | while read filename; do
    git difftool "$@" --no-prompt "$filename" &
done

But that only works by opening n windows for n files (if you try to use the -s option of WinMerge, it will not work because of the temp files being deleted by the difftool too early)


That is why I like the approach of GitDiff.bat - power-diffing with GI, which allows you to review the list of files with a difference, before selecting one to examine its internal differences.
I have tweaked it to use only DOS commands

@echo off

setlocal

if "%1" == "-?" (
    echo GitDiff - enables diffing of file lists, instead of having to serially
    echo diff files without being able to go back to a previous file.
    echo Command-line options are passed through to git diff.
    echo If GIT_FOLDER_DIFF is set, it is used to diff the file lists. Default is windff.
    goto END
)

if "%GIT_DIFF_COPY_FILES%"=="" (
    rd /s /q %TEMP%\GitDiff
    mkdir %TEMP%\GitDiff
    mkdir %TEMP%\GitDiff\old
    mkdir %TEMP%\GitDiff\new

    REM This batch file will be called by git diff. This env var indicates whether it is
    REM being called directly, or inside git diff
    set GIT_DIFF_COPY_FILES=1

    set GIT_DIFF_OLD_FILES=%TEMP%\GitDiff\old
    set GIT_DIFF_NEW_FILES=%TEMP%\GitDiff\new

    set GIT_EXTERNAL_DIFF=%~dp0\GitDiff.bat
    echo Please wait and press q when you see "(END)" printed in reverse color...
    call git diff %*

    if defined GIT_FOLDER_DIFF (
        REM This command using GIT_FOLDER_DIFF just does not work for some reason.
        %GIT_FOLDER_DIFF% %TEMP%\GitDiff\old %TEMP%\GitDiff\new
        goto END
    )

    if exist "%ProgramFiles%\Beyond Compare 2\BC2.exe" (
        set GIT_FOLDER_DIFF="%ProgramFiles%\Beyond Compare 2\BC2.exe"
        "%ProgramFiles%\Beyond Compare 2\BC2.exe" %TEMP%\GitDiff\old %TEMP%\GitDiff\new
        goto END
    )

    "%ProgramFiles(x86)%\WinMerge\WinMergeU.exe" -r -e -dl "Local" -dr "Remote"  %TEMP%\GitDiff\old %TEMP%\GitDiff\new
    goto END
)

REM diff is called by git with 7 parameters:
REM     path old-file old-hex old-mode new-file new-hex new-mode
copy %TEMP%\%~nx2 %GIT_DIFF_OLD_FILES%\%1
copy %5 %GIT_DIFF_NEW_FILES%

:END

It is not robust enough to handle files with same names in different directories, but it gives you a general idea of what is possible:
Here only one WinMerge will open up, with the list of files having internal differences. You can click on the ones you want to examines, then a simple ESC will close the all WinMerge-diff session.

Esoteric answered 10/12, 2009 at 22:25 Comment(20)
Trying this with git version 1.6.5.1.1367.gcd48 and it doesn't seem to generate any files in those temp folders. Any ideas where to look for the problem? Thanks!Employer
@Art: in those debug cases, I try to isolate the problem by simplifying the script: 1/ if the script called with the 7 parameter (first pass of git diff, to copy the files) 2/ is the script at least called back at the end of the git diff?Esoteric
So I tried this and it's not working for me (git version 1.7.2.3). echo Launching WinMergeU.exe: $1 $2 works, an example output is Launching WinMergeU.exe: /tmp/waxdnW_makeHTML.cfm scheduler/makeHTML.cfm but I never see this "tmp" folder and with winmerge launches the Left value is "C:\ColdFusion8\wwwroot\archiver-git\scheduler\makeHTML.cfm" but the right value is blank and I can't press "ok"Citral
what does -ub do? I don't see that argument documented.Citral
@Erik: regarding the option -ub, see the WinMerge FAQ: it is the same than -u: it tells WinMerge to not add the files to the MRU.Esoteric
@Erik: you should see comparison of files in c:\Temp\GitDiff\old and c:\Temp\GitDiff\new, not '/tmp'. Are you sure you are executing this DOS program from a DOS session (and not a bash session)?Esoteric
@Esoteric ah I was using cygwin.. your solution is working perfectly in DOS for me, thanks!Citral
Thanks! this solved my problem perfectly. One more detail for cygwin or git bash users is that the '$' needs to be escaped as well as the '"' characters when setting git configurations.Riyadh
@MichaelSteele Excellent! Can you edit the answer to include an example working for cygwin/bash?Esoteric
After following the first set of instructions git difftool yields /libexec/git-core/git-mergetool--lib: line 122: winmerge: command not found 4 times, and never launches winmerge. I'm at a bit of a loss on how to debug it since it all seems a bit magic to me.Acrobat
Continuing my previous comment: These changes have changed the behavior of Visual Studio's integrated diff. Now, it launches Winmerge with no files open, prompting me to use "C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\.sh" as the left file, which doesn't actually exist, and of course doesn't work. Hopefully, I can undo this.Acrobat
@Acrobat It would be best to post a separate question, for others to have a look at your issue.Esoteric
In the command git config --replace --global difftool.winmerge.cmd "winmerge.sh \"$LOCAL\" \"$REMOTE\"" "$LOCAL" and "$REMOTE" will evaluate to "". Use 'winmerge.sh "$LOCAL" "$REMOTE"' instead.Delenadeleon
@Delenadeleon it did not evaluate to "" in my case (executing the git config command from a Windows CMD. But you are right: it would evaluate to "" if executed from a bash shell.Esoteric
Wow, so you have to do all this just to configure your git to point to winmerge?Propane
@Propane You had to. These days, git config diff.tool winmerge is enough.Esoteric
No matter what I do (from this thread and gists and blogs), I can't get this working. It keeps launching the dialog box with just the first file prefilled. It used to work in the last job that I used Windows (quite a while ago unfortunately).Lymph
@SridharSarnobat Strange. Since I do not use Winmerge these days, it is best to ask a separate question, to see if there is a current solution.Esoteric
Resolved. It turns out that the PortableApps version of WinMerge doesn't play nicely with git. That's what happens when you try to be too clever on Windows :))Lymph
@SridharSarnobat OK. Strange, since if winmerge.exe is in your %PATH%, it should have worked.Esoteric
S
21

I faced trouble using the first part in 2 places and fixed it as follows

  1. The second command for setting up winmerge.cmd required an extra slash on cmdline (before $LOCAL and $REMOTE), else cygwin was substituting the variable in cmdline

    C:\myGitRepo>git config --replace --global difftool.winmerge.cmd "winmerge.sh \"\$LOCAL\" \"\$REMOTE\""
    
  2. changed the winmerge.sh file to (without this, was getting right-path-invalid error)

    #!/bin/sh
    echo Launching WinMergeU.exe: "$(cygpath -aw "$1")" "$(cygpath -aw "$2")"
    "$PROGRAMFILES/WinMerge/WinMergeU.exe" -e -ub -dl "Base" -dr "Mine" "$(cygpath -aw "$1")" "$(cygpath -aw "$2")"
    
Sorbose answered 10/10, 2011 at 4:57 Comment(1)
I did exactly how VonC instructed, but I was receiving empty arguments in my winmerge.sh script. Using extra slashes solved the problem. Thank you!Unific
T
9

Without configuration:

git difftool --tool winmerge

Assuming:

  • Winmerge is installed
  • Git for windows is installed, from "git version 2.12.0.windows1" or above (although earlier versions of git may have introduced the command).

If you get the following error

The diff tool winmerge is not available as 'WinMergeU.exe'

You will have to verify that the path to winmerge is correct in .gitconfig. You will minimally need the config

[difftool "winmerge"]
    cmd = "'C:/Program Files (x86)/WinMerge/WinMergeU.exe' -e $LOCAL $REMOTE"
Turpin answered 1/3, 2017 at 13:34 Comment(0)
L
7

I have a script that will set the Diff and Merge tools in the Git config with the proper parameters that doesn't require a separate .sh file to exist. It seems to be working fine for me.

git config --global diff.tool winmerge
git config --global difftool.prompt false
git config --global difftool.winmerge.cmd "\"\$PROGRAMFILES\"/WinMerge/WinMergeU.exe -r -u -e -dl \"Local\" -dr \"Remote\" \"\$LOCAL\" \"\$REMOTE\""

git config --global merge.tool winmerge
git config --global mergetool.prompt false
git config --global mergetool.winmerge.trustExitCode true
git config --global mergetool.winmerge.cmd "\"\$PROGRAMFILES\"/WinMerge/WinMergeU.exe -r -u -e -dl \"Local\" -dr \"Remote\" \"\$LOCAL\" \"\$REMOTE\" \"\$BASE\" \"\$MERGED\""

Note - the entire .cmd portion is quoted so that the parameters will be listed in the .gitconfig properly

Lobster answered 22/9, 2014 at 20:0 Comment(2)
The following command didn't work for me. git config --global difftool.winmerge.cmd "\"\$PROGRAMFILES\"/WinMerge/WinMergeU.exe -r -u -e -dl \"Local\" -dr \"Remote\" \"\$LOCAL\" \"\$REMOTE\"" Note: This command must be run from a command prompt and not from powershell. Manually adding the following to my .gitconfig [difftool "winmerge"] section did work for me: cmd = 'C:/Program Files (x86)/WinMerge/WinMergeU.exe' -r -u -e -dl \"Local\" -dr \"Remote\" \"$LOCAL\" \"$REMOTE\"Wife
It didn't work, but with some changes, it works: open cmd as administrator, and run: git config --global mergetool.winmerge.cmd "\"C:\Program Files (x86)\WinMerge\WinMergeU.exe\" -r -u -e -dl \"Local\" -dr \"Remote\" \"$LOCAL\" \"$REMOTE\" \"$BASE\" \"$MERGED\"". There were a few incorrect escaped strings (note a few additional unwanted backslashes there right before the $ - I guess $ don't need to be escaped). Also, it was missing an end " after WinMergeU?.exe. Run git config --get mergetool.winmerge.cmd to see what had been actually set. Anyway, thanks for non .sh version: +1!Seften
A
7

On windows you can do it this way:

1) Open .gitconfig file. It's located at your home directory: c:\users\username.gitconfig

2) Add the lines below. Pay attention to the single quotes wrapping the path to winmerge:

[diff]
    tool = winmerge
[difftool "winmerge"]
    cmd = "'C:/Program Files (x86)/WinMerge/WinMergeU.exe'" -e "$LOCAL" "$REMOTE"
[difftool]
    prompt = false
[merge]
    tool = winmerge
[mergetool "winmerge"]
    cmd = "'C:/Program Files (x86)/WinMerge/WinMergeU.exe'" \"$MERGED\" \"$REMOTE\"
[mergetool]
    keepBackup = false
    trustExitCode = false
Arianism answered 3/6, 2015 at 8:39 Comment(1)
Also pay attention to the forward slashes instead of backslashes in the command path.Brickwork
T
6

Since the thread is getting confusing and bifurcated, here are consolidated instructions for the Directory Listing "--dir-diff" WinMerge method for msysgit Git Windows.

Step 1 - Create a file named winmerge.sh at a location accessible to your path (such as /home/bin/winmerge.sh) with following contents.

#!/bin/sh
echo Launching WinMergeU.exe: $1 $2
"$PROGRAMFILES/WinMerge/WinMergeU.exe" -r -ub -dl "Remote" -dr "Local" "$1" "$2"

Step 2 - Type the following commands in Git Bash to instruct git to use winmerge.sh as difftool (these options get stored in /home/.gitconfig):

git config --replace --global diff.tool winmerge
git config --replace --global difftool.winmerge.cmd "winmerge.sh \"$LOCAL\" \"$REMOTE\""
git config --replace --global difftool.prompt false

Step 3 - Now you can test by typing the following command in Git Bash to start your WinMerge diff:

git difftool --dir-diff

Step 4 - For quicker access, create an alias for this command by adding this line to .bashrc in your home folder (or create .bashrc file with this line if file does not already exist):

alias diffdir='git difftool --dir-diff'

Step 5 - Now you can quickly see a diff in WinMerge just by typing the following command into Git Bash

diffdir
Teth answered 12/6, 2013 at 20:1 Comment(1)
It would be helpful to have someone explain the meanings of $LOCAL and $REMOTE.Farro
I
3

I can see lots of long and confusing answers here, so posting the simplified and minimal version which worked for me in 2021 on windows10

 git config diff.tool winmerge
 git config --replace --global difftool.prompt false
Illuse answered 1/2, 2021 at 17:16 Comment(0)
S
2

I was confused about why the solution was presented as a DOS batch file, as my Git installation came with a bash shell. I was also unable to get a DOS context running from bash, so I've attempted to adapt what was previously shared in a bash context.

Since git diff appears to run the specified command once for each file, I split my solution into two bash scripts:

First, configure gitprepdiff.sh to be the difftool as previously mentioned

#!/bin/sh
#echo ...gitprepdiff.sh
cp -v $1 "$TMP/GitDiff/old/$2"
cp -v $2 "$TMP/GitDiff/new"

I also noted that the results of the git configure commands can be found and edited directly in C:\Users\<username>\.gitconfigure

gitdiff.sh is then run at the command-line where you would normally call git diff

#!/bin/sh
#echo Running gitdiff.sh...

DIFFTEMP=$TMP/GitDiff

echo Deleting and re-creating $DIFFTEMP...
rm -rf $DIFFTEMP;
mkdir $DIFFTEMP;

echo Creating $DIFFTEMP/old...
mkdir $DIFFTEMP/old;

echo Creating $DIFFTEMP/new...
mkdir $DIFFTEMP/new;

git diff --name-only "$@" | while read filename; do
    git difftool "$@" --no-prompt "$filename";
done

"$PROGRAMFILES\WinMerge\WinMergeU.exe" -r -e -dl "Repository" -dr "Working" $LOCALAPPDATA\\Temp\\1\\GitDiff\\old $LOCALAPPDATA\\Temp\\1\\GitDiff\\new

Also worth noting is that, on my installation, /tmp (in bash) mapped to %LOCALAPPDATA%\Temp\1\ (in Windows), so that's why I'm using the latter in my call to WinMerge.

Simplify answered 24/11, 2011 at 0:59 Comment(2)
I changed gitprepdiff.sh for #!/bin/sh #echo ...gitprepdiff.sh mkdir -vp "$TMP/GitDiff/old/$(dirname $2)" cp -v $1 "$TMP/GitDiff/old/$2" cp -v --parents $2 "$TMP/GitDiff/new" Thank You!Juster
Seems ridiculous to jump through so many hoops to make this work, but it does. You get all file diffs in one go as it should be. I had to make the changes mentioned by @Juster too to properly handle files in subdirectories.Elman
B
1
git config --global diff.tool winmerge
git config --global difftool.winmerge.cmd "\"$PROGRAMFILES\\WinMerge\\WinMergeU.exe\" -u -dl \"Local\" -dr \"Remote\" \"\$LOCAL\" \"\$REMOTE\""
git config --global difftool.prompt false

As per the WinMerge command line manual: "Parameters are prefixed with either a forward slash ( / ) or dash ( - ) character"

Basinger answered 17/3, 2016 at 1:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.