Comment récupérer la date de dernière modification de tous les fichiers d'un référentiel git

64

Je sais comment récupérer la date de dernière modification d'un seul fichier dans un référentiel git:

git log -1 --format="%ad" -- path/to/file

Existe-t-il un moyen simple et efficace de procéder de la même manière pour tous les fichiers présents dans le référentiel?

Eric Bréchemier
la source

Réponses:

74

Une réponse simple consisterait à parcourir chaque fichier et à afficher son heure de modification, à savoir:

git ls-tree -r --name-only HEAD | while read filename; do
  echo "$(git log -1 --format="%ad" -- $filename) $filename"
done

Cela donnera une sortie comme ceci:

Fri Dec 23 19:01:01 2011 +0000 Config
Fri Dec 23 19:01:01 2011 +0000 Makefile

Évidemment, vous pouvez contrôler ceci depuis que c'est juste un script bash à ce stade - alors n'hésitez pas à personnaliser à votre guise!

Andrew M.
la source
2
J'espérais qu'il y avait une option pour obtenir une sortie combinée dans une seule exécution du journal git, mais votre réponse est meilleure que celle que j'avais en tête avec find. Je ne connaissais pas git-ls-tree, qui présente l'avantage de ne répertorier que les fichiers stockés dans le référentiel, en ignorant le dossier .git et les fichiers ignorés. Merci.
Eric Bréchemier
Pas de problème, Eric; vous suivez le même chemin que j'ai fait - c’est-à-dire que vous faites une recherche et que vous ignorez le répertoire .git! :) Il y a peut-être quelques options utilisant les commandes de plomberie de git, mais franchement, cela fonctionne plutôt bien. Si vous pouviez trouver un moyen d'obtenir toutes les informations par fichier, cela fonctionnerait mieux - mais rappelez-vous, git fonctionne sur l'état des commits, et non sur l'état des fichiers individuels.
Andrew M.
11
Je recommande d'utiliser le --format = "% ai" si vous voulez des horodatages triables au lieu de dates lisibles par l'homme.
ThorSummoner
2
Puisque "HEAD" n'est qu'une référence, vous pouvez utiliser n'importe quelle référence, qu'il s'agisse d'une balise, d'une branche, d'un hachage de commit, etc.
Andrew M.
1
comme @ThorSummoner l'a dit, utilisez le format% ai pour la date, puis effectuez simplement un tri pour classer les résultats:git ls-tree -r --name-only HEAD | while read filename; do echo "$(git log -1 --format="%ai" -- $filename) $filename"; done | sort
John Hunt
21

Cette approche fonctionne également avec les noms de fichiers contenant des espaces:

git ls-files -z | xargs -0 -n1 -I{} -- git log -1 --format="%ai {}" {}

Exemple de sortie:

2015-11-03 10:51:16 -0500 .gitignore
2016-03-30 11:50:05 -0400 .htaccess
2015-02-18 12:20:26 -0500 .travis.yml
2016-04-29 09:19:24 +0800 2016-01-13-Atlanta.md
2016-04-29 09:29:10 +0800 2016-03-03-Elmherst.md
2016-04-29 09:41:20 +0800 2016-03-03-Milford.md
2016-04-29 08:15:19 +0800 2016-03-06-Clayton.md
2016-04-29 01:20:01 +0800 2016-03-14-Richmond.md
2016-04-29 09:49:06 +0800 3/8/2016-Clayton.md
2015-08-26 16:19:56 -0400 404.htm
2016-03-31 11:54:19 -0400 _algorithms/acls-bradycardia-algorithm.htm
2015-12-23 17:03:51 -0500 _algorithms/acls-pulseless-arrest-algorithm-asystole.htm
2016-04-11 15:00:42 -0400 _algorithms/acls-pulseless-arrest-algorithm-pea.htm
2016-03-31 11:54:19 -0400 _algorithms/acls-secondary-survey.htm
2016-03-31 11:54:19 -0400 _algorithms/acls-suspected-stroke-algorithm.htm
2016-03-31 11:54:19 -0400 _algorithms/acls-tachycardia-algorithm-stable.htm
...

La sortie peut être triée par horodatage de modification en ajoutant | sortà la fin:

git ls-files -z | xargs -0 -n1 -I{} -- git log -1 --format="%ai {}" {} | sort
William Entriken
la source
Y a-t-il un moyen d'obtenir ceci trié par horodatage de modification?
Amelio Vazquez-Reina
1
@ AmelioVazquez-Reina: Ajoutez simplement `| sort` à la fin de la commande.
dotancohen
2
Cela fonctionne mais prend un temps très long ...
Guillochon
5

Ceci est un petit tweak de la réponse de Andrew M.. (Je n'ai pas pu commenter sa réponse.)

Placez le premier $ nom de fichier entre guillemets doubles , afin de prendre en charge les noms de fichiers avec des espaces incorporés.

git ls-tree -r --name-only HEAD | while read filename; do
    echo "$(git log -1 --format="%ad" -- "$filename") $filename"
done

Exemple de sortie:

Tue Jun 21 11:38:43 2016 -0600 subdir/this is a filename with spaces.txt

J'apprécie que la solution d'Andrew (basée sur ls-tree ) fonctionne avec des référentiels nus! (Ce n'est pas le cas des solutions utilisant les fichiers ls.)

Kevin G.
la source
Vous pouvez également ignorer echo: git log -1 --format = "% ad $ filename"
Kevin Lyda
0

Voici la version en coquille de poisson de la réponse d'Andrew M, pour ceux qui utilisent du poisson.

git ls-tree -r --name-only HEAD | while read -l filename
    printf '%s %s\n' (git log -1 --format="%ai" -- $filename) $filename
end

Je stocke cela comme une fonction de poisson pour un accès facile.

Kevin Cherepski
la source
0

Pour ceux d'entre nous qui utilisent Windows et PowerShell, la réponse d'Andrew M, avec le tweak lisible par ordinateur:

git ls-tree -r --name-only HEAD | ForEach-Object { "$(git log -1 --format="%ai" -- "$_")`t$_" }

Exemple de sortie:

2019-05-07 12:00:37 -0500   .editorconfig
2016-07-13 14:03:49 -0500   .gitattributes
2019-05-07 12:00:37 -0500   .gitignore
2018-02-03 22:01:17 -0600   .mailmap
James Skemp
la source