Dans Git, comment puis-je écrire le hachage de commit actuel dans un fichier du même commit

131

J'essaie de faire des trucs fantaisistes ici avec des hooks Git, mais je ne sais pas vraiment comment le faire (ou si c'est possible).

Ce que je dois faire est: dans chaque commit, je veux prendre son hachage puis mettre à jour un fichier dans le commit avec ce hachage.

Des idées?

Felipe Kamakura
la source
12
Fondamentalement, j'ai une application Web et je souhaite associer une version installée de cette application au commit exact auquel cette version est associée. Mon idée initiale était de mettre à jour une sorte de fichier about.html avec le hachage de validation. Mais après avoir étudié le modèle des objets de git, j'ai réalisé que c'était un peu impossible = /
Felipe Kamakura
29
C'est un problème très pratique. Je suis tombé dedans aussi!
Li Dong
7
Quant à moi, j'aimerais que mon programme écrive un message comme celui-ci dans les logs: "myprog startup up, v.56c6bb2". De cette façon, si quelqu'un signale un bogue et m'envoie les fichiers journaux, je peux savoir exactement quelle version de mon programme était en cours d'exécution.
Edward Falk
5
@Jefromi, le cas d'utilisation réel est en fait très courant et frappe très facilement les débutants. Avoir la version réelle "imprimée" d'une manière ou d'une autre dans des fichiers de base est un besoin de base, et il est loin d'être évident que ce serait une mauvaise idée, par exemple parce que c'est à peu près votre seule option avec les hacks de contrôle de révision manuel. (Rappelez-vous les débutants.) Ajoutez à cela que de nombreux projets n'ont tout simplement aucune sorte d'étape de construction / installation / déploiement qui pourrait saisir et tamponner la version dans des fichiers actifs. Quoi qu'il en soit, au lieu du pré-commit, le hook post-checkout pourrait aider même dans ces cas.
Sz.
C'est impossible! Si vous pouvez faire cela, vous avez cassé l'algorithme de hachage SHA-1 ... ericsink.com/vcbe/html/cryptographic_hashes.html
betontalpfa

Réponses:

82

Je recommanderais de faire quelque chose de similaire à ce que vous avez en tête: placer le SHA1 dans un fichier non suivi , généré dans le cadre du processus de construction / installation / déploiement. C'est évidemment facile à faire ( git rev-parse HEAD > filenameou peut-être git describe [--tags] > filename), et cela évite de faire quelque chose de fou comme se retrouver avec un fichier différent de ce que git traque.

Votre code peut alors référencer ce fichier lorsqu'il a besoin du numéro de version, ou un processus de génération peut incorporer les informations dans le produit final. Ce dernier est en fait la façon dont git lui-même obtient ses numéros de version - le processus de construction saisit le numéro de version du dépôt, puis le construit dans l'exécutable.

Cascabel
la source
3
Quelqu'un pourrait-il expliquer étape par étape comment procéder? Ou au moins un coup de coude dans la bonne direction?
Joel Worsham
1
@Joel Comment faire quoi? J'ai mentionné comment mettre le hachage dans un fichier; le reste concerne probablement votre processus de construction? Peut-être une nouvelle question si vous essayez de poser des questions sur cette partie.
Cascabel
1
Dans mon cas, j'ai ajouté une règle à mon Makefile qui génère un fichier "gitversion.h" à chaque build. Voir stackoverflow.com/a/38087913/338479
Edward Falk
1
Vous pourrez peut-être automatiser cela avec un hook "git-checkout". Le problème est que les crochets devraient être installés manuellement.
Edward Falk
14

Il est impossible d'écrire le hachage de validation actuel: si vous parvenez à pré-calculer le hachage de validation futur, il changera dès que vous modifierez un fichier.

Cependant, il existe trois options:

  1. Utilisez un script pour incrémenter 'commit id' et l'inclure quelque part. Laid
  2. .gitignore le fichier dans lequel vous allez stocker le hachage. Pas très pratique
  3. Dans pre-commit, stockez le hachage de commit précédent :) Vous ne modifiez / n'insérez pas de commits dans 99,99% des cas, donc, cela fonctionnera. Dans le pire des cas, vous pouvez toujours identifier la révision source.

Je travaille sur un script de hook, je le posterai ici `` quand c'est fait '', mais encore - avant la sortie de Duke Nukem Forever :))

Mise à jour : code pour .git/hooks/pre-commit:

#!/usr/bin/env bash
set -e

#=== 'prev-commit' solution by o_O Tync
#commit_hash=$(git rev-parse --verify HEAD)
commit=$(git log -1 --pretty="%H%n%ci") # hash \n date
commit_hash=$(echo "$commit" | head -1)
commit_date=$(echo "$commit" | head -2 | tail -1) # 2010-12-28 05:16:23 +0300

branch_name=$(git symbolic-ref -q HEAD) # http://stackoverflow.com/questions/1593051/#1593487
branch_name=${branch_name##refs/heads/}
branch_name=${branch_name:-HEAD} # 'HEAD' indicates detached HEAD situation

# Write it
echo -e "prev_commit='$commit_hash'\ndate='$commit_date'\nbranch='$branch'\n" > gitcommit.py

Maintenant, la seule chose dont nous avons besoin est un outil qui convertit la prev_commit,branchpaire en un véritable hachage de validation :)

Je ne sais pas si cette approche peut distinguer les commits de fusion. Je vais le vérifier bientôt

kolypto
la source
13

Quelqu'un m'a indiqué la section "man gitattributes" sur ident, qui contient ceci:

ident

Lorsque l'attribut ident est défini pour un chemin, git remplace $ Id $ dans l'objet blob par $ Id :, suivi du nom de l'objet blob hexadécimal à 40 caractères, suivi d'un signe dollar $ lors du paiement. Toute séquence d'octets commençant par $ Id: et se terminant par $ dans le fichier de l'arbre de travail est remplacée par $ Id $ lors de l'enregistrement.

Si vous y réfléchissez, c'est ce que font aussi CVS, Subversion, etc. Si vous regardez le référentiel, vous verrez que le fichier dans le référentiel contient toujours, par exemple, $ Id $. Il ne contient jamais l'expansion de cela. Ce n'est qu'à la caisse que le texte est développé.

Baron Schwartz
la source
8
identest le hachage du fichier lui-même, pas le hast du commit. De git-scm.com/book/en/… : "Cependant, ce résultat est d'une utilité limitée. Si vous avez utilisé la substitution de mots-clés dans CVS ou Subversion, vous pouvez inclure un horodatage - le SHA n'est pas très utile, car c'est assez aléatoire et vous ne pouvez pas dire si un SHA est plus ancien ou plus récent qu'un autre. " filterprend du travail, mais il peut obtenir les informations de validation dans (et hors de) un fichier.
Zach Young
11

Cela peut être réalisé en utilisant l' filterattribut dans gitattributes . Vous devez fournir une smudgecommande qui insère l'ID de validation et une cleancommande qui le supprime, de sorte que le fichier dans lequel il est inséré ne change pas simplement à cause de l'ID de validation.

Ainsi, l'ID de validation n'est jamais stocké dans l'objet blob du fichier; il est simplement développé dans votre copie de travail. (En fait, l'insertion de l'identifiant de validation dans le blob deviendrait une tâche infiniment récursive. ☺) Quiconque clonerait cet arbre devrait configurer les attributs pour elle-même.

legoscia
la source
7
Tâche impossible , pas tâche récursive. Le hachage de validation dépend du hachage de l'arborescence qui dépend du hachage du fichier, qui dépend du contenu du fichier. Vous devez obtenir la cohérence de soi. À moins que vous ne trouviez une sorte de point fixe [généralisé] pour le hachage SHA-1.
Jakub Narębski
1
@Jakub, y a-t-il une sorte d'astuce dans git qui permettra de créer des fichiers suivis qui ne modifient pas le hachage résultant? Un moyen de remplacer son hachage, peut-être. Ce sera une solution :)
kolypto
@o_O Tync: impossible. Un fichier modifié signifie un hachage modifié (d'un fichier) - c'est par conception et par définition d'une fonction de hachage.
Jakub Narębski le
2
C'est une très bonne solution, mais gardez à l'esprit que cela implique des hooks qui doivent être installés manuellement chaque fois que vous clonez un référentiel.
Edward Falk
7

Pensez en dehors de la boîte de validation!

placez-le dans le fichier hooks / post-checkout

#!/bin/sh
git describe --all --long > config/git-commit-version.txt

La version sera disponible partout où vous l'utilisez.

Keith Patrick
la source
3

Je ne pense pas que vous vouliez réellement faire cela, car lorsqu'un fichier du commit est modifié, le hachage du commit est également modifié.

midtiby
la source
1

Permettez-moi d'explorer pourquoi c'est un problème difficile en utilisant les internes de git. Vous pouvez obtenir le sha1 du commit actuel par

#!/bin/bash
commit=$(git cat-file commit HEAD) #
sha1=($((printf "commit %s\0" $(echo "$commit" | wc -c); echo "$commit") | sha1sum))
echo ${sha1[0]}

Essentiellement, vous exécutez une somme de contrôle sha1 sur le message renvoyé par git cat-file commit HEAD. Deux choses apparaissent immédiatement comme un problème lorsque vous examinez ce message. L'un est l'arbre sha1 et le second est l'heure de validation.

Désormais, le temps de validation est facilement pris en charge en modifiant le message et en devinant combien de temps il faut pour effectuer une validation ou planifier une validation à un moment donné. Le vrai problème est l'arbre sha1, à partir duquel vous pouvez obtenir git ls-tree $(git write-tree) | git mktree. Essentiellement, vous faites une somme de contrôle sha1 sur le message de ls-tree, qui est une liste de tous les fichiers et leur somme de contrôle sha1.

Par conséquent, votre somme de contrôle sha1 de validation dépend de la somme de contrôle sha1 de votre arbre, qui dépend directement de la somme de contrôle sha1 des fichiers, qui complète le cercle et dépend du commit sha1. Ainsi, vous avez un problème circulaire avec les techniques dont je dispose.

Avec des sommes de contrôle moins sécurisées , il s'est avéré possible d'écrire la somme de contrôle du fichier dans le fichier lui-même par force brute; cependant, je ne connais aucun travail qui ait accompli cette tâche avec sha1. Ce n'est pas impossible, mais presque impossible avec notre compréhension actuelle (mais qui sait peut-être que dans quelques années, ce sera insignifiant). Cependant, cela est encore plus difficile à utiliser par force brute puisque vous devez écrire la somme de contrôle (de validation) d'une somme de contrôle (d'arborescence) d'une somme de contrôle (blob) dans le fichier.

Novice C
la source
Existe-t-il un moyen de valider les fichiers, puis de faire une extraction et de placer le dernier hachage de validation en tant que commentaire au début de chaque fichier de code source? Puis construire et partir de ça?
John Wooten