web-dev-qa-db-fra.com

Git - Comment afficher 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 particulier est énorme et je ne suis vraiment intéressé que par les modifications d'une méthode particulière. Serait-il donc possible de voir l'historique des changements pour cette méthode en particulier?

Je sais que cela nécessiterait git pour analyser le code et que l'analyse serait différente pour différents langages, mais les déclarations de méthode/fonction semblent très similaires dans la plupart des langages, donc j'ai pensé que peut-être 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 je serais intéressé de savoir si cette fonctionnalité existe pour n'importe quel SCM/langage.

76
Erik B

Versions récentes de git log a appris une forme spéciale de -L paramètre:

- L: <funcname>: <file>

Suivez l'évolution de la gamme de lignes donnée par "<start>,<end>" (ou le nom de fonction regex <funcname>) dans le <file>. Vous ne pouvez pas donner de limiteurs pathspec. Ceci est actuellement limité à une marche à partir d'une seule révision, c'est-à-dire que vous ne pouvez donner que zéro ou un argument de révision positif. Vous pouvez spécifier cette option plusieurs fois.
...
Si “:<funcname>” est donné à la place de <start> et <end>, c'est une expression régulière qui désigne la plage de la première ligne de nom de fonction qui correspond à <funcname>, jusqu'à la prochaine ligne de nom de fonction. “:<funcname>” recherche depuis la fin de la précédente -L plage, le cas échéant, sinon depuis le début du fichier. “^:<funcname>” 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 avec bonheur l'historique des modifications de cette fonction.

71
eckes

En utilisant git gui blame est difficile à utiliser dans les scripts, et tandis que git log -G et git log --pickaxe peut chacun vous montrer quand la définition de la méthode est apparue ou a disparu, je n'ai trouvé aucun moyen de leur faire lister toutes les modifications apportées à le corps de votre méthode.

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

La clé est d'avoir Git supprimer du fichier toutes les lignes sauf celles qui vous intéressent avant de faire des opérations de diff. Alors git log, git diff, etc. ne verra que la zone qui vous intéresse.

Voici les grandes lignes de ce que je fais dans une autre langue; vous pouvez l'ajuster pour vos propres besoins.

  • Écrivez un court script Shell (ou un autre programme) qui prend un argument - le nom d'un fichier source - et ne produit que la partie intéressante de ce fichier (ou rien si rien n'est intéressant). Par exemple, vous pouvez utiliser sed comme suit:

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

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

    $ echo "my_file diff=my_filter" >> .gitattributes
    
  • Maintenant, si vous utilisez -G. (noter la .) pour répertorier toutes les validations qui produisent des modifications visibles lorsque votre filtre est appliqué, vous aurez exactement les validations qui vous intéressent. Toutes les autres options qui utilisent les routines diff de Git, telles que --patch, obtiendra également cette vue restreinte.

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

Une amélioration utile que vous pourriez souhaiter apporter est que votre script de filtrage prenne un nom de méthode comme premier argument (et le fichier comme deuxième). Cela vous permet de spécifier une nouvelle méthode d'intérêt simplement en appelant git config, plutôt que de devoir 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 autre: il y a beaucoup de flexibilité au-delà de ce que j'ai montré ici.

15
Paul Whittaker

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

-G Rechercher les différences dont la ligne ajoutée ou supprimée correspond au <regex>.

Donnez-lui simplement une expression correcte 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
10
lht

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

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

Cela ouvrira moins (ou un téléavertisseur équivalent). Vous pouvez maintenant taper /i_am_buggy (ou votre équivalent de téléavertisseur) et commencez à suivre les modifications.

Cela pourrait 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 expression régulière (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 que avec des expressions rationnelles soit une proposition différente.

9
badp

La bonne façon est d'utiliser git log -L :function:path/to/file comme expliqué dans réponse eckes .

Mais en plus, si votre fonction est très longue, vous voudrez peut-être voir uniquement les changements que divers commit ont introduits, pas toutes les lignes de fonction, y compris non modifiées, pour chaque commit qui peut ne toucher qu'une seule de ces lignes. Comme un diff normal.

Normalement git log peut afficher les différences avec -p, mais cela ne fonctionne pas avec -L. Vous devez donc grepgit log -L pour afficher uniquement les lignes impliquées et les en-têtes commit/files pour les contextualiser. L'astuce consiste à ne faire correspondre que les lignes colorées des terminaux, en ajoutant --color interrupteur, avec une expression régulière. Finalement:

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

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

Dernière -3 switch, permet d'imprimer 3 lignes de contexte de sortie, avant et après chaque ligne correspondante. Vous voudrez peut-être l'adapter à vos besoins.

3
Hazzard17

git blame vous montre qui a modifié en dernier 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.

2
Will