Как просмотреть вывод 'git diff' с помощью моего предпочтительного инструмента сравнения / средства просмотра?

Когда я печатаю git diffЯ хочу просмотреть вывод с помощью инструмента визуального сравнения (SourceGear "diffmerge" в Windows). Как мне настроить git для этого?

26 ответов

Решение

Начиная с Git1.6.3, вы можете использовать скрипт git difftool: см. Мой ответ ниже.


Может быть, эта статья поможет вам. Вот лучшие части:

Есть два разных способа указать внешний инструмент сравнения.

Первый - это метод, который вы использовали, установив переменную GIT_EXTERNAL_DIFF. Однако предполагается, что переменная указывает на полный путь к исполняемому файлу. Кроме того, исполняемый файл, указанный в GIT_EXTERNAL_DIFF, будет вызываться с фиксированным набором из 7 аргументов:

path old-file old-hex old-mode new-file new-hex new-mode

Поскольку большинству инструментов сравнения потребуется другой порядок (и только некоторые) аргументов, вам, скорее всего, придется вместо этого указать скрипт-обертку, который, в свою очередь, вызывает настоящий инструмент сравнения.

Второй метод, который я предпочитаю, это настроить внешний инструмент сравнения через "git config". Вот что я сделал:

1) Создайте скрипт-обертку "git-diff-wrapper.sh", который содержит что-то вроде

-->8-(snip)--
#!/bin/sh

# diff is called by git with 7 parameters:
# path old-file old-hex old-mode new-file new-hex new-mode

"<path_to_diff_executable>" "$2" "$5" | cat
--8<-(snap)--

Как видите, только второй ("старый файл") и пятый ("новый файл") аргументы будут переданы в инструмент сравнения.

2) Тип

$ git config --global diff.external <path_to_wrapper_script>

в командной строке, заменив путь к "git-diff-wrapper.sh", поэтому ваш ~/.gitconfig содержит

-->8-(snip)--
[diff]
    external = <path_to_wrapper_script>
--8<-(snap)--

Обязательно используйте правильный синтаксис, чтобы указать пути к сценарию-оболочке и инструменту сравнения, т. Е. Используйте прямую косую черту вместо обратной косой черты. В моем случае у меня есть

[diff]
    external = \"c:/Documents and Settings/sschuber/git-diff-wrapper.sh\"

в.gitconfig и

"d:/Program Files/Beyond Compare 3/BCompare.exe" "$2" "$5" | cat

в сценарии оболочки. Следите за "котом"!

(Я полагаю, | cat 'требуется только для некоторых программ, которые могут не возвращать правильный или непротиворечивый статус возврата. Возможно, вы захотите попробовать без конечного кота, если ваш инструмент сравнения имеет явный статус возврата)

( Diomidis Spinellis добавляет в комментариях:

cat команда требуется, потому что diff(1) по умолчанию выходит с кодом ошибки, если файлы различаются.
Git ожидает, что внешняя программа сравнения завершит работу с кодом ошибки, только если произошла фактическая ошибка, например, если она исчерпала память.
По трубопроводу вывод git в cat ненулевой код ошибки маскируется.
Более эффективно, программа могла бы просто запустить exit с аргументом 0.)


Это (статья, приведенная выше) является теорией для внешнего инструмента, определенного через конфигурационный файл (не через переменную окружения).
На практике (все еще для определения файла конфигурации внешнего инструмента), вы можете обратиться к:

Чтобы завершить мой предыдущий конфиг "diff.external", ответ выше:

Как упомянул Jakub, в Git1.6.3 появился git difftool, первоначально предложенный в сентябре 2008 года:

ПРИМЕНЕНИЕ = '[--tool=tool] [--commit=ref] [--start=ref --end=ref] [--no-prompt] [file to merge]'
(Увидеть --extcmd в последней части этого ответа)

$LOCAL содержит содержимое файла с начальной ревизии и $REMOTE содержит содержимое файла в окончательной ревизии.
$BASE содержит содержимое файла в

Это в основном git-mergetool модифицировано для работы с git index/worktree.

Обычный сценарий использования этого сценария - это когда вы вносите или не ставите изменения, и вы хотели бы видеть изменения в параллельном средстве просмотра различий (например, xxdiff, tkdiff, так далее).

git difftool [<filename>*]

Другой вариант использования - это когда вы хотели бы видеть ту же информацию, но сравнивать произвольные коммиты (это та часть, в которой анализ синтаксиса может быть лучше)

git difftool --start=HEAD^ --end=HEAD [-- <filename>*]

Последний вариант использования - это когда вы хотите сравнить текущее рабочее дерево с чем-то отличным от HEAD (например, тегом).

git difftool --commit=v1.0.0 [-- <filename>*]

Примечание: начиная с Git 2.5, git config diff.tool winmerge достаточно!
Смотрите " git mergetool winmerge "

А с Git 1.7.11 у вас есть возможность --dir-diff, чтобы породить внешние инструменты сравнения, которые могут сравнивать две иерархии каталогов за один раз после заполнения двух временных каталогов, вместо того, чтобы запускать экземпляр внешнего инструмента один раз для пары файлов.


Перед Git 2.5:

Практический кейс для настройки difftool с вашим собственным инструментом сравнения:

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

С winmerge.sh, хранящимся в директории вашего PATH:

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

Если у вас есть другой инструмент (kdiff3, P4Diff, ...), создайте другой сценарий оболочки и соответствующий difftool.myDiffTool.cmd директива конфигурации
Тогда вы можете легко переключать инструменты с помощью diff.tool конфигурации.

У вас также есть эта запись в блоге Дейва, чтобы добавить другие детали.
(Или этот вопрос для winmergeu опции)

Интерес с этой настройкой winmerge.sh скрипт: вы можете настроить его для учета особых случаев.

См., Например, ответ David Marble ниже для примера, который имеет дело с:

  • новые файлы в исходном или целевом
  • удаленные файлы в исходном или целевом

Как упоминает Kem Mason в своем ответе, вы также можете избежать любой обертки, используя --extcmd вариант:

--extcmd=<command>

Укажите пользовательскую команду для просмотра различий. git-difftool игнорирует настроенные значения по умолчанию и работает $command $LOCAL $REMOTE когда указана эта опция.

Например, вот как gitk умеет запускать / использовать любые diff инструмент

В духе ответов на вопросы, которые несколько отличаются от заданных. Попробуйте это решение:

$ meld my_project_using_git

Meld понимает git и обеспечивает навигацию по последним изменениям.

С новым git difftool это так же просто, как добавить это в ваш файл .gitconfig:

[diff]
    tool = any-name
[difftool "any-name"]
    cmd = "\"C:/path/to/my/ext/diff.exe\" \"$LOCAL\" \"$REMOTE\""

Также ознакомьтесь с diffall, простым сценарием, который я написал для расширения раздражающего (IMO) поведения diff по умолчанию при открытии каждого в последовательной версии.

Начиная с git версии 1.6.3 есть " git difftool", который вы можете настроить для использования вашего любимого графического инструмента сравнения. В настоящее время из коробки поддерживаются: kdiff3, kompare, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge, diffuse и opendiff; если нужного вам инструмента нет в этом списке, вы всегда можете использоватьdifftool.<tool>.cmdвариант конфигурации.

"git difftool" принимает те же параметры, что и "git diff".

У меня есть одно дополнение к этому. Мне нравится регулярно использовать приложение diff, которое не поддерживается в качестве одного из инструментов по умолчанию (например, калейдоскоп), через

git difftool -t

Я также хотел бы иметь по умолчанию diff просто будьте обычной командной строкой, поэтому настройте GIT_EXTERNAL_DIFF переменная не вариант.

Вы можете использовать произвольный diff app как одноразовый с этой командой:

git difftool --extcmd=/usr/bin/ksdiff

Он просто передает 2 файла в указанную вами команду, поэтому вам, вероятно, также не нужна оболочка.

Основываясь на ответе VonC, касающемся удаления и добавления файлов, используйте следующие команды и сценарии:

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

Что то же самое, что поместить это в ваш глобальный .gitconfig:

[diff]
    tool = winmerge
[difftool "winmerge"]
    cmd = winmerge.bat "$LOCAL" "$REMOTE" "$BASE"
[difftool]
    prompt = false

Затем вставьте следующее в winmerge.shкоторый должен быть на вашем пути:

#!/bin/sh
NULL="/dev/null"
if [ "$2" = "$NULL" ] ; then
    echo "removed: $3"
elif [ "$1" = "$NULL" ] ; then
    echo "added: $3"
else
    echo "changed: $3"
    "C:/Program Files (x86)/WinMerge/WinMergeU.exe" -e -ub -dl "Base" -dr "Mine" "$1" "$2"
fi

Решение для Windows/ MSY GIT

Прочитав ответы, я обнаружил более простой способ, который заключается в изменении только одного файла.

  1. Создайте командный файл для вызова вашей программы сравнения с аргументами 2 и 5. Этот файл должен находиться где-то на вашем пути. (Если вы не знаете, где это, поместите его в c:\windows). Назовите это, например, "gitdiff.bat". Мой это:

    @echo off
    REM This is gitdiff.bat
    "C:\Program Files\WinMerge\WinMergeU.exe" %2 %5
    
  2. Установите переменную окружения так, чтобы она указывала на ваш командный файл. Например:GIT_EXTERNAL_DIFF=gitdiff.bat, Или через powershell, набрав git config --global diff.external gitdiff.bat,

    Важно не использовать кавычки или указывать какую-либо информацию о пути, иначе это не сработает. Вот почему gitdiff.bat должен быть на вашем пути.

Теперь, когда вы наберете "git diff", он вызовет ваш внешний просмотрщик diff.

Если вы делаете это через cygwin, вам может понадобиться использовать cygpath:

$ git config difftool.bc3.cmd "git-diff-bcomp-wrapper.sh \$LOCAL \$REMOTE"
$ cat git-diff-bcomp-wrapper.sh
#!/bin/sh
"c:/Program Files (x86)/Beyond Compare 3/BComp.exe" `cygpath -w $1` `cygpath -w $2`

Посмотрев на некоторые другие внешние инструменты сравнения, я обнаружил, что diff просмотр в IntelliJ IDEA (и Android Studio) - лучший для меня.

Шаг 1 - настроить IntelliJ IDEA для запуска из командной строки

Если вы хотите использовать IntelliJ IDEA в качестве инструмента сравнения, сначала необходимо настроить IntelliJ IDEA для запуска из командной строки, следуя приведенным ниже инструкциям:

В macOS или UNIX:

  1. Убедитесь, что IntelliJ IDEA работает.
  2. В главном меню выберите Tools | Create Command-line Launcher, Откроется диалоговое окно "Создать сценарий запуска" с предложенным путем и именем сценария запуска. Вы можете принять значение по умолчанию или указать свой собственный путь. Обратите внимание на это, так как оно понадобится вам позже. Вне IntelliJ IDEA, добавьте путь и имя сценария запуска к вашему пути.

В Windows:

  1. Укажите расположение исполняемого файла IntelliJ IDEA в системной переменной среды Path. В этом случае вы сможете вызывать исполняемый файл IntelliJ IDEA и другие команды IntelliJ IDEA из любого каталога.

Шаг 2 - сконфигурируйте git для использования IntelliJ IDEA в качестве difftool

Следуя инструкциям в этом блоге:

удар

export INTELLIJ_HOME /Applications/IntelliJ\ IDEA\ CE.app/Contents/MacOS
PATH=$IDEA_HOME $PATH

Рыба

set INTELLIJ_HOME /Applications/IntelliJ\ IDEA\ CE.app/Contents/MacOS
set PATH $INTELLIJ_HOME $PATH

Теперь добавьте следующее в ваш git config:

[merge]
   tool = intellij
[mergetool "intellij"]
   cmd = idea merge $(cd $(dirname "$LOCAL") && pwd)/$(basename "$LOCAL") $(cd $(dirname "$REMOTE") && pwd)/$(basename "$REMOTE") $(cd $(dirname "$BASE") && pwd)/$(basename "$BASE") $(cd $(dirname "$MERGED") && pwd)/$(basename "$MERGED")
   trustExitCode = true
[diff]
   tool = intellij
[difftool "intellij"]
   cmd = idea diff $(cd $(dirname "$LOCAL") && pwd)/$(basename "$LOCAL") $(cd $(dirname "$REMOTE") && pwd)/$(basename "$REMOTE")

Вы можете попробовать это с git difftool или же git difftool HEAD~1

Краткое резюме вышеупомянутых отличных ответов:

git difftool --tool-help
git config --global diff.tool <chosen tool>
git config --global --add difftool.prompt false

Затем используйте его, набрав (при желании также указав имя файла):

git difftool

Это работает для меня на Windows 7. Нет необходимости для промежуточных скриптов sh

содержимое.gitconfig:

    [diff]
      tool = kdiff3

    [difftool]
       prompt = false

    [difftool "kdiff3"]
      path = C:/Program Files (x86)/KDiff3/kdiff3.exe
      cmd = "$LOCAL" "$REMOTE"

Установить смесь

 # apt-get install meld

Затем выберите это как difftool

 $ git config --global diff.tool meld

Если вы хотите запустить его на консоли типа:

 $ git difftool

Если вы хотите использовать графический режим типа:

 $ git mergetool

И вывод будет:

 'git mergetool' will now attempt to use one of the following tools:
 meld opendiff kdiff3 tkdiff xxdiff tortoisemerge gvimdiff diffuse
 diffmerge ecmerge p4merge araxis bc3 codecompare emerge vimdiff
 Merging:
 www/css/style.css
 www/js/controllers.js

 Normal merge conflict for 'www/css/style.css':
   {local}: modified file
   {remote}: modified file
 Hit return to start merge resolution tool (meld):

Так что просто нажмите Enter, чтобы использовать meld(по умолчанию), это откроет графический режим, сохранит магию и нажмите, чтобы разрешить слияние. Это все

Если вы используете Mac и у вас есть XCode, значит, у вас установлен FileMerge. Терминальная команда opendiff, так что вы можете просто сделать git difftool -t opendiff

Вот пакетный файл, который работает для Windows - предполагается, что DiffMerge установлен в расположении по умолчанию, обрабатывает x64, обрабатывает замену с обратным слешем по мере необходимости и имеет возможность установить себя. Должно быть легко заменить DiffMerge вашей любимой программой сравнения.

Установить:

gitvdiff --install 

gitvdiff.bat:

@echo off

REM ---- Install? ----
REM To install, run gitvdiff --install

if %1==--install goto install



REM ---- Find DiffMerge ----

if DEFINED ProgramFiles^(x86^) (
    Set DIFF="%ProgramFiles(x86)%\SourceGear\DiffMerge\DiffMerge.exe"
) else (
    Set DIFF="%ProgramFiles%\SourceGear\DiffMerge\DiffMerge.exe"
)



REM ---- Switch forward slashes to back slashes ----

set oldW=%2
set oldW=%oldW:/=\%
set newW=%5
set newW=%newW:/=\%


REM ---- Launch DiffMerge ----

%DIFF% /title1="Old Version" %oldW% /title2="New Version" %newW%

goto :EOF



REM ---- Install ----
:install
set selfL=%~dpnx0
set selfL=%selfL:\=/%
@echo on
git config --global diff.external %selfL%
@echo off


:EOF

Вступление

Для справки я бы хотел добавить свой вариант ответа VonC. Имейте в виду, что я использую версию MSit для Git (1.6.0.2 в настоящее время) с измененным PATH и запускаю сам Git из Powershell (или cmd.exe), а не из оболочки Bash.

Я ввел новую команду, gitdiff, Выполнение этой команды временно перенаправляет git diff использовать программу визуального сравнения по вашему выбору (в отличие от решения VonC, которое делает это постоянно). Это позволяет мне использовать обе функции Git diff по умолчанию (git diff), а также функциональность визуальных различий (gitdiff). Обе команды принимают одинаковые параметры, поэтому, например, для визуального изменения изменений в конкретном файле, вы можете набрать

gitdiff path/file.txt

Настроить

Обратите внимание, что $GitInstall используется в качестве заполнителя для каталога, в котором установлен Git.

  1. Создать новый файл, $GitInstall\cmd\gitdiff.cmd

    @echo off
    setlocal
    for /F "delims=" %%I in ("%~dp0..") do @set path=%%~fI\bin;%%~fI\mingw\bin;%PATH%
    if "%HOME%"=="" @set HOME=%USERPROFILE%
    set GIT_EXTERNAL_DIFF=git-diff-visual.cmd
    set GIT_PAGER=cat
    git diff %*
    endlocal
    
  2. Создать новый файл, $GitInstall\bin\git-diff-visual.cmd (замена [visual_diff_exe] заполнитель с полным путем к программе diff на ваш выбор)

    @echo off
    rem diff is called by git with 7 parameters:
    rem path old-file old-hex old-mode new-file new-hex new-mode
    echo Diffing "%5"
    "[visual_diff_exe]" "%2" "%5"
    exit 0
    
  3. Теперь вы сделали. Бег gitdiff из репозитория Git теперь должен вызывать вашу программу визуального сравнения для каждого файла, который был изменен.

Для Linux-версии о том, как сконфигурировать инструмент сравнения различий в версиях git до 1.6.3 (1.6.3 добавило difftool в git), это отличный краткий учебник,

вкратце:

Шаг 1: добавьте это в ваш.gitconfig

[diff]
  external = git_diff_wrapper
[pager]
  diff =

Шаг 2: создайте файл с именем git_diff_wrapper, поместите его где-нибудь в $PATH

#!/bin/sh

vimdiff "$2" "$5"

В Mac OS X

git difftool -t diffuse 

делает за меня работу в папке git. Для установки diffuse можно использовать порт -

sudo port install diffuse

Ты можешь использовать git difftool,

например, если у вас есть объединение, вы можете редактировать ветви master а также devel от:

git config --global diff.external meld
git difftool master..devel

Следующее можно почерпнуть из других ответов здесь, но для меня это сложно (слишком много информации), так что вот ответ "просто введите его" для tkdiff:

git difftool --tool=tkdiff <path to the file to be diffed>

Вы можете заменить исполняемое имя вашего любимого инструмента сравнения на tkdiff. Пока (например, tkdiff) (или ваш любимый инструмент сравнения) находится в вашем PATH, он будет запущен.

Я попробовал модные вещи здесь (с tkdiff), и у меня ничего не получалось. Поэтому я написал следующий скрипт, tkgitdiff. Он делает то, что мне нужно.

$ cat tkgitdiff
#!/bin/sh

#
# tkdiff for git.
# Gives you the diff between HEAD and the current state of your file.
#

newfile=$1
git diff HEAD -- $newfile > /tmp/patch.dat
cp $newfile /tmp
savedPWD=$PWD
cd /tmp
patch -R $newfile < patch.dat
cd $savedPWD
tkdiff /tmp/$newfile $newfile

Я использовал этот бит в ~/.gitconfig в течение долгого времени:

[diff]
    external = ~/Dropbox/source/bash/git-meld

С git-meld:

#!/bin/bash
if [ "$DISPLAY" = "" ];
then
    diff $2 $5
else
    meld $2 $5
fi

Но теперь я устал от использования meld в графической среде, и с этой настройкой вызывать нормальный diff нетривиально, поэтому я переключился на это:

[alias]
    v =  "!sh -c 'if [ $# -eq 0 ] ; then git difftool -y -t meld ; else git difftool -y $@ ; fi' -"

При такой настройке работают такие вещи:

git v
git v --staged
git v -t kompare
git v --staged -t tkdiff

И я все еще могу сохранить старое доброе git diff,

Я использую Kompare на Ubuntu:

sudo apt-get install kompare

Чтобы сравнить две ветви:

git difftool -t kompare <my_branch> master

Вы можете попробовать xd http://github.com/jiqingtang/xd, который является оболочкой GUI для diff GIT/SVN. Это не инструмент сравнения. Ты бежишь xd когда хочешь бежать git diff или же svn diff и он покажет вам список файлов, окно предварительного просмотра, и вы сможете запустить любой инструмент сравнения, который вам нравится, включая tkdiff, xxdiff, gvimdiff, emacs(ediff), xemacs(ediff), meld, diffuse, kompare и kdiff3. Вы также можете запустить любой пользовательский инструмент.

К сожалению, инструмент не поддерживает Windows.

Раскрытие: я являюсь автором этого инструмента.

Если у вас уже есть инструмент сравнения, связанный с типами файлов (скажем, из-за того, что вы установили TortoiseSVN, который поставляется с средством просмотра diff), вы можете просто передать обычный git diff Выведите в "временный" файл, затем просто откройте этот файл напрямую, не нужно ничего знать о программе просмотра:

git diff > "~/temp.diff" && start "~/temp.diff"

Установка его в качестве глобального псевдонима работает еще лучше: git what

[alias]
    what = "!f() { git diff > "~/temp.diff" && start "~/temp.diff"; }; f"

Если вы не один для командной строки, то, если вы устанавливаете Git tortoise, вы можете щелкнуть правой кнопкой мыши файл, чтобы получить подменю tortoisegit с опцией "Diff позже".

Когда вы выбираете это в первом файле, вы можете затем щелкнуть правой кнопкой мыши по второму файлу, перейти в подменю tortoisegit и выбрать "Diff with ==yourfilehere==". Это даст графический интерфейс tortoisegitmerge для результата.

Другие вопросы по тегам