Git diff, чтобы отображать только строки, которые были изменены

128

Когда я делаю git diff, он показывает добавленные строки:

+ this line is added

строки, которые были удалены:

- this line is removed

но он также показывает много строк, которые не изменяются:

this line is not modified
this line is also not modified

Это приводит к тому, что фактический git diff выглядит примерно так:

+ this line is added
  this line is not modified
- this line is removed
  this line is not modified

Могу ли я попросить git отображать только измененные строки и игнорировать весь остальной код, который не был изменен? Я написал метод, который удалит все строки, перед которыми нет знака «+» или «-», но я уверен, что должен быть более простой способ сделать это.

В моем git diff меня интересуют только те строки, которые были изменены.

Заранее спасибо.

r3b00t
источник

Ответы:

182

Вам нужна разница с 0 строками контекста. Вы можете создать это с помощью:

git diff --unified=0

или

git diff -U0

Вы также можете установить это как параметр конфигурации для этого репозитория:

git config diff.context 0

Чтобы настроить его глобально для любого репозитория:

 git config --global diff.context 0
Крис Хейс
источник
4
Спасибо за быстрый ответ. Это решает половину моей проблемы, но я все еще получаю несколько строк вроде «@@ -1 +1 @@» в моем diff, а в верхней части моего git diff есть «diff --git a / db / xxxxxxx b / db / xxxx index. xxxxx..aaaaaaa bbbbbbbb
r3b00t
3
Я не думаю, что git предоставляет какой-либо способ избежать вывода этих строк, потому что без них различие не имело бы смысла (вы не могли знать, какой файл вы просматриваете, и где вы были в файле).
Chris Hayes
8
@Rakesh: Чтобы развернуть, git-diff пытается создать различия, которые можно фактически использовать в качестве исправлений для исходных файлов, что невозможно без этой информации. Единственный способ удалить его - это обработать его самостоятельно, например, через git diff | egrep "^(\+|-) ".
Крис Хэйс
1
git config --global diff.context 0 чтобы установить его глобально
Анджей Реманн
Если вы хотите увидеть в конкретном каталоге, попробуйте git diff -U0 <dir>
Eswar Yaganti
42

Еще один прием (на un * x), чтобы показать только строки, начинающиеся с +и -:

git diff -U0 | grep '^[+-]' | grep -Ev '^(--- a/|\+\+\+ b/)'

Приведенный выше код делает следующее:

  • git diff -U0: выберите 0 контекстных строк
  • Первый grep включает только все строки, начинающиеся с +или-
  • Второй grep исключает строки, начинающиеся с --- a/или+++ b/

цвет

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

git diff -U0 --color | grep '^\e\[[^m]*m[-+]' | grep -Ev '(--- a/|\+\+\+ b/)'
  • Выражение ,, ^\e\[[^m]*m[-+]ищет начало строки ( ^), затем escape characer ( \e), за [которым вместе начинается escape-последовательность, затем любой символ, не являющийся "m" (числа, точки с запятой или ничего), за которым следует " m ", который завершает escape-последовательность.
  • Обратите внимание, что все следующие допустимые escape-последовательности: \e[0m(сброс), \e[m(также сброс), \e[1m(жирный шрифт), \e[31m(красный), \e[32m(зеленый), \e[9;31m(зачеркнутый + красный), \e[31;9m(красный + зачеркнутый), \e[1;4;9;31m(жирный + подчеркнутый + зачеркнутый + красный). В цветах git по умолчанию используются красный и зеленый, но их можно изменить.
  • --colorтакое же, как --color=always.
  • Ограничение на --- a/или +++ b/появление в начале строки было снято, чтобы учесть escape-последовательности, и это могло привести к краевому случаю.

Дополнительные замечания:

  • Выше решение должно быть изменено , если использовать дополнительные опции мерзавец Diff , такие как -R, --src-prefix, --dst-prefix, --no-prefixи т.д.
  • Два grep можно объединить в один grep -E -v '^(\+\+\+ b/|--- a/|@@ |diff --git|index )', но мне легче понять версию с двойным grep.
user650654
источник
2
Хороший. Проголосуйте за четкое объяснение каждого фильтра.
henrebotha
Я вижу много git diffстрок типа «заголовок», которые начинаются с символа @@, но какие git diffстроки начинаются с ---или +++? Я не знал об этих.
Габриэль Стейплс
Да ладно. Они обозначают имена файлов, которые содержат добавления ( +++) или удаления ( ---). Теперь я вижу это здесь: git-scm.com/docs/git-diff#_combined_diff_format .
Габриэль Стейплс
Еще раз исправление: --- a/filenameпохоже, обозначает «файл слева» или файл, как было раньше, и, +++ b/filenameкажется, обозначает «файл справа», или файл, как сейчас, с вашими изменениями. Я так привык использовать git difftoolс meld , который показывает красивые параллельные сравнения, что я никогда не привык смотреть на это git diff, поэтому мне это все еще кажется странным, и я никогда раньше не обращал внимания на эти нюансы.
Габриэль Стейплс
1
@GabrielStaples, добавлена ​​поддержка цвета. Спасибо.
user650654
6

Следуя последнему комментарию Криса, основная проблема с постобработкой заключается в том, что вы хотите сохранить строки, начинающиеся с, -|+но вы также хотите отфильтровать те, которые начинаются с ---|+++. С другой стороны, если вы храните файлы патчей в своем репо (я храню в Pydoop ), вы хотите сохранить строки, начинающиеся с --|++, поэтому регулярное выражение становится немного сложным:

git diff | grep -P '^\+(?:(?!\+\+))|^-(?:(?!--))'

Регулярное выражение использует отрицательный просмотр вперед: подробное объяснение см. В ответе Питера Боутона на этот вопрос .

Если вы делаете это часто, вы можете настроить для него псевдоним git:

git config --global alias.diffonly '!git diff | grep -P "^\+(?:(?!\+\+))|^-(?:(?!--))"'
simleo
источник
1
это не сработало для меня в Windows git bash. Не знаю, почему (grep сказал недопустимый вариант P), в данный момент у меня нет наглости, чтобы разобраться в этом.
Деннис
1
-Pили --perl-regexpиспользуется для интерпретации шаблона как регулярного повторного выражения Perl, но не всегда реализуется. У меня это не сработало на OSX. gnu.org/software/grep/manual/grep.html#grep-Programs
Виллингтон Вега,
5

Я думаю, что для простых случаев регулярное выражение может быть намного короче и его легче запомнить, с оговоркой, что это не сработает, если у вас есть изменения строки, где сама строка начинается с +или-

$ git diff | grep '^[+|-][^+|-]'

Регулярное выражение говорит, что строка должна начинаться с +или -, а следующий за ним символ не должен быть ни одним из них. Я получил те же результаты вне зависимости от того, сбежал я здесь +или нет, кстати ...


Пример:

$ cat testfile
A
B
C
D
E
F
G

Скажем, я перехожу Cна X, Eна Yи Gна Z.

$ git diff | grep '^[+|-][^+|-]'
-C
+X
-E
+Y
-G
+Z

Однако, как я сказал выше, это только для большинства случаев. Если вы отправите этот вывод в файл dout, а затем попробуйте то же регулярное выражение, это не сработает.

$ git diff dout | grep '^[+|-][^+|-]'
$

В любом случае, надеюсь, что это поможет в вашем случае

Галуа
источник
В случаях, когда строка начинается с «-», это не сработает. Пример: - name: No pdbв файле yaml.
anapaulagomes
3

В этом ответе для удобства чтения сохранятся исходные красный / зеленый цвета. Я предоставил несколько вариантов синтаксиса:

git diff --color | grep --color=never $'^\e\[3[12]m'
git diff --color | grep --color=never $'^\033\[3[12]m'
git diff --color | grep --color=never -P '^\e\[3[12]m'
git diff --color | grep --color=never -P '^\033\[3[12]m'

Объяснение:

  • Это git diff --colorнеобходимо, чтобы git не отключал цвет, когда он работает.
  • Это grep --color=neverпредотвращает удаление исходным цветом и выделение совпадающей строки с помощью grep.
  • Мы подбираем строки, которые начинаются с escape-кодов red ( \e[31m) или green ( \e[32m).
  • $'...'(ANSI-C , со ссылкой на синтаксис) или -P(Perl синтаксис) должен позволить , grepчтобы интерпретировать \eили в \033качестве ESCсимвола.
wisbucky
источник
Спасибо за это. Вот альтернативная форма, которую я только что придумал. Ваша $''часть мне особенно помогла. stackoverflow.com/a/61929887/4561887
Габриэль Скобы,
1

Как использовать , awkчтобы показать только те , +и -линию, учет любого цвета или форматирование текста git diffможет быть вывод:

Ни один из других ответов здесь (включая мой другой ответ ) не сделает именно то, что вы хотите, на 100% правильно. Этот ответ, однако, будет. Вот однострочный файл, который вы можете скопировать и вставить в свой терминал. Я только что сделал его несколькими строками для удобства чтения - вы можете скопировать и вставить его одинаково, так что я могу сделать его читабельным! Он полагается на awkязык программирования:

git diff --color=always "$@" | awk '
# 1. Match and then skip "--- a/" and "+++ b/" lines
/^(\033\[(([0-9]{1,2};?){1,10})m)?(--- a\/|\+\+\+ b\/)/ {
    next 
} 
# 2. Now print the remaining "+" and "-" lines ONLY! Note: doing step 1 above first was required or
# else those lines would have been matched by this matcher below too since they also begin with 
# the "+" and "-" symbols.
/^(\033\[(([0-9]{1,2};?){1,10})m)?[-+]/ {
    print $0 
}
' | less -RFX

Вот его особенности. Все эти функции, взятые вместе, решают недостатки любого другого ответа здесь:

  1. Он обрабатывает цветной И бесцветный вывод. Вот что делает это регулярное выражение:^(\033\[(([0-9]{1,2};?){1,10})m)?
  2. Он обрабатывает ВСЕ ЦВЕТА и ВСЕ ОПЦИИ ФОРМАТИРОВАНИЯ ТЕКСТА, включая полужирный шрифт, курсив, зачеркивание и т. Д., Которые вы можете установить в своих git configнастройках . Вот почему в приведенном выше регулярном выражении есть ;?и {1,10}: если оно обнаруживает начало кода форматирования цвета или текста, оно сопоставляет до 10 последовательностей этих комбинированных кодов ANSI.
  3. Он также НЕ включает строки, которые начинаются с @@и слова diff, как принятый ответ . Если вам действительно нужны эти строки (которые, откровенно говоря, я считаю полезными :)), сделайте вместо этого:

    git diff --unified=0
    

    или

    git diff -U0
    
  4. Вывод выводится точно так же, как git diffи в lessпейджере с дополнительным выводом цвета ( -R), и только если текст> 1 страницы ( -F), и при сохранении текущей страницы текста на экране при использовании quit ( -X) ,

Он также имеет то преимущество, что он мощный и легко настраиваемый, поскольку он использует язык программирования awk.

Если вы заинтересованы в изучении awk , вот несколько ресурсов:

  1. gawk(GNU awk) руководство: https://www.gnu.org/software/gawk/manual/html_node/index.html#SEC_Contents
  2. Исследование git diffnи комментарии к нему: https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles/blob/master/useful_scripts/git-diffn.sh
    1. Если вы git diffnтоже хотите , то есть git diffс номерами строк, см. Здесь: Git diff с номерами строк (журнал Git с номерами строк)
  3. Некоторые примеры тестов awk "hello world" и синтаксиса: https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/tree/master/awk

В качестве бонуса я также завернул приведенное выше, чтобы использовать его как git diffc, что означает «git diff для отображения ТОЛЬКО 'c'hanges'». Использование является идентичным с git diff; просто используйте git diffcвместо этого! Он поддерживает ВСЕ параметры. Цвет по умолчанию включен. Чтобы выключить его, просто используйте git diffc --no-colorили git diffc --color=never. Подробнее man git diffсм.

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

Установить git diffc:

Следуйте инструкциям в конце этого ответа здесь , за исключением того, что вы видите git-diffnв инструкциях, используйте git-diffcвместо этого. Это wgetтоже входит в команду. Скачать и установить git diffcочень просто: это всего несколько команд.

Габриэль Скобы
источник
0

Вот еще один, более простой способ найти только строки, которые были изменены и, следовательно, начинаются с одного +или -, сохраняя при этом цветной вывод:

git diff -U0 --color=always HEAD~ | grep --color=never -E $'^\e\[(32m\+|31m-)'
  1. Он -U0говорит, что нужно включить 0 строк контекста вокруг измененных строк, то есть: включить только сами измененные строки. Смотрите man git diff.
  2. Команда -Efor grep позволяет ему работать с расширенными регулярными выражениями
  3. $''Синтаксис , по- видимому позволяет ANSI квотирование, который правильно интерпретирует ESC (побег, или 0x1B) символов правильно. Смотрите здесь .
  4. А вот описание регулярного выражения с https://www.regex101.com :введите описание изображения здесь
  5. По сути, ^соответствует началу строки, \eсоответствует символу Escape, который является началом цветового кода в терминале, \[соответствует следующему символу в цветовом коде, который равен [, а затем (this|that)синтаксис соответствует «этому» или «тому» , где "это" - 32m+это зеленая + линия, а 31m-красная -.
  6. Цвета такие: \e[32mзеленый и \e[31mкрасный.
  7. +показывает строки, помеченные git diffкак добавленные, конечно, и -показывает строки, отмеченные git diffкак удаленные.
  8. Обратите внимание, что --color=neverэто требуется во втором grepвыражении, чтобы оно не выделяло свои совпадения, что в противном случае могло бы испортить цветовые коды, поступающие git diffслева.
  9. Также +необходимо экранировать, \+потому что в противном случае +это специальный символ регулярного выражения (регулярного выражения), который определяет одно или несколько вхождений предыдущего элемента . См. Здесь: https://en.wikipedia.org/wiki/Regular_expression#Basic_concepts .

Ссылки:

  1. https://git-scm.com/docs/git-diff#_combined_diff_format
  2. Ответ @ user650654: Git diff для отображения только строк, которые были изменены
  3. Ответ @wisbucky: Git diff для отображения только строк, которые были изменены

Связанный:

  1. [мой собственный ответ] Git diff с номерами строк (Git log с номерами строк)
  2. [чужой ответ] Git diff с номерами строк (Git log с номерами строк)
  3. git diff с номерами строк и правильным выравниванием / отступом кода
  4. git-filechange-search.sh- сценарий, который позволяет вам искать в файле имя переменной или функции и выяснять, какие коммиты содержат изменения с этой переменной или именем функции. Ex. Использование: ./git-filechange-search.sh path/to/my/file.cpp variable_nameнайдет все коммиты с изменениями в file.cpp, которые variable_nameв них содержатся . Это полезно, чтобы увидеть, где и когда были изменены определенные функции. Это как если бы это был поиск, который мог наблюдать разделы файла, отображаемые с git blameтечением времени.
Габриэль Скобы
источник