Exibir apenas blocos relevantes de um diff / patch com base em uma regexp

20

git log -G<regex> -pé uma ferramenta maravilhosa para pesquisar no histórico de uma base de código alterações que correspondam ao padrão especificado. No entanto, pode ser esmagador localizar o pedaço relevante na saída do diff / patch em um mar de pedaços principalmente irrelevantes.

É claro que é possível pesquisar a saída da git logstring / regex original, mas isso faz pouco para reduzir o ruído visual e a distração de muitas alterações não relacionadas.

Continuando lendo git log, vejo --pickaxe-allque há exatamente o oposto do que eu quero: ele amplia a saída (para todo o conjunto de alterações), enquanto eu quero limitá-lo (para o pedaço específico).

Essencialmente, estou procurando uma maneira de "inteligentemente" analisar o diff / patch em pedaços individuais e, em seguida, executar uma pesquisa em cada pedaço (visando apenas as linhas alteradas), descartar os pedaços que não coincidem e produzir os mesmos isso faz.

Existe uma ferramenta como eu descrevo? Existe uma abordagem melhor para obter os pedaços correspondentes / afetados?

Algumas pesquisas iniciais que fiz ...

  • Se fosse possível obter grepa saída diff / patch e tornar dinâmicos os valores das opções de contexto - digamos, através de regexps em vez de contagens de linha -, isso seria suficiente. Mas grepnão é exatamente construído dessa maneira (nem estou necessariamente solicitando esse recurso).

  • Encontrei a suíte patchutils , que inicialmente parecia ser adequada às minhas necessidades. Mas depois de ler suas manpáginas, as ferramentas não parecem lidar com pedaços correspondentes com base em regexps. (Eles podem aceitar uma lista de pedaços, no entanto ...)

  • Finalmente encontrei o splitpatch.rb , que parece lidar bem com a análise do patch, mas seria necessário aumentar significativamente para lidar com a leitura dos patches stdin, a correspondência entre os blocos desejados e a saída dos blocos.

wrksprfct
fonte
11
Não exatamente o que você pediu, mas tente o git log -Gfoo | menos + / foo
James Youngman 02/02

Respostas:

7

aqui /programming//a/35434714/5305907 é descrita uma maneira de fazer o que você está procurando. efetivamente:

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

Ele mostra apenas os blocos que correspondem à string "console" fornecida.

nagu
fonte
obrigado. grepdiffé basicamente o que eu quero; Eu devo ter perdido a opção de correspondência de pedaços! no entanto ... as informações de confirmação do git são removidas grepdiff; portanto, depois de localizar o hunk relevante, você deve adivinhar o commit sha do objeto / blob sha no cabeçalho diff - uma operação bastante cara. (veja stackoverflow.com/a/223890/2284440 ) seria algo comogit find-object SHA --reverse | head -1 | cut -c 1-7 | { read sha ; git log -1 $sha; }
wrksprfct
Observe também que há uma versão golanggrepdiff mais barebones em termos de argumentos aceitos. note que quando o pedaço correspondente é o último pedaço de uma diff, ele inclui incorretamente o cabeçalho git commit do seguinte commit - algo que me confundiu completamente até que eu percebi o que estava acontecendo!
wrksprfct
0

Não é exatamente o que você está pedindo, mas uma maneira de lidar com os pedaços é o modo de adição interativa. Isso requer que você verifique o commit após o patch em que está interessado

git checkout COMMIT_ID

então volte mais uma etapa no VCS, mas não no diretório de trabalho

git reset --soft HEAD^

(Nesse ponto, a diferença entre o índice e o diretório de trabalho corresponderá ao patch em que você está interessado.)

Agora você pode executar git add -p. Isso iniciará uma sessão interativa que tem uma /opção, que permite localizar blocos nos quais alguma linha corresponde a um regex. Particularmente útil se você realmente quiser processar esses patches (como preparar uma palheta parcial).

Infelizmente, pelo menos no momento, o /comando add -psó funciona em um único arquivo; portanto, você pode precisar pular vários arquivos não relevantes.

leftaroundabout
fonte
0

Com base na resposta acima do @nagu e nas outras respostas vinculadas, consegui git log -Gmostrar apenas os trechos relevantes.

  1. Primeiro, crie um script em algum lugar do seu $ PATH com este conteúdo:

    #!/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. Ligue git log -Ge diga ao Git para usar o pickaxe-diffscript como um driver diff externo:

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

    Isso usará o script pickaxe-diff apenas para gerar os diffs, para que o restante da git logsaída (commit hash, mensagem, etc.) permaneça intocado.

Advertência
A maneira como a picareta Git funciona é que ela limita a saída aos arquivos cujos blocos alteram a sequência / regex especificada. Isso significa que, se outro pedaço desses arquivos também contiver a cadeia de caracteres de pesquisa / regex, mas não a alterar, ele ainda será exibido com o script acima. Esta é uma limitação do grepdiff. Há uma solicitação de recebimento aberto no projeto patchutils para adicionar um --only-matchingsinalizador ao grepdiff, que forneceria a funcionalidade necessária para filtrar corretamente esses blocos.


Eu escrevi minha solução nessa essência .

philb
fonte