Come si ottiene uno schema numerico di versioning con Git?


131

La mia organizzazione sta valutando di passare da SVN a Git. Un argomento contro lo spostamento è il seguente:

Come facciamo il versioning?

Abbiamo una distribuzione SDK basata sulla piattaforma NetBeans. Poiché le revisioni SVN sono numeri semplici, possiamo usarle per estendere i numeri di versione dei nostri plugin e build SDK. Come possiamo gestirlo quando ci spostiamo su Git?

Possibili soluzioni:

  • Usando il numero di build di Hudson (Problema: devi controllare Hudson per correlarlo a una versione Git effettiva)
  • Aumentare manualmente la versione per notte e stabile (Problema: curva di apprendimento, errore umano)

Se qualcun altro ha riscontrato un problema simile e lo ha risolto, ci piacerebbe sapere come.


3
Potresti convincere il tuo server hudson (non jenkins ?) Ad aggiungere automaticamente un gittag dopo ogni build riuscita? Ciò avrebbe l'ulteriore vantaggio di chiarire quali gitcommit hanno problemi di build o test di errori, poiché rimarrebbero senza tag.
Mark Booth,


Come nota a margine, puoi aggiungere il numero di build al tag monitorando i tempi di build .
Shahbaz,

Non sei sicuro che sia una soluzione praticabile, ma che ne dici di esportare da git a un repository svn subito prima di ogni build? Quindi costruisci semplicemente dal repository svn - se centralizzato è ciò che vogliamo, usa invece quello.
Jonny il

Risposte:


152

Usa i tag per contrassegnare i commit con i numeri di versione:

git tag -a v2.5 -m 'Version 2.5'

Push tag upstream: ciò non avviene per impostazione predefinita:

git push --tags

Quindi utilizzare il comando descrivi :

git describe --tags --long

Questo ti dà una stringa del formato:

v2.5-0-gdeadbee
^    ^ ^^
|    | ||
|    | |'-- SHA of HEAD (first seven chars)
|    | '-- "g" is for git
|    '---- number of commits since last tag
|
'--------- last tag

Accetto: dovrebbe essere facile automatizzare la numerazione dei tag notturni se necessario e la promozione a stable è comunque manuale.
Inutile

20
Piccolo miglioramento: git describe --long --tags --dirty --always. 'Dirty' ti dirà se ci sono stati cambiamenti locali quando è stato fatto il 'descrivi' (il che significa che non può descrivere completamente lo stato del repository). "Sempre" significa che non verrà visualizzato un errore quando non sono presenti tag. Il fallback sarà solo un hash di commit. Quindi puoi ottenere 76001f2-dirtycome esempio. Ovviamente, vedere "sporco" significa che qualcuno ha incasinato.
Mike Weller,

1
Come può funzionare quando il tag viene generato per ultimo . Normalmente vuoi che le build in futuro abbiano la prossima versione del tuo prodotto. Ma saranno sempre costretti a usare l' ultima versione in questo caso. Solo la build finale spedita avrà il numero corretto.
void.pointer

@ void.pointer: Certo, questo numero di versione risponde alla domanda "su quale versione è stato basato questo commit?" non "in quale versione si troverà questo commit?" Tuttavia, sei libero di interpretare i tag in modo diverso. Ad esempio, se tagghi HEADcome v2.5, puoi anche interpretarlo come l' inizio del ciclo di rilascio 2.5, quindi taggare v2.5-releaseo quello che ti piace.
Jon Purdy,

8
Un altro piccolo miglioramento. Se si desidera avere anche altri tag, ma utilizzare un tag con motivi specifici per la generazione di revisioni, è possibile utilizzare l' --matchopzione in questo modo:git describe --long --tags --dirty --always --match 'v[0-9]\.[0-9]'
Alexander Amelkin,

42

Questo è emerso per alcuni progetti per me. La migliore soluzione che ho avuto finora è quella di generare un numero di versione come questo:

xy <numero di commit> .r <git-hash>

In genere, viene generato dal nostro sistema di compilazione utilizzando una combinazione di alcuni file o tag statici per ottenere i principali numeri di revisione git rev-list HEAD | wc -l(che era più veloce dell'uso git log) e git rev-parse HEAD. Il ragionamento è stato il seguente:

  1. Avevamo bisogno della possibilità che la versione di alto livello avvenga esplicitamente (iexy)
  2. Quando avveniva uno sviluppo parallelo, non dovevamo MAI generare lo stesso numero di versione.
  3. Volevamo rintracciare facilmente la provenienza di una versione.
  4. Quando le linee parallele sono state unite, volevamo che la nuova versione si risolvesse più in alto di uno dei rami.

Il numero 2 è invisibile per la maggior parte delle persone, ma è davvero importante e molto difficile con il controllo del codice sorgente distribuito. SVN aiuta con questo dandoti un singolo numero di revisione. Si scopre che un conteggio dei commit è il più vicino possibile, risolvendo magicamente anche il n. 4. In presenza di rami, questo non è ancora unico, nel qual caso aggiungiamo l'hash, che risolve ordinatamente anche il n. 3.

La maggior parte di ciò consisteva nell'accomodare la distribuzione tramite il pip di Python. Ciò ha garantito che pip installsarebbe forse un po 'strano durante lo sviluppo parallelo (vale a dire che i pacchetti di persone di rami diversi si mescolerebbero, ma in modo deterministico), ma che dopo le fusioni tutto si sarebbe risolto. Escludendo la presenza di un rebase esposto o di una modifica, questo ha funzionato abbastanza bene per i requisiti di cui sopra.

Nel caso te lo stia chiedendo, abbiamo scelto di mettere la r davanti all'hash a causa di qualche stranezza con il modo in cui la confezione di Python gestisce le lettere nei numeri di versione (ovvero ae sono inferiori a 0, il che renderebbe "1.3.10.a1234" < "1.3.10" <"1.3.10.1234").


1
a proposito, come hai affrontato il problema dell'uovo di gallina nel determinare l'hash git prima di registrarlo? Hai usato qualche forma di .gitignore o qualche altro trucco?
kfmfe04,

3
Non l'ho fatto Non uso l'hash fino al momento della creazione del pacchetto, che è molto tempo dopo il check-in. Lingue diverse hanno diversi modi per iniettare questo. Per Python, utilizzo './setup.py egg_info -b ". $ {BUILD_VERSION}" sdist ". Per C e C ++, definisco una macro in fase di compilazione con 'CFLAGS = -D "$ {BUILD_VERSION}"'. Per Go, definisco un simbolo al momento del collegamento con 'go install -ldflags appmodule.BuildVersion "-X. $ {BUILD_VERSION}"'.
Jayson,

1
Questa dovrebbe essere la risposta migliore.
alvinabad,

risposta molto buona
haelix,

9

Questo potrebbe essere un po 'eccessivo, ma ti farò sapere come lo facciamo.

Usiamo una struttura di ramificazione molto simile a questa .

Hudson costruisce i nostri rami "sviluppa" e incrementa i numeri di build a partire da 0. Il numero di build è univoco per ciascun progetto e viene taggato nel controllo della versione. Il motivo è che puoi dire esattamente da quale derivazione la build 42 del ramo di sviluppo, ad esempio (ogni progetto può avere più rami di sviluppo in parallelo, perché ogni progetto può avere diversi team che lavorano su diversi aspetti del progetto).

Quando decidiamo che una determinata build è abbastanza buona per essere rilasciata, il commit che ha innescato quella build viene taggato con un numero di versione di rilascio, che viene deciso dal marketing. Ciò significa che i team di sviluppo non si preoccupano di quale sia il numero della versione finale e che il marketing è libero di mescolare i numeri di versione come meglio crede. Il numero di versione finale e il numero di build sono entrambi presenti nel prodotto rilasciato.

Esempio: 2.1.0 build 1337

Ciò significa che, per una specifica versione del prodotto, è possibile sapere quale è stata l'ultima squadra che ha lavorato su di essa e si può interrogare git per tutti i commit che hanno portato alla versione per diagnosticare un problema, se necessario.


8

Le versioni vengono identificate come hash degli hash SHA1 di tutti i file nella struttura di directory memorizzata al momento del check-in. Questo hash viene archiviato accanto agli hash dei check-in padre in modo che sia possibile leggere l'intera cronologia.

Dai un'occhiata al processo di utilizzo di 'git-descritto' tramite GIT-VERSION-GEN e come puoi aggiungerlo tramite il tuo processo di compilazione quando tagghi la tua versione.

Ecco un bel blog che fornisce un esempio di come ottenere ciò che desideri:

http://cd34.com/blog/programming/using-git-to-generate-an-automatic-version-number/


0

Jon Purdy ha l'idea giusta. git flowsemplifica anche la gestione effettiva di queste filiali e la gestione delle filiali è un argomento a cui rivolgersi git.

Cominciamo con una carrellata di base git, dal momento che si sta venendo dal svn-a- gitprospettiva. Considerare gitquanto segue:

master--...............-.....-..............-
        \             /     /              /
         ---develop---------............../
                            \            /
                             --feature---

Sopra, si ramifica masterin develop(indicato da \) e si ramifica developin un featureramo. Uniamo i rami di backup (indicato da /), con commit ( -) lungo un ramo. (Se non c'è nessun commit ma l'unione è a destra, ci sono degli .indicatori per mostrare che il prossimo -è il prossimo commit).

Abbastanza facile. E se avessimo un hotfix nella nostra versione principale?

master--...............-.....-................-...........-.........-
        \             /     /                / \         /|        /
         \           /     /                /   -hotfix-- V       /
          ---develop---------............../..............-...----
                             \            / \             V   /
                              --feature---   --feature2...----

Sopra, developramificato da master. Il bug scoperto in masterveniva corretto ramificandosi master, risolvendolo e ricongiungendosi master. Ci siamo quindi uniti masterin develop, e poi developinfeature2 , che ha rotolato il nuovo codice da hotfixquesti rami.

Quando feature2torni a develop, la sua cronologia include developcon hotfix. Allo stesso modo, developviene unito feature2al nuovo codice da master, quindi la fusione di developnuovo masteravverrà senza intoppi, dato che si basa su quel commit in masterquel momento, come se da quel momento ti fossi ramificato master.

Quindi ecco un altro modo per farlo.

master--..........-........-
        \        /\       /
         ---1.0--  --1.1-- 

I suoi 1.0 release ottenere tagged- 1.0.1, 1.0.2, 1.0.3, e così via.

Ora ecco un trucco: hai trovato un bug in 1.0 e riguarda 1.1, 1.2 e 1.3. cosa fai?

Si ramifica la versione più recente o la prima mantenuta e la si corregge. Poi si unisce la nuova hotfixfiliale in 1.3-e in 1.2, 1.1e 1.0. Non diramare da ciascuno dei rami della versione di manutenzione; Non unire 1.0in mastero unire masternuovamente dentro 1.0. Prendi un hotfixramo e uniscilo in tutti i rami della versione. Se ci sono conflitti, te lo dirà; rivedi il tuo codice per assicurarti che le modifiche siano corrette ( git diffè tuo amico).

Ora quel cambiamento specifico è applicato ovunque. Il lignaggio è ramificato, ma va bene. Non è casuale. Contrassegnare la 1.3testina come 1.3.17, unirla in ogni feature in progress derivata 1.3e andare avanti.

L' git flowestensione aiuta a gestire questi rami di manutenzione, funzionalità e hotfix per te. Una volta ridotto il flusso di lavoro, questo è banale e risolve enormemente la gestione del codice sorgente.

Ho visto questo fatto nei team di programmazione, ma non ho lavorato così profondamente come programmatore, quindi mi sto ancora concentrando sul flusso di lavoro quotidiano.


-6

Pro Git nella sezione 7.2 "Attributi Git" nella parte di espansione "Parola chiave" contiene un bell'esempio di utilizzo di filtri sfumati e puliti per generare parole chiave in stile RCS. Puoi usare la stessa tecnica per incorporare una stringa di una versione nel codice, formattata e calcolata secondo le tue regole . È comunque possibile utilizzare git describecome un punto fisso, ma si ha la possibilità di trasformare a qualsiasi forma più appropriata e ottenere da v2.5-14-feebdaed, per esempio, pulito 2.5.14


9
-1 per aver rovinato una buona risposta con attacchi completamente non richiamati per gli annunci domestici.
Jörg W Mittag,

9
Chi può dire che sono stati i ragazzi git che ti hanno votato. Potrebbero essere facilmente le persone che preferiscono un po 'di civiltà .
Mark Booth,

Cordiali saluti, ho appena modificato la risposta.
Keith Thompson,

git describegenera il nome del tag a meno che non --longvenga passato o non ci siano commit dall'ultimo tag, quindi è già perfettamente pulito. Se non avessi modificato le impostazioni predefinite, ti avrebbe dato esattamente quello che volevi.
Strcat,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.