użyj Winmerge wewnątrz Gita, aby zapisać różnice

Odpowiedzi:

113

Aktualizacja czerwiec 2015, 6 lat później:

Jak opisano szczegółowo w " git connectetool winmerge ", wystarczy prosty git config diff.tool winmerge.

Git 2.5+ (Q2, 2015) jest teraz świadomy Winmerge jako narzędzia porównywania lub scalania!


Oryginalna odpowiedź (2009-2012)

(msysgit, 1.6.5, sesja DOS)

Pierwsza część (używając winmerge) jest opisana w " Jak wyświetlić wyjście 'git diff' za pomocą programu 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

Z winmerge.shprzechowywanymi w katalogu części PATH:

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

(zobacz opcje wiersza poleceń WinMerge )

git difftool

uruchomi teraz WinMerge.
Jeśli chcesz git diffuruchomić WinMerge, po prostu ustaw:

set GIT_EXTERNAL_DIFF=winmerge.sh

Ale prawdziwa wartość dodana pochodzi z możliwości użycia tego samego narzędzia porównywania do przedstawienia wszystkich różnic w jednej partii zamiast przedstawiania ich po kolei, zmuszając cię do zamykania okien narzędzia porównywania po jednym pliku na raz.

Aktualizacja czerwiec 2012 (2 i pół roku później):

Wkrótce będzie dostępne porównywanie katalogów zamiast plików po plikach:
Zobacz [ANNOUNCE] Git 1.7.11.rc1 :

" git difftool" nauczył się " --dir-diff" opcji wywoływania zewnętrznych narzędzi porównujących, które mogą porównywać dwie hierarchie katalogów naraz po zapełnieniu dwóch katalogów tymczasowych, zamiast uruchamiać instancję narzędzia zewnętrznego raz dla pary plików .

Zobacz „ Łatka difftool: naucz difftoolobsługiwać różnice katalogowe ” i odpowiedź „ Porównanie katalogów gałęzi Git ”, aby uzyskać więcej informacji.


Oryginalny skrypt difftool by directories (grudzień 2009)

Jak wspomina Seba Illingworth w swojej odpowiedzi , skrypt git-diffall.sh (również umieszczony w ścieżce) może to zrobić:

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

Ale to działa tylko po otwarciu n okien dla n plików (jeśli spróbujesz użyć -sopcji WinMerge, nie zadziała z powodu zbyt wczesnego usunięcia plików tymczasowych przez difftool)


Dlatego podoba mi się podejście GitDiff.bat - różnicowanie mocy za pomocą GI , które pozwala przejrzeć listę plików z różnicą, przed wybraniem jednego do zbadania jego wewnętrznych różnic.
Poprawiłem go, aby używał tylko poleceń 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

Nie jest wystarczająco solidne, aby obsługiwać pliki o tych samych nazwach w różnych katalogach, ale daje ogólne pojęcie o tym, co jest możliwe:
tutaj otworzy się tylko jedno WinMerge, z listą plików mających wewnętrzne różnice. Możesz kliknąć te, które chcesz zbadać, a następnie prosty ESCzamknie całą WinMerge-diffsesję.

VonC
źródło
1
Próbuję tego z wersją git 1.6.5.1.1367.gcd48 i wygląda na to, że nie generuje żadnych plików w tych folderach tymczasowych. Jakieś pomysły, gdzie szukać problemu? Dzięki!
Art
@Art: w tych przypadkach debugowania staram się wyodrębnić problem, upraszczając skrypt: 1 / jeśli skrypt wywołany z parametrem 7 (pierwsze przejście git diff, aby skopiować pliki) 2 / czy skrypt jest przynajmniej wywołany z powrotem pod koniec git diff?
VonC,
1
@Erik: odnośnie opcji -ub, zobacz WinMerge FAQ : jest to to samo, co -u: mówi WinMerge, aby nie dodawał plików do MRU.
VonC
1
@Erik: powinieneś zobaczyć porównanie plików w c:\Temp\GitDiff\oldi c:\Temp\GitDiff\newnie ' /tmp'. Czy na pewno uruchamiasz ten program DOS z sesji DOS (a nie z sesji bash)?
VonC
1
@coffeemakr to nie zostało ocenione ""w moim przypadku (wykonywanie git configpolecenia z CMD systemu Windows. Ale masz rację: wynikałoby to, ""gdyby został wykonany z powłoki bash.
VonC
19

Miałem problemy z użyciem pierwszej części w 2 miejscach i naprawiłem to w następujący sposób

  1. Drugie polecenie do ustawienia winmerge.cmd wymagało dodatkowego ukośnika w cmdline (przed $ LOCAL i $ REMOTE), w przeciwnym razie cygwin podstawiał zmienną w cmdline

    C:\myGitRepo>git config --replace --global difftool.winmerge.cmd "winmerge.sh \"\$LOCAL\" \"\$REMOTE\""
    
  2. zmienił plik winmerge.sh na (bez tego pojawiał się błąd prawidłowej ścieżki)

    #!/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
źródło
3
Zrobiłem dokładnie tak, jak polecił VonC, ale otrzymałem puste argumenty w moim skrypcie winmerge.sh. Użycie dodatkowych ukośników rozwiązało problem. Dziękuję Ci!
ashagi
6

Ponieważ wątek staje się zagmatwany i rozwidlony, poniżej znajdują się skonsolidowane instrukcje dotyczące metody WinMerge "--dir-diff" z listą katalogów dla msysgit Git Windows.

Krok 1 - Utwórz plik o nazwie winmerge.sh w lokalizacji dostępnej dla Twojej ścieżki (takiej jak /home/bin/winmerge.sh) z następującą zawartością.

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

Krok 2 - Wpisz następujące polecenia w Git Bash, aby poinstruować git, aby używał winmerge.sh jako difftool (te opcje są przechowywane w /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

Krok 3 - Teraz możesz przetestować, wpisując następujące polecenie w Git Bash, aby uruchomić różnicę WinMerge:

git difftool --dir-diff

Krok 4 - Aby uzyskać szybszy dostęp, utwórz alias dla tego polecenia, dodając tę ​​linię do .bashrc w folderze domowym (lub utwórz plik .bashrc z tą linią, jeśli plik jeszcze nie istnieje):

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

Krok 5 - Teraz możesz szybko zobaczyć różnicę w WinMerge, po prostu wpisując następujące polecenie w Git Bash

diffdir
robertcollier4
źródło
Byłoby pomocne, gdyby ktoś wyjaśnił znaczenie $LOCALi $REMOTE.
Tola Odejayi
6

Mam skrypt, który ustawi narzędzia porównywania i scalania w konfiguracji Git z odpowiednimi parametrami, które nie wymagają oddzielnego pliku .sh. Wydaje się, że dla mnie działa dobrze.

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

Uwaga - cała część .cmd jest cytowana, aby parametry były poprawnie wymienione w pliku .gitconfig

Alf47
źródło
1
Następujące polecenie nie działa dla mnie. git config --global difftool.winmerge.cmd "\"\$PROGRAMFILES\"/WinMerge/WinMergeU.exe -r -u -e -dl \"Local\" -dr \"Remote\" \"\$LOCAL\" \"\$REMOTE\"" Uwaga: to polecenie należy uruchomić z wiersza polecenia, a nie z programu PowerShell. Ręczne dodanie następujących elementów do mojej [difftool "winmerge"]sekcji .gitconfig zadziałało dla mnie: cmd = 'C:/Program Files (x86)/WinMerge/WinMergeU.exe' -r -u -e -dl \"Local\" -dr \"Remote\" \"$LOCAL\" \"$REMOTE\"
Josh
1
To nie działa, ale z pewnymi zmianami, to działa: otwarty cmd jako administrator i uruchom: git config --global mergetool.winmerge.cmd "\"C:\Program Files (x86)\WinMerge\WinMergeU.exe\" -r -u -e -dl \"Local\" -dr \"Remote\" \"$LOCAL\" \"$REMOTE\" \"$BASE\" \"$MERGED\"". Było kilka niepoprawnych ciągów znaków ucieczki (zwróć uwagę na kilka dodatkowych niechcianych odwrotnych ukośników tuż przed $- chyba $nie trzeba ich uciekać). Także, to brakowało kres "po WinMergeU?.exe. Biegnij, git config --get mergetool.winmerge.cmdaby zobaczyć, co zostało ustawione. W każdym razie dzięki za brak .shwersji: +1!
falsarella
5

W systemie Windows możesz to zrobić w ten sposób:

1) Otwórz plik .gitconfig. Znajduje się w twoim katalogu domowym: c: \ users \ nazwa_użytkownika.gitconfig

2) Dodaj poniższe linie. Zwróć uwagę na pojedyncze cudzysłowy otaczające ścieżkę do 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
źródło
Zwróć także uwagę na ukośniki do przodu zamiast ukośników odwrotnych w ścieżce poleceń.
wisbucky
5

Bez konfiguracji:

git difftool --tool winmerge

Zarozumiały:

  • Winmerge jest zainstalowany
  • Git dla Windows jest instalowany z "git w wersji 2.12.0.windows1" lub nowszej (chociaż wcześniejsze wersje gita mogły wprowadzać to polecenie).
John Bentley
źródło
Dzięki, to najprostsze rozwiązanie
code4j
2

Byłem zdezorientowany, dlaczego rozwiązanie zostało przedstawione jako plik wsadowy DOS, ponieważ moja instalacja Git była dostarczana z powłoką bash. Nie mogłem również uruchomić kontekstu DOS z bash, więc próbowałem dostosować to, co było wcześniej udostępniane w kontekście bash.

Ponieważ git diffwydaje się, że uruchamia określone polecenie raz dla każdego pliku, podzieliłem moje rozwiązanie na dwa skrypty bash:

Najpierw skonfiguruj gitprepdiff.shnarzędzie difftool, jak wspomniano wcześniej

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

Zauważyłem również, że wyniki git configurepoleceń można znaleźć i edytować bezpośrednio wC:\Users\<username>\.gitconfigure

gitdiff.sh jest następnie uruchamiany w wierszu poleceń, w którym normalnie byś wywołał 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

Warto również zauważyć, że w mojej instalacji /tmp(w bash) jest mapowane na %LOCALAPPDATA%\Temp\1\(w systemie Windows), dlatego używam tego drugiego w moim wywołaniu WinMerge.

Shawn South
źródło
2
Zmieniłem się gitprepdiff.shna #!/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"Dziękuję!
dobau
Wydaje się śmieszne, aby przeskoczyć przez tak wiele obręczy, aby to zadziałało, ale tak jest. Otrzymujesz wszystkie różnice plików za jednym razem, tak jak powinno. Musiałem też wprowadzić zmiany, o których wspomniał @dobau, aby poprawnie obsługiwać pliki w podkatalogach.
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

Zgodnie z instrukcją wiersza poleceń WinMerge : „Parametry są poprzedzone znakiem ukośnika (/) lub myślnika (-)”

Steve Lang
źródło