109 votes

Comment récupérer la date de dernière modification de tous les fichiers d'un dépôt Git ?

Je sais comment récupérer la date de dernière modification d'un seul fichier dans un dépôt Git :

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

Existe-t-il un moyen simple et efficace de faire de même pour tous les fichiers actuellement présents dans le référentiel ?

112voto

Andrew M. Points 10852

Une réponse simple serait d'itérer à travers chaque fichier et d'afficher son temps de modification, c'est-à-dire :

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

Le résultat sera le suivant :

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

Évidemment, vous pouvez contrôler ceci puisque c'est juste un bash script à ce stade - donc sentez-vous libre de personnaliser à votre guise !

45voto

Pompair Points 1606

Cette approche fonctionne également avec les noms de fichiers qui contiennent 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 l'horodatage de la modification en ajoutant | sort jusqu'à la fin :

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

20voto

Mikko Rantalainen Points 778

Voici un autre moyen :

git ls-tree -r --name-only HEAD -z | TZ=UTC xargs -0n1 -I_ git --no-pager log -1 --date=iso-local --format="%ad _" -- _

Modifications des réponses données précédemment :

  • Gère correctement les espaces dans les noms de fichiers.
  • Utilisations ls-tree au lieu de ls-files et en tant que tel, il peut être utilisé avec des dépôts nus.
  • Imprime toutes les heures avec un décalage de zéro (UTC) dans le format ISO 8601. Cela permet un tri correct également pour les heures proches des changements d'heure d'été (ou commits de différents fuseaux horaires) en annexant | sort à la commande.
  • Il n'est pas nécessaire d'utiliser des sous-shells, les performances devraient donc être aussi bonnes que possible.

Notez que cela ne gère pas correctement les noms de fichiers avec le caractère % caractère. Voir ci-dessous pour une commande plus élaborée permettant de gérer correctement tous les caractères dans les noms de fichiers.

Notez que cette commande est toujours très lente car Git ne stocke pas vraiment les informations que nous recherchons. Techniquement, cela passe en revue tous les fichiers, filtre toutes les modifications apportées à un fichier donné à partir de l'ensemble de l'historique du projet, prend le dernier commit et imprime son timestamp d'auteur. En conséquence, les heures affichées correspondent au dernier commit qui a modifié chaque fichier. Si le fichier avait un horodatage différent sur le disque au moment où le commit original a été fait, il n'a jamais été stocké nulle part dans le dépôt Git et en tant que tel il ne peut jamais être restauré sans une source de données externe.

Si vous voulez définir les temps de modification du système de fichiers au dernier auteur commit temps de chaque fichier, vous pouvez faire quelque chose comme ceci pour traiter les caractères spéciaux dans les noms de fichiers (ajouter | bash pour exécuter automatiquement toutes les commandes émises) :

git ls-tree -r --name-only HEAD -z | TZ=UTC xargs -0n1 git --no-pager log -1 --date=iso-local --name-only -z --format="format:%ad" | perl -npe "INIT {\$/ = \"\\0\"} s@^(.*? .*?) .*?\n(.*)\$@\$date=\$1; \$name=\$2; \$name =~ s/'/'\"'\"'/sg; \"TZ=UTC touch -m --date '\$date' '\$name';\n\"@se"

Même si cette commande est beaucoup plus complexe que la commande ci-dessus, les performances de cette commande devraient être à peu près égales à celles de la première, car les performances sont limitées par la recherche de la dernière heure de modification de chaque fichier au lieu de définir réellement l'heure de modification. Notez que cette commande convertit les heures en UTC, utilise des fichiers non séparés et réinitialise l'horodatage correct pour chaque fichier du système de fichiers en utilisant le fuseau horaire UTC tout en définissant l'heure.

Si l'ordre de sortie n'est pas strictement important, vous pouvez améliorer la performance de cette commande en ajoutant -P $(nproc) a xargs pour adapter Git à tous les processeurs, ce qui donne à la commande l'aspect suivant ...TZ=UTC xargs -0n1 -P $(nproc) git... .

Si vous préférez l'heure du committer plutôt que la date de l'auteur, utilisez %cd au lieu de %ad dans la ligne de commande ci-dessus.

9voto

Andrew Murphy Points 151

Si vous essayez de définir les temps de modification des fichiers sur un grand dépôt, regardez à Outils Git . C'est déjà un paquet.

sudo apt install git-restore-mtime
cd repo
git restore-mtime

Il utilise git whatschanged plutôt que git log qui est beaucoup plus rapide sur les gros dépôts.

6voto

OTZ Points 1039

Il s'agit d'une petite modification de La réponse d'Andrew M. . (Je n'ai pas pu commenter sa réponse).

Mettez le premier $filename entre guillemets doubles. afin de prendre en charge les noms de fichiers comportant des espaces intégré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 les dépôts nus ! (Ce n'est pas le cas des solutions utilisant ls-files .)

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X