Passer de CVS à Git: équivalent $ Id $?


124

J'ai lu un tas de questions sur les outils de contrôle de code source simples et Git semblait être un choix raisonnable. Je l'ai opérationnel, et cela fonctionne bien jusqu'à présent. Un aspect que j'aime chez CVS est l'incrémentation automatique d'un numéro de version.

Je comprends que cela a moins de sens dans un référentiel distribué, mais en tant que développeur, je veux / ai besoin de quelque chose comme ça. Laissez-moi vous expliquer pourquoi:

J'utilise Emacs. Périodiquement, je passe en revue et cherche de nouvelles versions des fichiers source Lisp pour les paquets tiers. Disons que j'ai un fichier, foo.el, qui, selon l'en-tête, est la version 1.3; si je regarde la dernière version et vois que c'est 1.143 ou 2.6 ou autre, je sais que je suis assez loin derrière.

Si à la place je vois quelques hachages de 40 caractères, je ne saurai pas lequel est le plus tardif ou n'aurai aucune idée de combien de temps il est plus tard. Je détesterais absolument si je devais vérifier manuellement les ChangeLogs juste pour avoir une idée de mon dépassement.

En tant que développeur, je souhaite étendre cette courtoisie, telle que je la vois, aux personnes qui utilisent ma sortie (et peut-être que je me moque de moi, mais laissons cela de côté pendant un moment). Je ne veux pas avoir à me souvenir d'incrémenter moi-même ce foutu nombre à chaque fois, ou un horodatage ou quelque chose comme ça. C'est un vrai PITA, et je le sais par expérience.

Alors, quelles alternatives ai-je? Si je ne peux pas obtenir un équivalent $ Id: $, comment puis-je fournir ce que je recherche?

Je dois mentionner que je m'attends à ce que l'utilisateur final n'ait PAS installé Git et même s'il le fait, il n'aura pas de référentiel local (en effet, je m'attends à ne pas le rendre disponible de cette façon).

Réponses:


67

Le SHA n'est qu'une représentation d'une version (bien que canonique). La git describecommande en propose d'autres et le fait très bien.

Par exemple, lorsque je lance git describedans ma branche principale de ma source client Java Memcached , j'obtiens ceci:

2.2-16-gc0cd61a

Cela dit deux choses importantes:

  1. Il y a eu exactement 16 commits dans cet arbre depuis la version 2.2
  2. L' arbre source exact peut être affiché sur le clone de n'importe qui d'autre.

Disons, par exemple, que vous avez empaqueté un versionfichier avec la source (ou même réécrit tout le contenu pour la distribution) pour afficher ce numéro. Disons que la version packagée était 2.2-12-g6c4ae7a(pas une version, mais une version valide).

Vous pouvez maintenant voir exactement à quelle distance vous êtes (4 commits), et vous pouvez voir exactement quels 4 commits:

# The RHS of the .. can be origin/master or empty, or whatever you want.
% git log --pretty=format:"%h %an %s" 2.2-12-g6c4ae7a..2.2-16-gc0cd61a
c0cd61a Dustin Sallings More tries to get a timeout.
8c489ff Dustin Sallings Made the timeout test run on every protocol on every bui
fb326d5 Dustin Sallings Added a test for bug 35.
fba04e9 Valeri Felberg Support passing an expiration date into CAS operations.

1
L'utilisation de cela échouera lorsque vous fusionnerez la branche de développement, tandis que le maître disposait de correctifs. Le nombre de commits depuis la dernière version changera. Le hachage n'est pas fiable car quelqu'un peut reconstruire le tout avec filter-branchou quelque chose.
LeMike

La rédaction décrit uniquement l'apprentissage des informations, et non leur intégration dans votre exécutable. Pour cela, vous devez exécuter la git describecommande juste avant de créer, enregistrer la sortie dans un fichier d'en-tête ou incorporer la valeur dans votre code.
Jesse Chisholm

55

À présent, il existe un support pour $ Id: $ dans Git. Pour l'activer pour le fichier README, vous devez mettre "README ident" dans .gitattributes . Les caractères génériques sur les noms de fichiers sont pris en charge. Voir man gitattributes pour plus de détails.


14
Cela vous donne le sha1 du blob, mais pas le sha1 du commit. Utile, mais pas comme identifiant pour le commit.
Stephen Jennings

4
git n'a pas de mécanisme d'expansion de mot-clé comme celui $Id$mentionné. Ce qui est rangé est exactement ce que vous obtenez. Dans tous les cas, la version appartient à la collection complète des fichiers constituant un commit, pas à un fichier en particulier (cette idée est un vestige de l'époque RCS, ou peut-être que SCCS est à blâmer ici ... Comme CVS n'est qu'un glorifié frontend à RCS, et SVN essaie d'être un CVS-workalike, il est resté.).
vonbrand

32

Ce n'est pas une demande déraisonnable de l'OP.

Mon cas d'utilisation est:

  1. J'utilise Git pour mon propre code personnel, donc pas de collaboration avec les autres.
  2. Je garde des scripts système Bash là-dedans qui pourraient entrer /usr/local/binquand ils sont prêts.

J'utilise trois machines distinctes avec le même référentiel Git. Ce serait bien de savoir dans quelle "version" du fichier j'ai actuellement /usr/local/binsans avoir à faire un manuel "diff -u <repo version> <version dans / usr / local / bin>".

Pour ceux d'entre vous qui sont négatifs, rappelez-vous qu'il existe d'autres cas d'utilisation. Tout le monde n'utilise pas Git pour un travail collaboratif, les fichiers du référentiel Git étant leur emplacement «final».

Quoi qu'il en soit, la façon dont je l'ai fait a été de créer un fichier d'attributs dans le référentiel comme ceci:

cat .git/info/attributes
# see man gitattributes
*.sh ident
*.pl ident
*.cgi ident

Ensuite, mettez $ Id $ quelque part dans le fichier (j'aime le mettre après le shebang).

Le commit. Notez que cela ne fait pas automatiquement l'expansion comme je m'y attendais. Vous devez recopier le fichier, par exemple,

git commit foo.sh
rm foo.sh
git co foo.sh

Et puis vous verrez l'extension, par exemple:

$ head foo.sh
#!/bin/sh

# $Id: e184834e6757aac77fd0f71344934b1cd774e6d4 $

Vous trouverez de bonnes informations dans Comment activer la chaîne d'identification pour un référentiel Git? .


3
Il convient de noter que cela identifie le fichier actuel (blob), pas le commit actuel
CharlesB

3
Que git codoit-on faire? J'ai reçu le message d'erreur " git: 'co' is not a git command. See 'git --help'." Doit- il l'êtregit checkout ?
Peter Mortensen

23

Je ne suis pas sûr que ce sera jamais dans Git. Pour citer Linus :

"Toute la notion de substitution de mots-clés est totalement idiote. Il est trivial de faire" en dehors "du suivi de contenu réel, si vous voulez l'avoir lorsque vous faites des arbres de publication comme des boules tar, etc."

Cependant, il est assez facile de vérifier le journal - si vous suivez la branche stable de foo.el, vous pouvez voir quels nouveaux commits sont dans le journal de la branche stable qui ne sont pas dans votre copie locale. Si vous souhaitez simuler le numéro de version interne de CVS, vous pouvez comparer l'horodatage du dernier commit.

Edit: vous devez écrire ou utiliser les scripts de quelqu'un d'autre pour cela, bien sûr, ne pas le faire manuellement.


26
Oui, j'ai lu une partie de cette longue chaîne d'e-mails sur les extensions de mots clés. L'attitude de Linus était presque suffisante pour me décourager complètement.
Joe Casadonte

15
Oui, parfois il manque de politesse, mais il a généralement raison, et il est définitivement sur le sujet de l'expansion des mots clés.
Bombe

Le suivi des versions est nécessaire. git est utilisé dans tant d'autres infrastructures en plus du développement pur où l'on peut lire le code pour déterminer s'il a du sens. Mais lorsqu'un système de contrôle de révision est utilisé pour suivre des fichiers avec un contenu arbitraire, vous devez avoir des moyens de connaître la version officielle. git, et encore moins git log n'est pas sur la machine sur laquelle les fichiers .ini, .conf, .html et autres ont été envoyés.
rjt

7
Linus a commenté un seul aspect de l'expansion des mots clés: le suivi des versions. Mais ce n'est pas le seul objectif. Cette citation démontre clairement l'attitude d'un homme, mais ne dit rien d'utile sur le sujet. Un truc politique typique «énoncez l'évidence d'une manière exaltée», et la foule est à vous. Le problème est que la foule est par définition stupide, car elle n'a qu'un seul cerveau à travers tout cela. Ce qui explique clairement la situation avec git et l'expansion des mots clés. Un idiot a dit "non" et tout le monde a applaudi!
AnrDaemon

1
@AnrDaemon non seulement cela, git maintenant depuis l'ajout du support pour $Id$via l' identattribut, comme mentionné dans une autre réponse ici, montrant que même git lui-même n'est pas l'otage de l'opinion de Linus.
orip

21

Comme je l' ai écrit avant :

Avoir des balises d'identification générées automatiquement qui montrent un numéro de version raisonnable est impossible à faire avec des outils DSCM comme Bazaar car la ligne de développement de chacun peut être différente de toutes les autres. Donc, quelqu'un pourrait se référer à la version "1.41" d'un fichier mais votre version "1.41" de ce fichier est différente.

Fondamentalement, $ Id $ n'a aucun sens avec Bazaar, Git et d'autres outils de gestion de code source distribués.


6
Bien, j'ai lu cela avant de poster, et c'est pourquoi j'ai demandé une solution plus générale au problème sous-jacent. Je pense que le désir pour un fichier individuel d'avoir une version # est légitime, tout comme l'incapacité de git à fournir une solution.
Joe Casadonte

Ce n'est pas une incapacité de Git, c'est une incapacité de tous les SCM distribués. Si vous voulez vraiment des numéros de version significatifs, utilisez Subversion ou CVS, ou un autre système centralisé.
Bombe

7
qu'est-ce qui ne va pas avec juste cracher le hachage au lieu d'un "numéro de version"? Je veux des instructions de journal, des pages Web de débogage et des options «--version» sur les scripts internes qui me diront facilement quelle révision est en cours d'exécution, où, afin que je puisse extraire ce hachage spécifique et voir pourquoi il se comporte comme il est. Cela simplifie la gestion des applications déployées ... et je ne veux pas d'un hook de validation qui considère chaque commit comme une modification de chaque fichier contenant une balise $ Id $.
nairbv

1
le hachage du fichier sur lequel vous travaillez fonctionnerait de la même manière qu'une "version", tant que vous pouvez le rechercher dans git par cet identifiant
Erik Aronesty

2
@Brian - selon la modification de l'OP, l'utilisateur final veut connaître le numéro de version mais n'a pas accès à git ou aux journaux git. Dans ce cas, le hachage est un nombre sans signification, pas un numéro de version. Un DSCM ne fournit aucune aide pour résoudre ce besoin.
Jesse Chisholm

10

J'ai eu le même problème. J'avais besoin d'une version plus simple qu'une chaîne de hachage et disponible pour les personnes utilisant l'outil sans avoir besoin de se connecter au référentiel.

Je l'ai fait avec un hook de pré-commit Git et j'ai changé mon script pour pouvoir se mettre à jour automatiquement.

Je base la version sur le nombre de commits effectués. Il s'agit d'une légère condition de concurrence car deux personnes pourraient s'engager en même temps et toutes les deux pensent qu'elles commettent le même numéro de version, mais nous n'avons pas beaucoup de développeurs sur ce projet.

À titre d'exemple, j'ai un script que j'archive qui est en Ruby, et j'y ajoute ce code - c'est un code assez simple, il est donc facile de porter vers différentes langues si vous enregistrez quelque chose dans une langue différente (bien que évidemment cela ne fonctionnera pas facilement avec des archivages non exécutables tels que des fichiers texte). J'ai ajouté:

MYVERSION = '1.090'
## Call script to do updateVersion from .git/hooks/pre-commit
def updateVersion
  # We add 1 because the next commit is probably one more - though this is a race
  commits = %x[git log #{$0} | grep '^commit ' | wc -l].to_i + 1
  vers = "1.%0.3d" % commits

  t = File.read($0)
  t.gsub!(/^MYVERSION = '(.*)'$/, "MYVERSION = '#{vers}'")
  bak = $0+'.bak'
  File.open(bak,'w') { |f| f.puts t }
  perm = File.stat($0).mode & 0xfff
  File.rename(bak,$0)
  File.chmod(perm,$0)
  exit
end

Et puis j'ajoute une option de ligne de commande (-updateVersion) au script donc si je l'appelle comme "tool -updateVersion" alors il appelle juste updateVersion pour l'outil qui modifie la valeur "MYVERSION" en lui-même et puis quitte (vous pouvez faites-le également mettre à jour d'autres fichiers s'ils sont également ouverts si vous le souhaitez).

Une fois que c'est configuré, je vais à la tête de Git et crée un script bash exécutable sur une ligne dans .git/hooks/pre-commit.

Le script change simplement en tête du répertoire Git et appelle mon script avec -updateVersion.

Chaque fois que j'enregistre le script de pré-validation est exécuté qui exécute mon script avec -updateVersion, puis la variable MYVERSION est mise à jour en fonction du nombre de validations. La magie!


Alors, votre script Ruby doit-il s'appeler updateVersion pour avoir git updateVersion? Veuillez mettre quelques exemples de son nom.
rjt

Je fais une option (-updateVersion) au script que je vérifie qui appelle la fonction 'updateVersion' (dans ce cas, j'essaye de changer le numéro de version dans le script lui-même). Ensuite, je fais juste une commande shell oneliner qui appelle mon script avec -updateVersion, puis il se met à jour avant chaque enregistrement.
David Ljung Madison Stellar

8

Si avoir $ Keywords $ est essentiel pour vous, alors peut-être pourriez-vous essayer de regarder Mercurial à la place? Il a une extension hgkeyword qui implémente ce que vous voulez. Mercurial est de toute façon intéressant en tant que DVCS.


8

Une chose qui est faite avec les référentiels Git est d'utiliser l' tagobjet. Cela peut être utilisé pour marquer un commit avec n'importe quel type de chaîne et peut être utilisé pour marquer des versions. Vous pouvez voir que les balises dans un référentiel avec legit tag commande, qui renvoie toutes les balises.

Il est facile de vérifier une balise. Par exemple, s'il existe une balise, v1.1vous pouvez récupérer cette balise dans une branche comme celle-ci:

git checkout -b v1.1

Comme il s'agit d'un objet de premier niveau, vous verrez tout l'historique de cette validation, ainsi que vous pourrez exécuter des différences, apporter des modifications et des fusions.

Non seulement cela, mais une balise persiste, même si la branche sur laquelle elle se trouvait a été supprimée sans être fusionnée dans la ligne principale.


6
Existe-t-il alors un moyen d'insérer automatiquement cette balise dans le fichier par git? Merci!
Joe Casadonte

1
Si vous entendez par expansion de mots clés? Pas pour autant que je sache. si vous créez des produits, vous pouvez obtenir les informations dans le cadre de votre script de construction et les insérer quelque part dans votre produit construit. Essayez man git-describe qui donne la dernière balise, le nombre de commits depuis cette balise et le hachage actuel.
Abizern

Oui, les balises et autres informations associées peuvent désormais être éditées automatiquement dans des fichiers par git via la export-substfonctionnalité de gitattributes(5). Cela nécessite bien sûr l'utilisation de git archivepour créer des versions, et les modifications de substitution ne seront visibles que dans le fichier tar résultant.
Greg A. Woods le

4

Si je comprends bien, vous voulez essentiellement savoir combien de commits se sont produits sur un fichier donné depuis la dernière mise à jour.

Commencez par récupérer les modifications dans l'origine distante, mais ne les fusionnez pas dans votre masterbranche:

% git fetch

Ensuite, obtenez un journal des changements qui se sont produits sur un fichier donné entre votre mastersuccursale et la télécommande origin/master.

% git log master..origin/master foo.el

Cela vous donne les messages de journal de toutes les validations qui se sont produites dans le référentiel distant depuis votre dernière fusion origin/masterdans votre master.

Si vous voulez juste un décompte des modifications, dirigez-le vers wc. Dis, comme ceci:

% git rev-list master..origin/master foo.el | wc -l

1
Donc, n'utilisez pas log: git rev-list master..origin / master | wc -l
Dustin

4

Si vous voulez simplement que les gens puissent avoir une idée de leur dépassement, Git peut les informer de plusieurs manières assez simples. Ils comparent les dates du dernier commit sur leur coffre et votre coffre, par exemple. Ils peuvent utiliser git cherrypour voir combien de commits se sont produits dans votre coffre qui ne sont pas présents dans le leur.

Si c'est tout ce que vous voulez, je chercherais un moyen de le fournir sans numéro de version.

De plus, je ne prendrais pas la peine d'étendre la courtoisie à qui que ce soit à moins que vous ne soyez sûr qu'il le souhaite. :)


Si vous pouvez comparer les dates, placez le DateTImeStamp dans le fichier. git a tellement d'autres cas d'utilisation que de simples développeurs. Le service informatique sur le terrain a besoin de savoir si le fichier .INI ou .conf sur le poste de travail en cours de dépannage est proche de ce qui est actuel.
rjt

Un simple horodatage suffira-t-il? La mauvaise branche peut avoir un horodatage attrayant et être encore moins correcte.
user2066657

4

Pour appliquer l'expansion à tous les fichiers de tous les sous-répertoires du référentiel, ajoutez un .gitattributesfichier au répertoire de niveau supérieur du référentiel (c'est-à-dire où vous placez normalement le .gitignorefichier) contenant:

* ident

Pour voir cela en vigueur, vous devez d'abord effectuer une extraction efficace du ou des fichiers, par exemple en les supprimant ou en les modifiant de quelque manière que ce soit. Puis restaurez-les avec:

git checkout .

Et vous devriez voir $Id$remplacé par quelque chose comme:

$Id: ea701b0bb744c90c620f315e2438bc6b764cdb87 $

De man gitattributes:

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.

Cet ID changera chaque fois qu'une nouvelle version du fichier est validée.


3

Les ID RCS sont bien pour les projets à un seul fichier, mais pour tous les autres, $ Id $ ne dit rien sur le projet (sauf si vous effectuez des vérifications forcées dans un fichier de version factice).

On pourrait néanmoins être intéressé par la façon d'obtenir les équivalents de $ Author $, $ Date $, $ Revision $, $ RCSfile $, etc. au niveau par fichier ou au niveau de la validation (comment les mettre là où se trouvent certains mots-clés en est une autre question). Je n'ai pas de réponse à ce sujet, mais je vois la nécessité de les mettre à jour, en particulier lorsque les fichiers (maintenant dans Git) proviennent de systèmes compatibles RCS (CVS).

De tels mots-clés peuvent être intéressants si les sources sont distribuées séparément de tout dépôt Git (c'est ce que je fais aussi). Ma solution est comme ceci:

Chaque projet a son propre répertoire et à la racine du projet, j'ai un fichier texte nommé .version dont le contenu décrit la version actuelle (le nom qui sera utilisé lors de l'exportation des sources).

Tout en travaillant pour la prochaine version, un script extrait ce .versionnuméro, un descripteur de version Git (comme git describe) et un numéro de build monotone dans .build(plus l'hôte et la date) dans un fichier source généré automatiquement qui est lié au programme final, afin que vous puissiez trouver de quelle source et quand il a été construit.

Je développe de nouvelles fonctionnalités dans des branches séparées, et la première chose que je fais est d'ajouter n(pour "next") à la .versionchaîne (plusieurs branches provenant de la même racine utiliseraient le même .versionnuméro temporaire ). Avant la sortie, je décide quelles branches fusionner (j'espère qu'elles ont toutes les mêmes .version). Avant de valider la fusion, je mets à jour .versionle numéro suivant ( mise à jour majeure ou mineure, selon les fonctionnalités fusionnées).


3

Si vous voulez que les informations git commit soient accessibles dans votre code, vous devez effectuer une étape de pré-construction pour y parvenir. Dans bash pour C / C ++, cela pourrait ressembler à ceci:

prebuild.sh

#!/bin/bash
commit=$(git rev-parse HEAD)
tag=$(git describe --tags --always ${commit})
cat <<EOF >version.c
#include "version.h"
const char* git_tag="${tag}";
const char* git_commit="${commit}";
EOF

avec version.hressemblant à:

#pragma once
const char* git_tag;
const char* git_commit;

Ensuite, partout où vous en avez besoin dans votre code #include "version.h"et référence git_tagou git_commitselon vos besoins.

Et vous Makefilepourriez avoir quelque chose comme ça:

all: package
version:
  ./prebuild.sh
package: version
  # the normal build stuff for your project

Cela a l'avantage de:

  • obtenir les valeurs actuellement correctes pour cette version indépendamment de la ramification, de la fusion de la sélection de cerises et autres.

Cette implémentation de prepublish.shprésente les inconvénients de:

  • forcer une recompilation même si le git_tag/git_commit n'a pas changé.
  • il ne prend pas en compte les fichiers modifiés locaux qui n'ont pas été validés mais effectuent la construction.
    • utiliser git describe --tags --always --dirtypour attraper ce cas d'utilisation.
  • pollue l'espace de noms global.

Un amateur prebuild.shqui pourrait éviter ces problèmes est laissé comme exercice pour le lecteur.


1

Je suis d'accord avec ceux qui pensent que le remplacement des jetons appartient aux outils de construction plutôt qu'aux outils de contrôle de version.

Vous devriez avoir un outil de publication automatisé pour définir les ID de version dans vos sources au moment où la publication est balisée.


2
.INI .conf et .txt n'ont généralement pas d'outil de construction.
rjt

Mais vous pouvez pirater ensemble un script de publication qui prend la balise Git actuelle et l'écrit dans un fichier, ou quelque chose du genre.
Marnen Laibow-Koser

1

Les noms de balises et autres informations associées peuvent désormais être édités directement dans des fichiers automatiquement par Git grâce à la export-substfonctionnalité de gitattributes(5). Cela nécessite bien sûr l'utilisation de git archivepour créer des versions, et les modifications de substitution ne seront visibles que dans le fichier tar résultant.

Par exemple, dans le .gitattributesfichier, mettez la ligne suivante:

* export-subst

Ensuite, dans les fichiers source, vous pouvez ajouter une ligne comme celle-ci:

#ident  "@(#)PROJECTNAME:FILENAME:$Format:%D:%ci:%cN:%h$"

Et il se développera pour ressembler à ceci dans une version créée par, par exemple git archive v1.2.0.90,:

#ident  "@(#)PROJECTNAME:FILENAME:HEAD -> master, tag: v1.2.0.90:2020-04-03 18:40:44 -0700:Greg A. Woods:e48f949"

0

Puisque vous utilisez Emacs, vous pourriez avoir de la chance :)

Je suis tombé sur cette question par coïncidence, et aussi par coïncidence, je suis tombé sur Lively il y a quelques jours, un paquet Emacs qui permet d'avoir des morceaux vivants d'Emacs Lisp dans votre document. Je n'ai pas essayé pour être honnête, mais cela m'est venu à l'esprit en lisant ceci.


0

Je suis également venu de SCCS, RCS et CVS ( %W% %G% %U%).

J'ai eu un défi similaire. Je voulais savoir quelle version était un morceau de code sur n'importe quel système qui l'exécutait. Le système peut ou non être connecté à un réseau. Le système peut avoir installé ou non Git. Le système peut ou non avoir le référentiel GitHub installé dessus.

Je voulais la même solution pour plusieurs types de code (.sh, .go, .yml, .xml, etc.). Je voulais que toute personne sans connaissance de Git ou GitHub puisse répondre à la question "Quelle version utilisez-vous?"

Donc, j'ai écrit ce que j'appelle un wrapper autour de quelques commandes Git. Je l'utilise pour marquer un fichier avec un numéro de version et quelques informations. Cela résout mon défi. Cela peut vous aider.

https://github.com/BradleyA/markit

git clone https://github.com/BradleyA/markit
cd markit

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.