Comment trouver le commit git le plus récent qui a modifié un fichier?

193

Je veux trouver le commit le plus récent qui a modifié un fichier source.

Je peux utiliser git blamepour voir toutes les dates de commits par ligne, mais il est difficile de voir exactement quel commit a été le dernier à toucher le fichier.

Comment puis-je trouver le dernier commit qui a touché un fichier donné dans mon dépôt git?

Cory Klein
la source

Réponses:

244

git log prend en charge la recherche de l'historique de fichiers (et de répertoires) spécifiques, vous pouvez donc l'appeler comme ceci:

git log my/file.c

Si vous voulez vraiment que la liste l' un dernier commettras, par exemple pour l' utiliser dans un script, utilisez l' -n 1option de :

git log -n 1 --pretty=format:%H -- my/file.c

--pretty=format:%hdit git logde n'afficher que le hachage de validation. Le --séparateur empêche le nom de fichier d'être interprété comme un nom de validation, juste au cas où il serait ambigu.

Jo Liss
la source
12
Si vous voulez savoir la dernière fois qu'un fichier a été modifié, quelle que soit la branche, vous pouvez considérer toutes les branches en ajoutant l' --alloption.
KC
46

Si vous voulez juste trouver le commit le plus récent, alors vous ne voulez pas git-log, vous voulez git-rev-list, qui répertorie les objets de commit modifiant ce fichier, dans ce chemin de commit, en commençant par le plus récent (chronologiquement). Tout simplement:

git rev-list -1 <commit> <filename>

Car git-rev-listdans votre cas, il vous suffit de fournir:

  • Le nombre de commits à inclure, ou -1 pour le plus récent,
  • La branche (ou l'identifiant de validation) à partir de laquelle commencer à regarder en arrière, HEAD si vous y êtes déjà, ou --all si vous voulez tous les validations connues, et
  • Le chemin relatif de votre fichier.

Cela renvoie simplement l'ID de validation le plus récent dans la branche actuelle pour modifier ce fichier, ex: 215095e2e338525be0baeeebdf66bfbb304e7270

Pour un exemple plus complexe, vous pouvez utiliser des noms de balises, et même des références distantes, et inclure des noms de chemins relatifs avec des caractères génériques, par exemple:

git rev-list origin/user/bob/testbranch -1 src/bfiles/*.txt

... Ce qui vous dirait quel a été le changement le plus récent de la correspondance générique dans l'histoire de cette branche. Les options pour la liste des rév.sont extrêmes, c'est l'une des commandes de plomberie les plus importantes, vous pouvez donc inclure ou exclure selon à peu près tous les critères que vous pouvez imaginer.

Bien sûr, reportez-vous à la page de manuel de git-rev-list (1) .

Michael Erickson
la source
Vous n'avez vraiment pas expliqué pourquoi l'utilisation git-logest inférieure.
Piotr Dobrogost le
7
Je ne dirais pas inférieur, juste qu'il fournit des informations superflues par défaut. git-rev-list renvoie simplement l'ID de validation, ce que vous voulez si vous voulez alimenter la réponse dans un script ou un autre processus d'automatisation. git-log renvoie des informations sur les commits sélectionnés, d'abord en utilisant git-rev-list pour collecter les identifiants de commit, puis en collectant des informations sur chaque commit. Si vous voulez simplement filtrer les informations de commit et utiliser les identifiants, vous pouvez simplement utiliser git-rev-list en premier lieu. Étant donné que le journal est basé sur la liste des rév, il prend la plupart des mêmes paramètres de filtre.
Michael Erickson
3
git-logest de la porcelaine, git-rev-listest la plomberie.
blitzen9872
27

Si vous souhaitez simplement obtenir le hachage du dernier commit pour modifier un ensemble spécifique de fichiers (et que vous voulez éviter awk), vous pouvez utiliser:

git log -n 1 --pretty=format:%h -- <path>

Cela peut être utile pour obtenir le hachage de validation pour une utilisation ultérieure avec git describe.

Par exemple (au cas où cela serait utile pour n'importe qui)…

Je crée un identifiant de version actuelle en considérant le dernier commit pour changer n'importe quel fichier source (en supposant que vous marquez les versions avec des balises comme mycode-1.2.1):

COMMIT=$(git log -n 1 --pretty=format:%h -- *.c *.h)
if VN=$(git describe --always --abbrev=5 --match "mycode-*" $COMMIT 2>/dev/null) &&
case "$VN" in
mycode-*)
    git update-index -q --refresh
    test -z "$(git diff-index --name-only HEAD *.c *.h)" ||
    VN="$VN-mod" ;;
*) VN="mycode-unknown-g$VN" ;;
esac
then
    continue
else
VN="mycode-unknown"
fi

Cela produit des identifiants comme:

  • mycode-1.2.1 - lorsque l'état actuel des fichiers source correspond à une version balisée
  • mycode-1.2.1-g3k7s2 - lorsque l'état actuel des fichiers source correspond à un commit suivant une version balisée
  • mycode-1.2.1-g3k7s2-mod - lorsque l'état actuel des fichiers sources a été modifié depuis le dernier commit suite à une version taguée
  • mycode-unknown - lorsqu'il n'y a pas encore eu de balise de version créée
TheBamf
la source
5
$VNressemble à une sorte de cauchemar de morts-vivants SVN
ThorSummoner
10

Je ne sais pas si c'est ce que vous voulez, mais si vous faites un git log <thefile>pour obtenir les commits qui ont modifié ce fichier. Vous pouvez choisir le plus haut. Ce devrait être celui que vous recherchez.

Noufal Ibrahim
la source
4
si vous utilisez git log -n1 -- <thefile>(ou dirigez la sortie vers head -1si vous voulez gaspiller des ressources), vous n'avez pas à choisir manuellement la ligne du haut (voir la réponse de Jo Liss )
Tobias Kienzler
4
Bon point. Je pense que vous pouvez également ignorer -net utiliser -1directement.
Noufal Ibrahim
3

Pour obtenir uniquement la référence sur une ligne, essayez:

git log -n1 --oneline <path> | awk '{print $1;}'
multiplication rapide
la source
2

Une fois que vous avez l'ID SHA du commit que vous souhaitez utiliser git log FILENAME, vous devriez pouvoir faire git show SHA_ID_HEREpour voir ce que vous avez fait pour ce commit particulier. Vous n'avez même pas besoin de saisir l'ID complet; les 6 premiers caractères devraient suffire.

Joe
la source
4
c'est un peu plus que ce que l'OP demandait, mais pour info, vous pouvez combiner cela en une seule ligne:git show $(git log -1 --pretty="%H" -- FILENAME)
Tobias Kienzler