Как я могу получить разностное сравнение, когда я делаю «git diff»?

163

Когда я набираю «git diff», я хотел бы видеть параллельный diff, например «diff -y», или отображать diff в интерактивном инструменте diff, например «kdiff3». Как это может быть сделано?

Майк
источник

Ответы:

89

Хотя Git имеет внутреннюю реализацию diff, вы можете вместо этого настроить внешний инструмент.

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

  1. установка переменных GIT_EXTERNAL_DIFFи GIT_DIFF_OPTSокружения.
  2. настройка внешнего инструмента сравнения с помощью git config

Смотрите также:

При выполнении git diffGit проверяет как настройки вышеупомянутых переменных окружения, так и его .gitconfigфайл.

По умолчанию Git передает следующие семь аргументов программе diff:

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

Обычно вам нужны только параметры old-file и new-file. Конечно, большинство инструментов сравнения принимают в качестве аргумента только два имени файла. Это означает, что вам нужно написать небольшой скрипт-обертку, который принимает аргументы, которые Git предоставляет скрипту, и передает их внешней программе git по вашему выбору.

Допустим, вы поместили свой скрипт-обертку в ~/scripts/my_diff.sh:

#!/bin/bash
# un-comment one diff tool you'd like to use

# side-by-side diff with custom options:
# /usr/bin/sdiff -w200 -l "$2" "$5" 

# using kdiff3 as the side-by-side diff:
# /usr/bin/kdiff3 "$2" "$5"

# using Meld 
/usr/bin/meld "$2" "$5"

# using VIM
# /usr/bin/vim -d "$2" "$5"

Затем вам нужно сделать этот скрипт исполняемым:

chmod a+x ~/scripts/my_diff.sh

Затем вам нужно сообщить Git, как и где найти ваш собственный скрипт для оболочки diff. У вас есть три варианта, как это сделать: (Я предпочитаю редактировать файл .gitconfig)

  1. Используя GIT_EXTERNAL_DIFF,GIT_DIFF_OPTS

    например, в вашем файле .bashrc или .bash_profile вы можете установить:

    GIT_EXTERNAL_DIFF=$HOME/scripts/my_diff.sh
    export GIT_EXTERNAL_DIFF
    
  2. С помощью git config

    используйте "git config", чтобы определить, где находится ваш скрипт-обертка:

    git config --global diff.external ~/scripts/my_diff.sh
    
  3. Редактирование вашего ~/.gitconfigфайла

    Вы можете отредактировать свой ~/.gitconfigфайл, чтобы добавить эти строки:

    [diff]
      external = ~/scripts/my_diff.sh
    

Примечание:

Аналогично установке вашего специального инструмента сравнения, вы также можете установить собственный инструмент слияния, который может быть визуальным инструментом слияния, чтобы лучше помочь визуализировать слияние. (см. страницу progit.org)

Смотрите: http://fredpalma.com/518/visual-diff-and-merge-tool/ и https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration

Тило
источник
1
Сохраняет ли это окраску git терминала?
Шридхар Сарнобат
3
Это здорово, но запускает новый просмотрщик для каждого файла. Есть ли способ создать консолидированную разницу, скажем, в meld?
HRJ
2
@ Tilo Я получаю сообщение об ошибке для vim as im: Предупреждение: вывод не на терминал
мертвый программист
Можно meldли настроить версию для создания каталога diff, где я могу выбрать, для каких файлов я хочу просмотреть diff? В настоящее время он запускает отдельную meldкоманду для каждого файла, и мне нужно выйти meld, чтобы увидеть следующий файл. Я бы предпочел meldпоказать мне список каталогов измененных файлов, как он ведет себя при meldиспользовании из Mercurial.
kasperd
163

Попробуй git difftool

Используйте git difftoolвместо git diff. Ты никогда не вернешься.

ОБНОВЛЕНИЕ, чтобы добавить пример использования:

Вот ссылка на другой стековый поток, в котором говорится git difftool: Как просмотреть вывод «git diff» с помощью моего предпочтительного инструмента сравнения / средства просмотра?

Для более новых версий git, то difftoolкоманда поддерживает множество инструментов внешней Diff вне из коробки. Например, vimdiffподдерживается автоматически и может быть открыт из командной строки:

cd /path/to/git/repo
git difftool --tool=vimdiff

Другие поддерживаемые внешние инструменты сравнения перечислены git difftool --tool-helpв следующем примере:

'git difftool --tool=<tool>' may be set to one of the following:
        araxis
        kompare
        vimdiff
        vimdiff2

The following tools are valid, but not currently available:
        bc3
        codecompare
        deltawalker
        diffuse
        ecmerge
        emerge
        gvimdiff
        gvimdiff2
        kdiff3
        meld
        opendiff
        tkdiff
        xxdiff
Мэтт Болл
источник
34
Или, может быть, вы вернетесь, если получите This message is displayed because 'diff.tool' is not configured.. Возможно, обновите ответ с минимальной настройкой этой вещи, чтобы она отображала в терминале параллельные различия, о чем просил OP? Инструменты с графическим интерфейсом совершенно бесполезны на удаленном сервере, где вы подключаетесь с помощью ssh.
Петр
1
Интересный момент, хотя я не думаю, что лично мне когда-либо нужно было использовать git во время SSH. Одна из приятных вещей в DVCS - это распределенная часть: по крайней мере, в моей среде никогда не возникает проблем с локальным клонированием любого репо, который я хочу просмотреть.
Мэтт Болл
1
По крайней мере, в моей конфигурации, git difftoolс vimdiffне всегда правильно выстроить два файла / буфера.
Ромер
1
Это хорошо, и так внизу в списке ответов: использование OI, git difftool -yчтобы предотвратить приглашение
tkdiff
Связанный: сделайте свою комбинацию git difftoolв Windows & Linux: stackoverflow.com/a/48979939/4561887
Габриэль Стейплс
57

Вы также можете попробовать git diff --word-diff. Это не совсем бок о бок, но как-то лучше, так что вы можете предпочесть это вашим реальным потребностям.

mb14
источник
12
Это самый простой способ. Что еще лучшеgit diff --word-diff=color
Рольф
@Rolf --word-diff=colorвыдает мне неверную опцию ошибки. В какой версии он был представлен?
Холлоуэй,
@Trengot Я запускаю Git 1.7.9, начиная с 02/2012
Рольф,
4
@Рольф по умолчанию установленная версия здесь 1.7.1. Могли бы объяснить разницу. git diff --color-wordsработает.
Holloway
4
Да, git diff --color-wordsэто путь на современных версиях git.
Василий Новиков
41

ydiff

Ранее назывался cdiff, этот инструмент может отображать бок о бок , инкрементные и красочные различия.

Вместо этого git diffсделайте:

ydiff -s -w0

Это запустит ydiffрежим параллельного отображения для каждого файла с различиями.

Установить с помощью:

python3 -m pip install --user ydiff

-или-

brew install ydiff

Для git logвы можете использовать:

ydiff -ls -w0

-w0автоматически определяет ширину вашего терминала. Смотрите ydiff страницу репозитория GitHub для деталей и демонстрации.

Протестировано в Git 2.18.0, ydiff 1.1.

ymattw
источник
@RyneEverett: Можете ли вы объяснить, как сделать эквивалент git diff | cdiff -sс icdiff?
einpoklum
Просто запустите ydiff -sиз рабочего пространства git / svn / hg, вам не нужно
вводить данные
если вы хотите ограничить diff определенным файлом в истории Git, cd <git repo>а затем запуститьydiff -ls <path/to/file>
slm
22

Вы можете сделать бок о бок, diffиспользуя sdiffследующее:

$ git difftool -y -x sdiff  HEAD^ | less

где HEAD^пример, который вы должны заменить тем, с чем хотите разобраться.

Я нашел это решение здесь, где есть несколько других предложений. Тем не менее, этот единственный ответ - вопрос ОП кратко и ясно.

Смотрите man git-difftool для объяснения аргументов.


Принимая комментарии на доске, вы можете создать удобную git sdiffкоманду, написав следующий исполняемый скрипт:

#!/bin/sh
git difftool -y -x "sdiff -w $(tput cols)" "${@}" | less

Сохраните это как /usr/bin/git-sdiffи chmod -xэто. Тогда вы сможете сделать это:

$ git sdiff HEAD^
starfry
источник
Я обычно делаю "$ git difftool -x 'sdiff -s -w 240'" (или любой другой ширины экрана), если / когда я хочу подавить те же строки и есть только один файл (иначе я делаю vimdiff)
HidekiAI
1
@HidekiAI Я считаю , это боль , чтобы ввести терминал ширина каждый раз, поэтому я использую tput colsвместо этого, например: git difftool -x "sdiff -s -w $(tput cols)".
Жауме
это может выделить изменения в цвете? Прямо сейчас кажется, что мы должны использовать наши глаза, чтобы определить, что на самом деле являются изменениями
неполярность
Замените sdiff на icdiff, чтобы получить хороший цветной дисплей.
Грег
10
export GIT_EXTERNAL_DIFF='meld $2 $5; echo >/dev/null'

тогда просто:

git diff
krzych
источник
1
`Слияние. ' тоже работает! И он показывает все изменения в сводном окне.
HRJ
@ HRJ, который работает отлично! Так просто и практично :)
Waldyrious
9

Если вы хотите видеть в браузере параллельные различия без использования GitHub, вам может понравиться git webdiff , заменяющий git diff:

$ pip install webdiff
$ git webdiff

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

Подробнее об этом читайте здесь .

danvk
источник
7

Я использую Colordiff .

В Mac OS X установите его с

$ sudo port install colordiff

На Linux это возможно apt get install colordiffили что-то подобное, в зависимости от вашего дистрибутива.

Затем:

$ git difftool --extcmd="colordiff -ydw" HEAD^ HEAD

Или создайте псевдоним

$ git alias diffy "difftool --extcmd=\"colordiff -ydw\""

Тогда вы можете использовать его

$ git diffy HEAD^ HEAD

Я назвал это "diffy", потому что diff -yэто параллельный diff в unix. Colordiff также добавляет цвета, которые приятнее. В этом параметре -ydw, yэто для бок о бок, wигнорировать пробелы и dпроизводить минимальный diff (обычно вы получите лучший результат как diff)

Луиджи Р. Виджано
источник
добавить, -yчтобы пропустить Launch 'colordiff' [Y/n]:приглашение.
Бени Чернявский-Паскин
ты уверен, что это так git alias diffy "difftool --extcmd=\"colordiff -ydw\""? Не должно ли это быть git config --global alias.diffy "difftool --extcmd=\"colordiff -ydw\""?
неполярность
6

Для Unix, совмещая как раз gitи встроенный diff:

git show HEAD:path/to/file | diff -y - path/to/file

Конечно, вы можете заменить HEAD любой другой ссылкой на git и, возможно, захотите добавить что-то вроде -W 170команды diff.

Это предполагает, что вы просто сравниваете содержимое своего каталога с прошлым коммитом. Сравнение двух коммитов более сложное. Если ваша оболочка есть, bashвы можете использовать «процесс подстановки»:

diff -y -W 170 <(git show REF1:path/to/file) <(git show REF2:path/to/file)

где REF1и REF2git ссылки - теги, ветки или хеши.

Уокер Хейл IV
источник
Спасибо - ваша команда 'git show HEAD: путь / к / файлу' была тем, что мне было нужно, чтобы найти собственное решение, 'vimdfiff <(git show HEAD: путь / к / файлу) путь / к / файлу ". Биты все еще не выстроены правильно, но это лучшее решение, которое у меня есть сейчас.
talexb
5

Мне лично очень нравится icdiff !

Если вы на Mac OS Xс HomeBrew, просто сделать brew install icdiff.

Чтобы правильно получить метки файлов, а также другие интересные функции, я имею в своем ~/.gitconfig:

[pager]
    difftool = true
[diff]
    tool = icdiff
[difftool "icdiff"]
    cmd = icdiff --head=5000 --highlight --line-numbers -L \"$BASE\" -L \"$REMOTE\" \"$LOCAL\" \"$REMOTE\"

И я использую это как: git difftool

Хосе Албан
источник
3

Этот вопрос появился, когда я искал быстрый способ использовать встроенный способ git для определения различий. Мои критерии решения:

  • Быстрый запуск, нужны встроенные опции
  • Может легко обрабатывать множество форматов, XML, различные языки программирования
  • Быстрое выявление небольших изменений кода в больших текстовых файлах

Я нашел этот ответ, чтобы получить цвет в мерзавце.

Чтобы получить параллельный diff вместо строки diff, я настроил отличный ответ mb14 на этот вопрос со следующими параметрами:

$ git diff --word-diff-regex="[A-Za-z0-9. ]|[^[:space:]]"

Если вам не нравится дополнительная [- или {+, опция --word-diff=colorможет быть использована.

$ git diff --word-diff-regex="[A-Za-z0-9. ]|[^[:space:]]" --word-diff=color

Это помогло получить правильное сравнение как с json, так и с xml текстом и java кодом.

Таким образом, --word-diff-regexпараметры имеют полезную видимость вместе с настройками цвета, чтобы получить возможность раскрашивать исходный код рядом друг с другом по сравнению со стандартной разницей строк при просмотре больших файлов с небольшими изменениями строк.

Майк
источник
3

Несколько других уже упоминали cdiff для git- сравнения, но никто не дал полной реализации этого.

Настройте cdiff:

git clone https://github.com/ymattw/cdiff.git
cd cdiff
ln -s `pwd`/cdiff ~/bin/cdiff
hash -r # refresh your PATH executable in bash (or 'rehash' if you use tcsh)
        # or just create a new terminal

Отредактируйте ~ / .gitconfig, вставив эти строки:

[pager]
        diff = false
        show = false

[diff]
        tool = cdiff
        external = "cdiff -s $2 $5 #"

[difftool "cdiff"]
        cmd = cdiff -s \"$LOCAL\" \"$REMOTE\"

[alias]
        showw = show --ext-dif

Выключение пейджера необходимо для работы cdiff с Diff, в любом случае это пейджер, так что это нормально. Difftool будет работать независимо от этих настроек.

Псевдоним show необходим, потому что git show поддерживает только внешние инструменты сравнения через аргумент.

Знак «#» в конце внешней команды diff важен. Команда diff в Git добавляет $ @ (все доступные переменные diff) к команде diff, но нам нужны только два имени файла. Таким образом, мы вызываем эти два явно с $ 2 и $ 5, а затем скрываем $ @ за комментарием, который иначе запутал бы sdiff. В результате возникает ошибка, которая выглядит следующим образом:

fatal: <FILENAME>: no such path in the working tree
Use 'git <command> -- <path>...' to specify paths that do not exist locally.

Команды Git, которые теперь производят параллельное сравнение:

git diff <SHA1> <SHA2> 
git difftool <SHA1> <SHA2>
git showw <SHA>

Использование CDIF:

'SPACEBAR' - Advances the page of the current file.
'Q'        - Quits current file, thus advancing you to the next file.

Теперь у вас есть параллельный diff через git diff и difftool. И у вас есть исходный код Python для настройки опытных пользователей, если вам это нужно.

Эрик
источник
2

Вот подход. Если вы пропустили меньше, ширина xterm будет равна 80, что не так уж и жарко. Но если вы продолжите команду, например, с COLS = 210, вы можете использовать ваш расширенный xterm.

gitdiff()
{
    local width=${COLS:-$(tput cols)}
    GIT_EXTERNAL_DIFF="diff -yW$width \$2 \$5; echo >/dev/null" git diff "$@"
}
Томас Меллман
источник
1
Веселая. Я подписался именем под псевдонимом, но это было проигнорировано ... Спасибо, что вытащил меня, переполнение стека. :(
Томас Меллман
2

Откройте Intellij IDEA , выберите одну или несколько фиксаций в окне инструмента «Контроль версий», просмотрите измененные файлы и дважды щелкните их, чтобы просмотреть изменения рядом для каждого файла.

С помощью встроенного средства запуска командной строки вы можете вывести IDEA куда угодно с помощью простого idea some/path

представление управления версиями разный вид

Хольгер Брандл
источник
1

Есть много хороших ответов на эту тему. Моим решением этой проблемы было написать сценарий.

Назовите это 'git-scriptname' (и сделайте его исполняемым и поместите его в свой PATH, как любой скрипт), и вы можете вызвать его как обычную команду git, выполнив

$ git scriptname

Фактическая функциональность - это только последняя строка. Вот источник:

#!/usr/bin/env zsh
#
#   Show a side-by-side diff of a particular file how it currently exists between:
#       * the file system
#       * in HEAD (latest committed changes)

function usage() {
    cat <<-HERE
    USAGE

    $(basename $1) <file>

    Show a side-by-side diff of a particular file between the current versions:

        * on the file system (latest edited changes)
        * in HEAD (latest committed changes)

HERE
}

if [[ $# = 0 ]]; then
    usage $0
    exit
fi

file=$1
diff -y =(git show HEAD:$file) $file | pygmentize -g | less -R
Джон Картер
источник
1

Это может быть несколько ограниченным решением, но оно выполняет работу, используя системную diffкоманду без внешних инструментов:

diff -y  <(git show from-rev:the/file/path) <(git show to-rev:the/file/path)
  • Фильтруйте только использование линий изменения --suppress-common-lines(если ваша diffопция поддерживает эту опцию).
  • в этом случае нет цветов, только обычные diffмаркеры
  • можно настроить ширину столбца --width=term-width; в Bash можно получить ширину как $COLUMNSили tput cols.

Это может быть также включено в вспомогательный git-скрипт для большего удобства, например, при использовании такого типа:

git diffy the/file/path --from rev1 --to rev2
nomadbyte
источник