Questão Como ignorar linhas movidas em um diff


Atualmente estou trabalhando em uma ferramenta de geração de código fonte. Para garantir que minhas alterações não apresentem novos bugs, diff entre a saída do programa antes e depois de minhas alterações teoricamente seria uma ferramenta valiosa.

No entanto, isso acaba sendo mais difícil do que se poderia pensar, porque a ferramenta produz linhas onde a ordem não importa (como import declarações, declarações de funções,…) de uma forma ordenada semi-aleatoriamente. Por causa disso, a saída de diff está cheio de muitas mudanças que, na verdade, são apenas linhas movidas para outra posição no mesmo arquivo.

Existe uma maneira de fazer o diff ignorar esses movimentos e apenas mostrar as linhas que foram realmente adicionadas ou removidas?


7


origem


Talvez seja mais fácil alterar sua ferramenta para gerar funções e importar declarações em um pedido específico (por exemplo, lexicográfico, se possível em seu idioma)? - Daniel Beck♦
@Daniel Beck: Veja meu comentário para a resposta de Gilles abaixo. - klickverbot
Assunto antigo, mas para resumir os comentários abaixo, como seria diff ferramenta seja capaz de separar movimentos válidos de inválidos, como Ordem de instruções em código faz importa, e casos em que isso não é verdade são limitados (importações, declaração de funções e classes, etc.)? - Joël
@ Joël: A resposta é simplesmente que eu sabia que as alterações no gerador que eu tinha que testar não introduziam nenhum erro relacionado à alteração da ordem das linhas. Naturalmente, você precisa de uma ferramenta baseada em um analisador para o idioma de destino para evitar falsos positivos no caso geral (ou simplesmente um conjunto de testes abrangente para o seu gerador), mas isso deveria ser uma verificação rápida e única. para codificar a revisão. - klickverbot


Respostas:


Você poderia fazer um diff simples, armazenar o resultado em algum lugar (para evitar outro diff), percorrer as linhas em qualquer uma das versões e, em seguida, removê-las do outro lado.

Isso gerou um projeto separado para o código de trabalho. O código.


1



Não tenho certeza do que é suposto fazer exatamente, mas não parece produzir os resultados desejados. Pelo que entendi a pergunta, dos dois exemplos no código /tmp/olde /tmp/new nenhum resultado de diff seria desejado, pois há apenas linhas que foram movidas. Este código, no entanto, produz resultados. - Ilari Kajaste
Corrigido o código. - l0b0
Não testei a resposta quando terminei o processo de fusão mencionado acima há muito tempo, mas de uma olhada no código parece que ele poderia funcionar. - klickverbot


Você pode tentar classificá-los primeiro. Algo como:

sort file-a > s-file-a
sort file-b > s-file-b
diff s-file-a s-file-b

Bash (e zsh) pode fazer isso em uma linha com substituição de processo

diff <(sort file-a) <(sort file-b)

3



Isso pode ser uma opção, mas os diffs gerados não seriam muito úteis, pois eu perderia todo o número de linha e informações de contexto… - klickverbot
Mesmo que eu ainda esteja esperando por uma solução melhor, usei essa abordagem para verificar o lote de alterações em que eu estava trabalhando. - klickverbot
Eu posso prever onde isso iria perder algumas mudanças. Às vezes a ordem é importante, às vezes não. Você descarta todo o contexto. - Rich Homolka
Para um refinador de pedidos onde eu queria ter certeza de que tudo o que existia ainda existe, isso era exatamente o que eu precisava. - ntrrobng


Parece que você tem controle sobre a ferramenta. Em seguida, torne sua saída previsível: em vez de emitir declarações em uma ordem semi-aleatória, use (digamos) ordem alfabética como último recurso. Isso não só terá o benefício de remover resíduos inúteis dos diffs, mas também de tornar a saída da ferramenta mais fácil de ler e verificar para um ser humano.


0



Desculpe, mas esta resposta não me ajuda em nada - se fosse tão fácil, eu mudaria imediatamente. Além disso, estou atualmente mesclando mudanças de um projeto do qual o gerador foi originalmente bifurcado, portanto, adicionar uma mudança bastante abrangente complicaria ainda mais esse processo… - klickverbot


Se o arquivo estiver estruturado em seções, são apenas as seções que estão fora de ordem e existe uma expressão regular que você pode usar para reconhecer o cabeçalho da seção. csplit os arquivos em suas seções e, em seguida, compare as seções em pares.

Por exemplo, acabei de fazer isso em dois dumps do MySQL para compará-los depois que alguns dos nomes do banco de dados mudaram de case (e, portanto, o dump os listou em uma ordem diferente):

csplit all-07sep2015-11:19:12.sql '/Current Database/-1' '{*}'  # split the dump made before the change, creating files xx00, xx01, ...
csplit -f yy all-07sep2015-12:26:12.sql '/Current Database/-1' '{*}' # split the dump made after the change, creating files yy00, yy01, ...
fgrep 'Current Database' xx?? yy?? | perl -lne 'BEGIN{my %foo}; /(^....).*`(.*)`/ and push(@{$foo{lc($2)}}, $1); END {printf("diff -di %s %s\n", @{$_}) for values %foo}' | sh -x | less  # match the pairs and compare them with diff

0