use o Winmerge dentro do Git para arquivar diff

Respostas:

113

Atualização de junho de 2015, 6 anos depois:

Conforme detalhado em " git mergetool winmerge ", um simples git config diff.tool winmergeserá suficiente.

O Git 2.5+ (2º trimestre de 2015) agora reconhece o Winmerge como uma ferramenta de comparação ou fusão!


Resposta original (2009-2012)

(msysgit, 1.6.5, sessão DOS)

A primeira parte (usando o winmerge) é descrita em " Como faço para visualizar a saída 'git diff' com o programa visual diff? "

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

Com winmerge.sharmazenado em uma parte do diretório de PATH:

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

(consulte as opções de linha de comando do WinMerge )

git difftool

irá agora iniciar o WinMerge.
Se você deseja git diffiniciar o WinMerge, basta definir:

set GIT_EXTERNAL_DIFF=winmerge.sh

Mas o verdadeiro valor agregado vem da capacidade de usar a mesma ferramenta de comparação para apresentar todas as diferenças em um lote, ao invés de apresentá-las sequencialmente, forçando você a fechar as janelas da ferramenta de comparação um arquivo por vez.

Atualização de junho de 2012 (2 anos e meio depois):

A comparação de diretórios em vez de arquivo por arquivo estará disponível em breve:
Veja [ANNOUNCE] Git 1.7.11.rc1 :

" git difftool" aprendi a --dir-diffopção " " de gerar ferramentas diff externas que podem comparar duas hierarquias de diretório por vez após preencher dois diretórios temporários, em vez de executar uma instância da ferramenta externa uma vez por par de arquivos .

Veja " Patch difftool: ensinar difftoola lidar com diffs de diretório ", e a resposta " Comparação de diretório de ramificações Git " para mais detalhes.


Difftool original por script de diretórios (dezembro de 2009)

Como Seba Illingworth menciona em sua resposta , um script git-diffall.sh (também colocado no caminho) pode fazer exatamente isso:

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

Mas isso só funciona abrindo n janelas para n arquivos (se você tentar usar a -sopção de WinMerge, não funcionará porque os arquivos temporários foram excluídos pelo difftool muito cedo)


É por isso que gosto da abordagem de GitDiff.bat - power-diffing com GI , que permite revisar a lista de arquivos com diferenças, antes de selecionar um para examinar suas diferenças internas.
Eu ajustei para usar apenas comandos DOS

@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

Não é robusto o suficiente para lidar com arquivos com os mesmos nomes em diretórios diferentes, mas dá uma ideia geral do que é possível:
Aqui, apenas um WinMerge será aberto, com a lista de arquivos com diferenças internas. Você pode clicar naqueles que deseja examinar e, em seguida, um simples ESCfechará toda a WinMerge-diffsessão.

VonC
fonte
1
Tentando fazer isso com git versão 1.6.5.1.1367.gcd48 e não parece gerar nenhum arquivo nessas pastas temporárias. Alguma ideia de onde procurar o problema? Obrigado!
Art.
@Art: nesses casos de depuração, tento isolar o problema simplificando o script: 1 / se o script for chamado com o parâmetro 7 (primeira passagem de git diff, para copiar os arquivos) 2 / é o script pelo menos chamado de volta no final do git diff?
VonC de
1
@Erik: a respeito da opção -ub, veja o FAQ do WinMerge : é o mesmo que -u: diz ao WinMerge para não adicionar os arquivos ao MRU.
VonC
1
@Erik: você deve ver a comparação dos arquivos em c:\Temp\GitDiff\olde c:\Temp\GitDiff\new, não em ' /tmp'. Tem certeza de que está executando este programa DOS a partir de uma sessão DOS (e não de uma sessão bash)?
VonC
1
@coffeemakr não avaliou como ""no meu caso (executando o git configcomando de um CMD do Windows. Mas você está certo: ele avaliaria para ""se executado de um shell bash.
VonC
19

Tive problemas ao usar a primeira parte em 2 lugares e resolvi da seguinte forma

  1. O segundo comando para configurar winmerge.cmd exigia uma barra extra no cmdline (antes de $ LOCAL e $ REMOTE), caso contrário, o cygwin estava substituindo a variável no cmdline

    C:\myGitRepo>git config --replace --global difftool.winmerge.cmd "winmerge.sh \"\$LOCAL\" \"\$REMOTE\""
    
  2. alterou o arquivo winmerge.sh para (sem isso, estava obtendo erro de caminho correto inválido)

    #!/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")"
    
Gopi
fonte
3
Fiz exatamente como VonC instruiu, mas estava recebendo argumentos vazios em meu script winmerge.sh. Usar barras extras resolveu o problema. Obrigado!
ashagi
6

Como o tópico está ficando confuso e bifurcado, aqui estão as instruções consolidadas para o método WinMerge "--dir-diff" da Listagem de Diretórios para msysgit Git Windows.

Etapa 1 - Crie um arquivo chamado winmerge.sh em um local acessível ao seu caminho (como /home/bin/winmerge.sh) com o seguinte conteúdo.

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

Etapa 2 - Digite os seguintes comandos no Git Bash para instruir o git a usar winmerge.sh como difftool (essas opções são armazenadas em /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

Etapa 3 - Agora você pode testar digitando o seguinte comando no Git Bash para iniciar o seu diff WinMerge:

git difftool --dir-diff

Etapa 4 - Para acesso mais rápido, crie um alias para este comando adicionando esta linha a .bashrc em sua pasta inicial (ou crie o arquivo .bashrc com esta linha se o arquivo ainda não existir):

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

Etapa 5 - Agora você pode ver rapidamente uma diferença no WinMerge apenas digitando o seguinte comando no Git Bash

diffdir
robertcollier4
fonte
Seria útil ter alguém explicando os significados de $LOCALe $REMOTE.
Tola Odejayi
6

Eu tenho um script que irá definir as ferramentas Diff e Merge na configuração do Git com os parâmetros apropriados que não requerem um arquivo .sh separado para existir. Parece estar funcionando bem para mim.

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\""

Observação - toda a parte .cmd é citada para que os parâmetros sejam listados no .gitconfig corretamente

Alf47
fonte
1
O seguinte comando não funcionou para mim. git config --global difftool.winmerge.cmd "\"\$PROGRAMFILES\"/WinMerge/WinMergeU.exe -r -u -e -dl \"Local\" -dr \"Remote\" \"\$LOCAL\" \"\$REMOTE\"" Nota: Este comando deve ser executado a partir de um prompt de comando e não do PowerShell. Adicionar manualmente o seguinte à minha [difftool "winmerge"]seção .gitconfig funcionou para mim: cmd = 'C:/Program Files (x86)/WinMerge/WinMergeU.exe' -r -u -e -dl \"Local\" -dr \"Remote\" \"$LOCAL\" \"$REMOTE\"
Josh
1
Não funcionou, mas com algumas mudanças, ele funciona: cmd aberto como administrador, e executar: git config --global mergetool.winmerge.cmd "\"C:\Program Files (x86)\WinMerge\WinMergeU.exe\" -r -u -e -dl \"Local\" -dr \"Remote\" \"$LOCAL\" \"$REMOTE\" \"$BASE\" \"$MERGED\"". Havia algumas cadeias de caracteres de escape incorretas (observe algumas barras invertidas indesejadas antes do $- eu acho $que não precisa ser escapado). Além disso, estava faltando um fim "depois WinMergeU?.exe. Corra git config --get mergetool.winmerge.cmdpara ver o que foi definido de fato. De qualquer forma, obrigado pela não .shversão: +1!
falsarella
5

No Windows, você pode fazer isso desta forma:

1) Abra o arquivo .gitconfig. Ele está localizado em seu diretório inicial: c: \ users \ username.gitconfig

2) Adicione as linhas abaixo. Preste atenção às aspas simples que envolvem o caminho para o 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
Caner
fonte
Também preste atenção para os encaminhar barras em vez de barras invertidas no caminho de comando.
wisbucky de
5

Sem configuração:

git difftool --tool winmerge

Supondo:

  • Winmerge está instalado
  • O Git para Windows está instalado, a partir do "git versão 2.12.0.windows1" ou superior (embora versões anteriores do git possam ter introduzido o comando).
John Bentley
fonte
Obrigado, esta é a solução mais simples
code4j
2

Fiquei confuso sobre por que a solução foi apresentada como um arquivo batch DOS, já que minha instalação do Git veio com um shell bash. Eu também não consegui fazer um contexto DOS rodar no bash, então tentei adaptar o que era compartilhado anteriormente em um contexto bash.

Visto que git diffparece executar o comando especificado uma vez para cada arquivo, divido minha solução em dois scripts bash:

Primeiro, configure gitprepdiff.shpara ser o difftool conforme mencionado anteriormente

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

Também observei que os resultados dos git configurecomandos podem ser encontrados e editados diretamente noC:\Users\<username>\.gitconfigure

gitdiff.sh é então executado na linha de comando onde você normalmente chamaria 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

Também vale a pena notar que, na minha instalação, /tmp(em bash) mapeou para %LOCALAPPDATA%\Temp\1\(no Windows), então é por isso que estou usando o último em minha chamada para WinMerge.

Shawn South
fonte
2
Mudei gitprepdiff.shpara #!/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"Obrigado!
dobau
Parece ridículo saltar tantos obstáculos para fazer isso funcionar, mas funciona. Você obtém todas as diferenças de arquivo de uma vez, como deveria ser. Tive que fazer as alterações mencionadas por @dobau também para lidar adequadamente com os arquivos nos subdiretórios.
Tom,
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

De acordo com o manual de linha de comando WinMerge : "Os parâmetros são prefixados com uma barra (/) ou traço (-) caractere"

Steve Lang
fonte