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

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

Ответы [ 26 ]

376 голосов
/ 01 ноября 2008

Начиная с 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 инструмент, т.е. использовать косую черту вместо обратной косой черты. В моем случае у меня есть

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

в .gitconfig и

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

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

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

( Диомидис Спинеллис добавляет в комментариях :

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


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

204 голосов
/ 04 июня 2009

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

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

USAGE = '[--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 ответ ниже для примера, который имеет дело с:

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

Как Кем Мейсон упоминает в его ответ , вы также можете избежать любой оболочки, используя опцию --extcmd :

--extcmd=<command>

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

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

108 голосов
/ 14 марта 2010

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

$ meld my_project_using_git

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

40 голосов
/ 23 мая 2009

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

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

36 голосов
/ 27 августа 2009

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

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

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

23 голосов
/ 03 февраля 2011

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

git difftool -t

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

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

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

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

17 голосов
/ 07 ноября 2010

Опираясь на ответ 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
11 голосов
/ 21 февраля 2009

Решение для Windows / msys 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.

9 голосов
/ 30 марта 2010

Если вы делаете это через 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`
8 голосов
/ 21 июня 2017

Посмотрев на некоторые другие внешние инструменты сравнения, я обнаружил, что представление 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

...