web-dev-qa-db-fra.com

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

J'ai lu un tas de questions sur de simples outils de contrôle de code source et Git semblait être un choix raisonnable. Je l'ai et fonctionne, et cela fonctionne bien jusqu'à présent. L’un des aspects que j’aime dans 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. Je consulte périodiquement de nouvelles versions des fichiers source LISP pour les packages 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 que je vois la version 1.143 ou 2.6, peu importe, je sais que je suis assez loin derrière.

Si au lieu de cela je vois quelques hachages de 40 caractères, je ne saurai pas ce qui est plus tard ou n'aurai aucune idée de combien il sera plus tard. Je détesterais absolument cela si je devais vérifier manuellement les ChangeLogs juste pour avoir une idée de mon état de vieillesse.

En tant que développeur, je souhaite étendre cette courtoisie, à mon avis, aux personnes qui utilisent mes résultats (et je me fiche peut-être que quiconque l’est, mais laissons cela de côté un instant). Je ne veux pas avoir à me souvenir d’augmenter chaque fois ce nombre sacré, ni 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 l'équivalent $ Id: $, comment puis-je fournir ce que je cherche?

Je devrais mentionner que je m'attends à ce que l'utilisateur final ne fasse PAS installer Git et, même s'ils le font, ne disposeront pas de référentiel local (en fait, je m'attends à ne pas le rendre disponible de cette façon). 

115
Joe Casadonte

Le SHA n'est qu'une représentation d'une version (bien que canonique). La commande git describe offre aux autres et le fait très bien.

Par exemple, lorsque j'exécute git describe dans la branche principale de mon client memcached Java source, je reçois 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'arborescence source exact peut être affichée sur le clone de quelqu'un d'autre.

Supposons, par exemple, que vous ayez empaqueté un fichier version avec le source (ou même que vous ayez réécrit tout le contenu pour le distribuer) afin d'indiquer ce nombre. Supposons que la version empaquetée était 2.2-12-g6c4ae7a (non une version, mais une version valide).

Vous pouvez maintenant voir exactement à quelle distance derrière vous (4 commits), et vous pouvez voir exactement quels 4 commets:

# 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.
64
Dustin

A présent, il existe un support pour $ Id: $ dans Git. Pour l'activer pour le fichier README, vous devez placer "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.

51
Sebastian Pipping

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 d'autres.
  2. Je conserve des scripts Bash système qui pourraient entrer dans /usr/local/bin quand ils seront prêts.

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

Pour ceux d'entre vous qui êtes 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 constituant leur emplacement "final".

Quoi qu'il en soit, la façon dont je l'ai fait était 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 recoiffer le fichier, par exemple,

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

Et ensuite, vous verrez l'expansion, par exemple:

$ head foo.sh
#!/bin/sh

# $Id: e184834e6757aac77fd0f71344934b1cd774e6d4 $

Quelques bonnes informations se trouvent dans Comment activer la chaîne ident pour un référentiel Git?.

31
Imran-UK

Je ne suis pas sûr que cela se passera jamais à 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 le souhaitez .__

Il est cependant assez facile de consulter le journal. Si vous suivez la branche stable de foo.el, vous pouvez voir quels nouveaux commits figurent dans le journal de la branche stable qui ne figurent 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 devriez écrire ou utiliser les scripts de quelqu'un d'autre pour cela, bien sûr, ne le faites pas manuellement.

23
orip

Comme je l’ai écrit avant :

Il est impossible de créer des balises Id générées automatiquement qui indiquent un numéro de version raisonnable avec des outils DSCM tels que Bazaar, car chaque ligne de développement peut être différente de toutes les autres. Ainsi, quelqu'un pourrait faire référence à 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.

20
Bombe

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 peuvent s'engager en même temps et pensent toutes les deux qu'elles commettent le même numéro de version, mais nous n'avons pas beaucoup de développeurs sur ce projet.

Le mien est en Ruby, mais ce n'est pas un code extrêmement complexe. Le script Ruby a:

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'ai une option de ligne de commande (-updateVersion) qui appelle updateVersion pour l'outil.

Enfin, je vais à la tête Git et crée un script exécutable dans .git/hooks/pre-commit.

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

À chaque enregistrement, la variable MYVERSION est mise à jour en fonction du nombre de commits.

9

Une chose qui est faite avec les référentiels Git consiste à utiliser l'objet tag. Ceci peut être utilisé pour baliser un commit avec n'importe quel type de chaîne et pour marquer des versions. Vous pouvez voir ces balises dans un référentiel avec la commande git tag, qui renvoie toutes les balises.

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

git checkout -b v1.1

Comme il s'agit d'un objet de niveau supérieur, vous verrez tout l'historique de cette validation, ainsi que vous pourrez exécuter des diffs, apporter des modifications et fusionner.

De plus, 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.

8
Abizern

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

8
Keltia

Si vous voulez simplement que les gens sachent à quel point ils sont périmés, Git peut les en informer de plusieurs manières assez simples. Ils comparent par exemple les dates du dernier commit sur leur coffre et votre coffre. Ils peuvent utiliser git cherry pour voir combien de commits se sont produits dans votre coffre et 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 m'embêterais pas à faire preuve de courtoisie envers qui que ce soit, à moins que vous ne soyez sûr qu'ils le souhaitent. :)

4
skiphoppy

Les identifiants RCS sont intéressants pour les projets à fichier unique, mais pour tout autre projet, $ Id $ ne dit rien sur le projet (à moins que vous n'imposiez des vérifications factices à un fichier de version factice).

Cela dit, on peut être intéressé par l’obtention des équivalents $ Author $, $ Date $, $ Revision $, $ RCSfile $, etc. au niveau des fichiers ou au niveau de la validation (comment les placer là où certains mots-clés sont précisés). question). Je n'ai pas de réponse à cela, mais je vois l'obligation de les mettre à jour, en particulier lorsque les fichiers (maintenant dans Git) proviennent de systèmes compatibles avec RCS (CVS).

De tels mots-clés peuvent être intéressants si les sources sont distribuées séparément de tout référentiel Git (c'est ce que je fais aussi). Ma solution est comme ça:

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 numéro .version, un descripteur de version Git (comme git describe) et un numéro de build monotone dans .build (plus hôte et date) dans un fichier source généré automatiquement et lié au programme final vous pouvez trouver de quelle source et quand il a été construit.

Je développe de nouvelles fonctionnalités dans des branches distinctes et la première chose que je fais est d’ajouter n (pour "next") à la chaîne .version (plusieurs branches provenant de la même racine utiliseraient le même numéro temporaire .version). Avant la publication, je décide quelles branches fusionner (j'espère que toutes auront le même .version). Avant de valider la fusion, je mets à jour .version vers le numéro suivant (mise à jour majeure ou mineure, en fonction des fonctionnalités fusionnées).

3
U. Windl

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

Commencez par récupérer les modifications dans l'Origine distant, mais ne les fusionnez pas dans votre branche master:

% git fetch

Ensuite, obtenez un journal des modifications apportées à un fichier donné entre votre branche master et le Origin/master distant.

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

Cela vous donne les messages de journal de tous les commits qui se sont produits dans le référentiel distant depuis la dernière fusion de Origin/master dans votre master.

Si vous souhaitez simplement compter le nombre de modifications, transmettez-le à wc. Dis comme ça:

% git rev-list master..Origin/master foo.el | wc -l
3
Otto

Je suis d'accord avec ceux qui pensent que le remplacement de jeton 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 de vos sources au moment où la version est balisée.

1
Agustí Sánchez

Si vous voulez que les informations de commit de git accessibles dans votre code, alors vous avez faites une étape de pré-construction pour y arriver. En 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.h ressemblant à:

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

Ensuite, chaque fois que vous en avez besoin dans votre code #include "version.h" et faites référence à git_tag ou git_commit au besoin.

Et votre Makefile pourrait avoir quelque chose comme ceci:

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

Cela a l'avantage de:

  • obtenir les actuellement valeurs correctes pour this construire indépendamment de la création de branches, de la fusion, de la sélection de cerises et autres.

Cette implémentation de prepublish.sh a les inconvénients de:

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

Un amateur prebuild.sh qui pourrait éviter ces problèmes est considéré comme un exercice pour le lecteur.

0
Jesse Chisholm

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 passé par Lively il y a quelques jours, un paquet Emacs qui permet d'avoir des morceaux vivants de LISP Emacs dans votre document. Pour être honnête, je ne l'ai pas essayé, mais cela m'est venu à l'esprit en lisant ceci.

0
Amr Mostafa

Pour appliquer l’extension à tous les fichiers de tous les sous-répertoires du référentiel, ajoutez un fichier .gitattributes au répertoire de niveau supérieur du référentiel (c’est-à-dire où vous placeriez normalement le fichier .gitignore) contenant:

* ident

Pour que cela soit effectif, vous devez commencer par extraire efficacement le ou les 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 le fichier Objet blob avec $ Id :, suivi de l'objet blob hexadécimal de 40 caractères nom, suivi d’un signe dollar $ lors de votre départ. Toute séquence d'octets commençant with $ Id: et se termine par $ dans le fichier de la arborescence est remplacé par $ Id $ lors de l’enregistrement.

Cet identifiant change à chaque fois qu'une nouvelle version du fichier est validée.

0
Nagev

Je viens aussi de SCCS, RCS et CVS (%W% %G% %U%).

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

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 de GitHub puisse répondre à la question "Quelle version utilisez-vous?"

J'ai donc é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 des 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
0
Bradley Allen