Afficher uniquement les morceaux pertinents d'un diff / patch basé sur une expression rationnelle


20

git log -G<regex> -pest un merveilleux outil pour rechercher dans l'historique d'une base de code les modifications qui correspondent au modèle spécifié. Cependant, il peut être écrasant de localiser le morceau approprié dans la sortie diff / patch dans une mer de mecs pour la plupart non pertinents.

Il est bien sûr possible de rechercher la sortie de git logla chaîne / expression originale, mais cela ne fait pas grand-chose pour réduire le bruit visuel et la distraction de nombreux changements non liés.

En lisant la suite git log, je vois qu'il y a le --pickaxe-all, qui est l'exact opposé de ce que je veux: il élargit la sortie (à l'ensemble des modifications), alors que je veux le limiter (au morceau spécifique).

Essentiellement, je cherche un moyen d'analyser "intelligemment" le diff / patch en morceaux individuels, puis d'exécuter une recherche sur chaque morceau (en ciblant uniquement les lignes modifiées), de supprimer les morceaux qui ne correspondent pas et de sortir ceux qui font.

Existe-t-il un outil tel que je le décris? Existe-t-il une meilleure approche pour obtenir les mecs correspondants / affectés?

Quelques recherches initiales que j'ai faites ...

  • S'il était possible de faire grepla sortie diff / patch et de rendre les valeurs des options de contexte dynamiques - disons, via des regexps au lieu du nombre de lignes - cela pourrait suffire. Mais grepn'est pas exactement construit de cette façon (et je ne demande pas nécessairement cette fonctionnalité).

  • J'ai trouvé la suite de patchutils , qui semblait initialement convenir à mes besoins. Mais après avoir lu ses manpages, les outils ne semblent pas gérer les mecs correspondants basés sur des expressions régulières. (Ils peuvent accepter une liste de mecs, cependant ...)

  • J'ai finalement rencontré splitpatch.rb , qui semble bien gérer l'analyse du correctif, mais il devrait être considérablement augmenté pour gérer la lecture des correctifs via stdin, faire correspondre les morceaux souhaités, puis produire les morceaux.


1
Pas exactement ce que vous avez demandé mais essayez git log -Gfoo | moins + / foo
James Youngman

Réponses:


7

ici /programming//a/35434714/5305907 est décrit un moyen de faire ce que vous cherchez. effectivement:

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

Il montre uniquement les mecs qui correspondent à la chaîne "console" donnée.


Merci. grepdiffest fondamentalement ce que je veux; j'ai dû manquer son option de correspondance de morceau! cependant ... les informations de commit git sont supprimées grepdiff, donc une fois que vous avez localisé le morceau approprié, vous devez deviner le commit sha de l'objet / blob sha dans l'en-tête diff - une opération assez coûteuse. (voir stackoverflow.com/a/223890/2284440 ) ce serait quelque chose commegit find-object SHA --reverse | head -1 | cut -c 1-7 | { read sha ; git log -1 $sha; }
wrksprfct

notez également qu'il existe une version golanggrepdiff qui est plus simple en termes d'arguments acceptés. notez que lorsque le morceau correspondant est le dernier morceau d'un diff, il inclut incorrectement l'en-tête git commit du commit suivant - quelque chose qui m'a complètement dérouté jusqu'à ce que je réalise ce qui se passe!
wrksprfct

0

Pas exactement ce que vous demandez, mais le mode d'ajout interactif est une façon de parcourir les mecs. Cela vous oblige à vérifier le commit après le patch qui vous intéresse

git checkout COMMIT_ID

puis revenir une étape de plus dans le VCS, mais pas dans le répertoire de travail

git reset --soft HEAD^

(À ce stade, la différence entre l'index et le répertoire de travail correspondra au patch qui vous intéresse.)

Vous pouvez maintenant exécuter git add -p. Cela lancera une session interactive qui a une /option, qui vous permet de localiser des morceaux dans lesquels une ligne correspond à une expression régulière. Particulièrement utile si vous souhaitez réellement traiter ces correctifs (par exemple, préparer une sélection partielle).

Malheureusement, au moins en ce moment, la /commande add -pne fonctionne que dans un seul fichier, vous devrez donc peut-être ignorer plusieurs fichiers non pertinents.


0

Sur la base de la réponse ci-dessus de @nagu et des autres réponses liées, j'ai pu git log -Gafficher uniquement les mecs pertinents.

  1. Créez d'abord un script quelque part dans votre $ PATH avec ce contenu:

    #!/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. Appelez git log -Get dites à Git d'utiliser le pickaxe-diffscript comme pilote de diff externe:

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

    Cela utilisera le script pickaxe-diff juste pour générer les différences, donc le reste de la git logsortie (hachage de validation, message, etc.) ne sera pas modifié.

Avertissement
La façon dont fonctionne la pioche Git est qu'elle limite la sortie aux fichiers dont les mecs modifient la chaîne / l'expression régulière donnée. Cela signifie que si un autre morceau de ces fichiers contient également la chaîne de recherche / l'expression régulière, mais ne la modifie pas, elle sera toujours affichée avec le script ci-dessus. Il s'agit d'une limitation de grepdiff. Il y a une demande d'ouverture ouverte au projet --only-matchingpatchutils pour ajouter un indicateur à grepdiff, qui fournirait les fonctionnalités nécessaires pour filtrer correctement ces morceaux.


J'ai fait une récapitulation de ma solution dans cet essentiel .

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.