Отображать только релевантные фрагменты diff / patch на основе регулярного выражения

20

git log -G<regex> -pзамечательный инструмент для поиска в истории кодовой базы изменений, соответствующих указанному шаблону. Тем не менее, это может быть огромным, чтобы найти соответствующий кусок в diff / patch патч в море в основном нерелевантных блоков.

Конечно, можно искать в git logисходной строке / регулярном выражении вывод , но это мало что делает для уменьшения визуального шума и отвлечения многих несвязанных изменений.

Читая дальше git log, я вижу --pickaxe-all, что есть полная противоположность того, что я хочу: он расширяет вывод (до всего набора изменений), тогда как я хочу ограничить его (до конкретного блока).

По сути, я ищу способ «интеллектуально» разбить diff / patch на отдельные фрагменты, а затем выполнить поиск по каждому блоку (нацеливаясь только на измененные строки), отбросить фрагменты, которые не совпадают, и вывести те что делать.

Существует ли такой инструмент, как я описываю? Есть ли лучший подход, чтобы получить согласованные / затронутые фрагменты?

Некоторое начальное исследование, которое я сделал ...

  • Если бы это было возможно для grepdiff / patch и сделать значения параметров контекста динамическими, скажем, с помощью регулярных выражений вместо количества строк, этого могло бы быть достаточно. Но grepне совсем так (и я не обязательно запрашиваю эту функцию).

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

  • В конце концов я наткнулся на splitpatch.rb , который, кажется, хорошо справляется с разбором патча, но его нужно значительно расширить, чтобы обрабатывать чтение патчей stdin, сопоставлять нужные фрагменты, а затем выводить фрагменты.

wrksprfct
источник
1
Не совсем то, что вы просили, но попробуйте git log -Gfoo | меньше + / foo
Джеймс Янгман

Ответы:

7

здесь /programming//a/35434714/5305907 описан способ сделать то, что вы ищете. эффективно:

git diff -U1 | grepdiff 'console' --output-matching=hunk

Он показывает только те фрагменты, которые соответствуют заданной строке "console".

NAGU
источник
Спасибо. grepdiffэто в основном то, что я хочу; Должно быть, я пропустил его вариант соответствия! однако ... информация о коммите git удаляется grepdiff, поэтому, как только вы найдете соответствующий блок, вы должны отделить коммит sha от объекта / blob sha в заголовке diff - довольно дорогая операция. (см. stackoverflow.com/a/223890/2284440 ) это было бы что-то вродеgit find-object SHA --reverse | head -1 | cut -c 1-7 | { read sha ; git log -1 $sha; }
wrksprfct
Также обратите внимание, что есть версия golang,grepdiff которая более приемлема с точки зрения принятых аргументов. обратите внимание, что когда совпавший ханк - последний ханк в diff, он неправильно включает заголовок git commit следующего коммита - что меня полностью смущало, пока я не понял, что происходит!
wrksprfct
0

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

git checkout COMMIT_ID

затем вернитесь еще на один шаг в VCS, но не в рабочий каталог

git reset --soft HEAD^

(На этом этапе разница между индексом и рабочим каталогом будет соответствовать интересующему вас патчу.)

Теперь вы можете выполнить git add -p. Это запустит интерактивный сеанс с /опцией, которая позволяет вам найти фрагменты, в которых какая-либо строка соответствует регулярному выражению. Особенно полезно, если вы действительно хотите дополнительно обработать эти патчи (например, подготовить частичную вишню).

К сожалению, по крайней мере сейчас /команда add -pработает только в одном файле, поэтому вам может потребоваться пропустить несколько ненужных файлов.

leftaroundabout
источник
0

Основываясь на приведенном выше ответе @nagu и других связанных ответах, я смог git log -Gпоказать только соответствующие фрагменты.

  1. Сначала создайте сценарий где-нибудь в вашем $ PATH с этим содержимым:

    #!/bin/bash
    
    # pickaxe-diff : external diff driver for Git.
    #                To be used with the pickaxe options (git [log|show|diff[.*] [-S|-G])
    #                to only show hunks containing the searched string/regex.
    
    path=$1
    old_file=$2
    old_hex=$3
    old_mode=$4
    new_file=$5
    new_hex=$6
    new_mode=$7
    
    filtered_diff=$(diff -u -p $old_file $new_file | \
                    grepdiff "$GREPDIFF_REGEX" --output-matching=hunk | \
                    grep -v -e '+++ ' -e '--- ')
    
    a_path="a/$path"
    b_path="b/$path"
    
    echo "diff --git $a_path $b_path"
    echo "index $old_hex..$new_hex $old_mode"
    echo "--- $a_path"
    echo "+++ $b_path"
    echo "$filtered_diff"
    
  2. Вызовите git log -Gи скажите Git использовать pickaxe-diffскрипт в качестве внешнего драйвера diff:

    export GREPDIFF_REGEX=<string>; 
    GIT_EXTERNAL_DIFF=pickaxe-diff git log -p --ext-diff -G $GREPDIFF_REGEX
    

    Это будет использовать скрипт pickaxe-diff только для генерации различий, поэтому остальная часть git logвывода (хеш коммита, сообщение и т. Д.) Останется нетронутой.

Предостережение
Способ работы кирки Git заключается в том, что она ограничивает вывод файлами, чьи фрагменты изменяют данную строку / регулярное выражение. Это означает, что если другой блок в этих файлах также содержит строку поиска / регулярное выражение, но не меняет ее, он все равно будет отображаться с помощью приведенного выше сценария. Это ограничение grepdiff. В проекте patchutils есть открытый запрос на извлечение флага для добавления --only-matchingк grepdiff, который обеспечит необходимую функциональность для правильной фильтрации этих блоков.


Я сделал описание моего решения в этой сути .

philb
источник