Git – Comment visualiser l’historique des modifications d’une méthode / fonction?

J’ai donc trouvé la question de savoir comment afficher l’historique des modifications d’un fichier, mais l’historique des modifications de ce fichier est énorme et je ne suis vraiment intéressé que par les modifications d’une méthode particulière. Serait-il possible de voir l’historique des changements pour cette méthode particulière?

Je sais que cela nécessiterait que git parsing le code et que l’parsing soit différente pour différentes langues, mais les déclarations de méthode / fonction sont très similaires dans la plupart des langues, alors j’ai pensé que quelqu’un avait implémenté cette fonctionnalité.

Le langage avec lequel je travaille actuellement est Objective-C et le SCM que j’utilise actuellement est git, mais cela m’intéresserait de savoir si cette fonctionnalité existe pour tout SCM / langage.

Les versions récentes de git log appris une forme spéciale du paramètre -L :

-L: :

Trace l’évolution de la plage de lignes donnée par "," (ou le nom de la fonction regex ) dans le . Vous ne pouvez pas donner de limiteurs pathspec. Ceci est actuellement limité à une promenade à partir d’une seule révision, c’est-à-dire que vous ne pouvez donner que des arguments de révision positifs ou nuls. Vous pouvez spécifier cette option plus d’une fois.

Si “: est donné à la place de et , c’est une expression régulière qui indique la plage de la première ligne funcname qui correspond à , jusqu’à la ligne funcname suivante. “: recherche à partir de la fin de la plage précédente, le cas échéant, sinon depuis le début du fichier. “^: recherche depuis le début du fichier.

En d’autres termes: si vous demandez à Git de git log -L :myfunction:path/to/myfile.c , il affichera maintenant l’historique des modifications de cette fonction.

Utiliser git gui blame est difficile à utiliser dans les scripts, et bien que git log -G et git log --pickaxe puissent chacun vous montrer quand la définition de la méthode est apparue ou a disparu, je n’ai trouvé aucun moyen de les lister faite au corps de votre méthode.

Cependant, vous pouvez utiliser gitatsortingbutes et la propriété textconv pour textconv une solution qui ne fait que cela. Bien que ces fonctionnalités aient été initialement conçues pour vous aider à travailler avec des fichiers binarys, elles fonctionnent tout aussi bien ici.

La clé est de faire en sorte que Git supprime du fichier toutes les lignes à l’exception de celles qui vous intéressent avant d’effectuer des opérations de diff. Ensuite, git log , git diff , etc. ne verront que la zone qui vous intéresse.

Voici les grandes lignes de ce que je fais dans une autre langue. vous pouvez le modifier pour vos propres besoins.

  • Ecrivez un court script shell (ou un autre programme) qui prend un argument – le nom d’un fichier source – et affiche uniquement la partie intéressante de ce fichier (ou rien s’il n’est pas intéressant). Par exemple, vous pouvez utiliser sed comme suit:

     #!/bin/sh sed -n -e '/^int my_func(/,/^}/ p' "$1" 
  • Définissez un filtre textconv Git pour votre nouveau script. (Voir la page de manuel gitatsortingbutes pour plus de détails.) Le nom du filtre et l’emplacement de la commande peuvent être tout ce que vous voulez.

     $ git config diff.my_filter.textconv /path/to/my_script 
  • Dites à Git d’utiliser ce filtre avant de calculer les diffs pour le fichier en question.

     $ echo "my_file diff=my_filter" >> .gitatsortingbutes 
  • Maintenant, si vous utilisez -G. (notez le . ) pour lister tous les commits qui produisent des changements visibles lorsque votre filtre est appliqué, vous aurez exactement les commits qui vous intéressent. Toutes les autres options utilisant les routines diff de Git, telles que --patch , seront également Obtenez cette vue restreinte.

     $ git log -G. --patch my_file 
  • Voilà!

Une amélioration utile que vous voudrez peut-être apporter est que votre script de filtre prenne un nom de méthode comme premier argument (et le fichier comme second). Cela vous permet de spécifier une nouvelle méthode en appelant simplement git config , plutôt que de modifier votre script. Par exemple, vous pourriez dire:

 $ git config diff.my_filter.textconv "/path/to/my_command other_func" 

Bien sûr, le script de filtrage peut faire ce que vous voulez, prendre plus d’arguments, ou peu importe: il ya beaucoup de flexibilité au-delà de ce que j’ai montré ici.

La chose la plus proche que vous puissiez faire est de déterminer la position de votre fonction dans le fichier (par exemple, dites que votre fonction i_am_buggy trouve aux lignes 241-263 de foo/bar.c ), puis exécutez quelque chose ayant pour effet:

 git log -p -L 200,300:foo/bar.c 

Cela ouvrira moins (ou un téléavertisseur équivalent). Maintenant, vous pouvez saisir /i_am_buggy (ou votre équivalent de pageur) et commencer à parcourir les modifications.

Cela peut même fonctionner, selon votre style de code:

 git log -p -L /int i_am_buggy\(/,+30:foo/bar.c 

Cela limite la recherche du premier hit de cette regex (idéalement votre déclaration de fonction) à trente lignes après cela. L’argument de fin peut également être une expression rationnelle, bien que détecter cela avec des expressions rationnelles soit une proposition différente.

git log a une option ‘-G’ pourrait être utilisée pour trouver toutes les différences.

-G Rechercher les différences dont la ligne ajoutée ou supprimée correspond à la donnée.

Donnez-lui juste une expression rationnelle du nom de la fonction qui vous intéresse. Par exemple,

 $ git log --oneline -G'^int commit_tree' 40d52ff make commit_tree a library function 81b50f3 Move 'builtin-*' into a 'builtin/' subdirectory 7b9c0a6 git-commit-tree: make it usable from other builtins 

git blame vous indique qui a changé la dernière fois chaque ligne du fichier; vous pouvez spécifier les lignes à examiner afin d’éviter d’avoir l’historique des lignes en dehors de votre fonction.

La manière correcte consiste à utiliser git log -L :function:path/to/file comme expliqué dans eckes answer .

Mais en plus, si votre fonction est très longue, vous voudrez peut-être voir uniquement les modifications introduites par divers commit, pas toutes les lignes de fonction, non modifiées, pour chaque validation qui ne touche peut-être qu’une de ces lignes. Comme un diff normal.

Normalement, git log peut afficher les différences avec -p , mais cela ne fonctionne pas avec -L . Donc, vous devez grep git log -L pour afficher uniquement les lignes impliquées et commettre / en-tête de fichiers pour les contextualiser. L’astuce consiste ici à ne faire correspondre que les lignes de couleur terminale, en ajoutant l’option --color switch, avec une regex. Finalement:

 git log -L :function:path/to/file --color | grep --color=never -E -e "^(^[\[[0-9;]*[a-zA-Z])+" -3 

Notez que ^[ devrait être réel, littéral ^[ . Vous pouvez les taper en appuyant sur ^ V ^ [en bash, c’est-à-dire Ctrl + V , Ctrl + [ . Référence ici .

Aussi dernier commutateur -3 , permet d’imprimer 3 lignes de contexte de sortie, avant et après chaque ligne correspondante. Vous voudrez peut-être l’ajuster à vos besoins.