Qual è l’equivalente Git per il numero di revisione?

Usiamo SVN al lavoro, ma per i miei progetti personali ho deciso di utilizzare Git. Così ho installato Git ieri, e mi chiedo quale sia l’equivalente del numero di revisione in Git .

Diciamo che lavoriamo sulla versione 3.0.8 e ogni correzione di bug ha il suo numero di revisione che possiamo usare quando parliamo di questa correzione di bug. Quindi, se taggo il codice in Git a 3.0.8, cosa posso usare come numero di revisione o qualche altro tipo di identificazione più dettagliato? Trovo che l’hash non sia così facile da usare per gli umani.

Buone o cattive notizie per te, che hash è il numero di revisione. Ho anche avuto problemi con questo quando ho fatto il passaggio da SVN a Git.

Puoi usare “tagging” in git per taggare una certa revisione come “release” per una versione specifica, rendendo più facile fare riferimento a quella revisione. Dai un’occhiata a questo post del blog .

La cosa fondamentale da capire è che git non può avere numeri di revisione – pensa alla natura decentralizzata. Se gli utenti A e B si stanno entrambi impegnando nei loro repository locali, come può git ragionevolmente assegnare un numero di revisione sequenziale? A non ha conoscenza di B prima di spingere / tirare le modifiche l’uno dell’altro.

Un’altra cosa da considerare è la ramificazione semplificata per i rami di bugfix:

Inizia con una versione 3.0.8. Quindi, dopo questa versione, fai questo:

git branch bugfixes308 

Questo creerà un ramo per i bugfix. Controlla il ramo:

 git checkout bugfixes308 

Ora apporta le eventuali modifiche al bugfix che desideri.

 git commit -a 

Impegnati e torna al ramo principale:

 git checkout master 

Quindi inserisci le modifiche dall’altro ramo:

 git merge bugfixes308 

In questo modo, hai un ramo di bugfix separato specifico per la versione, ma stai ancora trasferendo le modifiche al bugfix nel tuo trunk principale.

Con il moderno Git (1.8.3.4 nel mio caso) e non usando i rami che puoi fare:

 $ git rev-list --count HEAD 68 

Il comando git describe crea un nome leggibile un po ‘più umano che si riferisce a un commit specifico. Ad esempio, dalla documentazione:

Con qualcosa come git.git tree corrente, ottengo:

 [torvalds@g5 git]$ git describe parent v1.0.4-14-g2414721 

cioè l’attuale capo del mio ramo “genitore” è basato sulla v1.0.4, ma poiché ha un minimo di commit in più, descrive ha aggiunto il numero di commit aggiuntivi (“14”) e un nome di object abbreviato per il commit stesso (“2414721”) alla fine.

Finché si utilizzano tag con nome sensibile per etichettare versioni particolari, questo può essere considerato approssimativamente equivalente a un “numero di revisione” SVN.

Gli altri poster hanno ragione, non esiste un “numero di revisione”.

Penso che il modo migliore sia usare tag per “releases”!

Ma ho fatto uso di quanto segue per falsificare i numeri di revisione (solo per i client di vedere le revisioni e il progresso, in quanto volevano avere le stesse revisioni sempre più da git quanto a cui si usa sovversione).

Mostra la “revisione attuale” di “HEAD” è simulata usando questo:

git rev-list HEAD | wc -l

Ma cosa succede se il client mi dice che c’è un bug in “revisione” 1302?

Per questo ho aggiunto quanto segue alla sezione [alias] del mio ~ / .gitconfig:

show-rev-number = !sh -c 'git rev-list --reverse HEAD | nl | awk \"{ if(\\$1 == "$0") { print \\$2 }}\"'

usando git show-rev-number 1302 stamperà quindi l’ hash per la “revisione” 🙂

Ho fatto un post sul blog (in tedesco) su quella “tecnica” qualche tempo fa.

Git non ha lo stesso concetto di numeri di revisione come sovversione. Invece ogni snapshot dato con un commit è taggato da un checksum SHA1. Perché? Ci sono diversi problemi con un revno in esecuzione in un sistema di controllo della versione distribuito:

Innanzitutto, poiché lo sviluppo non è affatto lineare, l’attaccamento di un numero è piuttosto difficile come un problema da risolvere in un modo che soddisferà le vostre necessità di programmatore. Cercando di risolvere questo problema aggiungendo un numero potrebbe diventare rapidamente problematico quando il numero non si comporta come previsto.

In secondo luogo, i numeri di revisione possono essere generati su macchine diverse. Ciò rende la sincronizzazione dei numeri molto più difficile, soprattutto perché la connettività è a senso unico; potresti non avere nemmeno accesso a tutte le macchine che hanno il repository.

Terzo, in git, un po ‘pioniere dal sistema OpenCM ormai defunto, l’ identity framework di un commit (ciò che è il commit) è equivalente al suo nome (l’id SHA). Questo concetto di naming = identity è molto forte. Quando ti siedi con un nome di commit in mano identifica anche il commit in un modo indimenticabile. Questo a sua volta ti consente di ricontrollare tutti i tuoi commit alla prima iniziale per corruzione con il comando git fsck .

Ora, dato che abbiamo un DAG (Directed Acyclic Graph) delle revisioni e queste costituiscono l’albero attuale, abbiamo bisogno di alcuni strumenti per risolvere il tuo problema: come discriminare le diverse versioni. Innanzitutto, puoi omettere parte dell’hash se un determinato prefisso, 1516bd , identifica in modo univoco il tuo commit. Ma questo è anche piuttosto inventato. Invece, il trucco è usare tag e / o rami. Un tag o ramo è simile a un “stick giallo nota” che si allega a un dato commit SHA1-id. I tag sono, in sostanza, pensati per essere non-moving mentre un ramo si muoverà quando vengono fatti nuovi commit al suo HEAD. Ci sono modi per riferirsi a un commit attorno a un tag o ramo, vedere la pagina man di git-rev-parse.

Di solito, se hai bisogno di lavorare su un pezzo di codice specifico, quel pezzo è in fase di cambiamento e dovrebbe essere come un ramo con un nome di argomento detto. Creare molti rami (20-30 per programmatore non è inaudito, con alcuni 4-5 pubblicati su cui altri possono lavorare) è il trucco per git efficace. Ogni pezzo di lavoro dovrebbe iniziare come una propria filiale e quindi essere unito quando viene testato. I rami non pubblicati possono essere riscritti interamente e questa parte della storia distruttiva è una forza di git.

Quando il cambiamento viene accettato in master, si blocca e diventa un po ‘l’archeologia. A quel punto, puoi taggarlo, ma più spesso un riferimento al particolare commit è fatto in un bug tracker o in un tracker di errori tramite la sum sha1. I tag tendono ad essere riservati per i dump di versione e i punti di diramazione per i rami di manutenzione (per le vecchie versioni).

Se sei interessato, ho gestito i numeri di versione automaticamente dalle informazioni git qui sotto il formato

 ..-b 

dove build è il numero totale di commit. Vedrai il codice interessante nel Makefile . Ecco la parte rilevante per accedere alla parte diversa del numero di versione:

 LAST_TAG_COMMIT = $(shell git rev-list --tags --max-count=1) LAST_TAG = $(shell git describe --tags $(LAST_TAG_COMMIT) ) TAG_PREFIX = "latex-tutorial-v" VERSION = $(shell head VERSION) # OR try to guess directly from the last git tag #VERSION = $(shell git describe --tags $(LAST_TAG_COMMIT) | sed "s/^$(TAG_PREFIX)//") MAJOR = $(shell echo $(VERSION) | sed "s/^\([0-9]*\).*/\1/") MINOR = $(shell echo $(VERSION) | sed "s/[0-9]*\.\([0-9]*\).*/\1/") PATCH = $(shell echo $(VERSION) | sed "s/[0-9]*\.[0-9]*\.\([0-9]*\).*/\1/") # total number of commits BUILD = $(shell git log --oneline | wc -l | sed -e "s/[ \t]*//g") #REVISION = $(shell git rev-list $(LAST_TAG).. --count) #ROOTDIR = $(shell git rev-parse --show-toplevel) NEXT_MAJOR_VERSION = $(shell expr $(MAJOR) + 1).0.0-b$(BUILD) NEXT_MINOR_VERSION = $(MAJOR).$(shell expr $(MINOR) + 1).0-b$(BUILD) NEXT_PATCH_VERSION = $(MAJOR).$(MINOR).$(shell expr $(PATCH) + 1)-b$(BUILD) 

Una funzione di Bash:

 git_rev () { d=`date +%Y%m%d` c=`git rev-list --full-history --all --abbrev-commit | wc -l | sed -e 's/^ *//'` h=`git rev-list --full-history --all --abbrev-commit | head -1` echo ${c}:${h}:${d} } 

produce qualcosa di simile

 $ git_rev 2:0f8e14e:20130220 

Questo è

 commit_count:last_abbrev_commit:date_YYmmdd 

L’ hash SHA1 del commit è l’equivalente di un numero di revisione di Subversion.

Questo è quello che ho fatto nel mio makefile basato su altre soluzioni. Nota non solo questo fornisce al codice un numero di revisione, ma aggiunge anche l’hash che consente di ricreare la versione.

 # Set the source control revision similar to subversion to use in 'c' # files as a define. # You must build in the master branch otherwise the build branch will # be prepended to the revision and/or "dirty" appended. This is to # clearly ID developer builds. REPO_REVISION_:=$(shell git rev-list HEAD --count) BUILD_BRANCH:=$(shell git rev-parse --abbrev-ref HEAD) BUILD_REV_ID:=$(shell git rev-parse HEAD) BUILD_REV_ID_SHORT:=$(shell git describe --long --tags --dirty --always) ifeq ($(BUILD_BRANCH), master) REPO_REVISION:=$(REPO_REVISION_)_g$(BUILD_REV_ID_SHORT) else REPO_REVISION:=$(BUILD_BRANCH)_$(REPO_REVISION_)_r$(BUILD_REV_ID_SHORT) endif export REPO_REVISION export BUILD_BRANCH export BUILD_REV_ID 

Ho scritto alcune utility di PowerShell per recuperare le informazioni sulla versione da Git e semplificare il tagging

funzioni: Get-LastVersion, Get-Revision, Get-NextMajorVersion, Get-NextMinorVersion, TagNextMajorVersion, TagNextMinorVersion:

 # Returns the last version by analysing existing tags, # assumes an initial tag is present, and # assumes tags are named v{major}.{minor}.[{revision}] # function Get-LastVersion(){ $lastTagCommit = git rev-list --tags --max-count=1 $lastTag = git describe --tags $lastTagCommit $tagPrefix = "v" $versionString = $lastTag -replace "$tagPrefix", "" Write-Host -NoNewline "last tagged commit " Write-Host -NoNewline -ForegroundColor "yellow" $lastTag Write-Host -NoNewline " revision " Write-Host -ForegroundColor "yellow" "$lastTagCommit" [reflection.assembly]::LoadWithPartialName("System.Version") $version = New-Object System.Version($versionString) return $version; } # Returns current revision by counting the number of commits to HEAD function Get-Revision(){ $lastTagCommit = git rev-list HEAD $revs = git rev-list $lastTagCommit | Measure-Object -Line return $revs.Lines } # Returns the next major version {major}.{minor}.{revision} function Get-NextMajorVersion(){ $version = Get-LastVersion; [reflection.assembly]::LoadWithPartialName("System.Version") [int] $major = $version.Major+1; $rev = Get-Revision $nextMajor = New-Object System.Version($major, 0, $rev); return $nextMajor; } # Returns the next minor version {major}.{minor}.{revision} function Get-NextMinorVersion(){ $version = Get-LastVersion; [reflection.assembly]::LoadWithPartialName("System.Version") [int] $minor = $version.Minor+1; $rev = Get-Revision $next = New-Object System.Version($version.Major, $minor, $rev); return $next; } # Creates a tag with the next minor version function TagNextMinorVersion($tagMessage){ $version = Get-NextMinorVersion; $tagName = "v{0}" -f "$version".Trim(); Write-Host -NoNewline "Tagging next minor version to "; Write-Host -ForegroundColor DarkYellow "$tagName"; git tag -a $tagName -m $tagMessage } # Creates a tag with the next major version (minor version starts again at 0) function TagNextMajorVersion($tagMessage){ $version = Get-NextMajorVersion; $tagName = "v{0}" -f "$version".Trim(); Write-Host -NoNewline "Tagging next majo version to "; Write-Host -ForegroundColor DarkYellow "$tagName"; git tag -a $tagName -m $tagMessage } 

Ogni commit ha un hash unico. Oltre a questo non ci sono numeri di revisione in git. Dovrai taggarti da solo se vuoi più facilità d’uso.

Il problema con l’utilizzo dell’hash git come numero di build è che non sta aumentando monotonicamente. OSGi suggerisce di utilizzare una data / ora per il numero di build. Sembra che il numero di commit al ramo possa essere usato al posto del subversion o del numero di variazione forzata.

Vorrei solo prendere nota di un altro approccio ansible – e cioè usando git git-notes (1) , esistente sin dalla v 1.6.6 ( Nota per Self-Git ) (sto usando git versione 1.7.9.5).

Fondamentalmente, ho usato git svn per clonare un repository SVN con cronologia lineare (senza layout standard, senza rami, senza tag) e volevo confrontare i numeri di revisione nel repository git clonato. Questo clone git non ha tag di default, quindi non posso usare git describe . Probabilmente la strategia qui funzionerebbe solo per la storia lineare, non so come sarebbe andata a finire con le fusioni, ecc .; ma ecco la strategia di base:

  • Chiedi git rev-list per l’elenco di tutte le cronologie di commit
    • Poiché rev-list è di default in “ordine cronologico inverso”, useremo il suo --reverse per ottenere l’elenco dei commit ordinati dal più vecchio prima
  • Utilizzare la shell bash in
    • aumentare una variabile contatore su ogni commit come contatore di revisione,
    • generare e aggiungere una nota git “temporanea” per ogni commit
  • Quindi, sfoglia il registro utilizzando git log con --notes , che eseguirà anche il dump di una nota di commit, che in questo caso sarebbe il “numero di revisione”
  • Al termine, cancella le note temporanee ( NB: non sono sicuro che queste note siano state commesse o meno, in realtà non vengono visualizzate nello git status )

Innanzitutto, notiamo che git ha una posizione predefinita per le note, ma puoi anche specificare un riferimento per le note, che le memorizzerebbe in una directory diversa sotto .git ; per esempio, mentre sei in una cartella git repo, puoi chiamare git notes get-ref per vedere quale directory sarà:

 $ git notes get-ref refs/notes/commits $ git notes --ref=whatever get-ref refs/notes/whatever 

La cosa da notare è che se notes add con un --ref , devi anche usare di nuovo quel riferimento – altrimenti potresti ricevere errori come ” Nessuna nota trovata per l’object XXX … “.

Per questo esempio, ho scelto di chiamare il riferimento delle note “linrev” (per la revisione lineare) – questo significa anche che non è probabile che la procedura interferisca con le note già esistenti. Sto anche usando l’ --git-dir , dato che sono un newbie git , ho avuto qualche problema a capirlo – quindi mi piacerebbe “ricordare per dopo” :) ; e io uso anche --no-pager per sopprimere spawn di less quando si utilizza git log .

Quindi, assumendo che tu sia in una directory, con una sottocartella myrepo_git che è un repository git ; si potrebbe fare:

 ### check for already existing notes: $ git --git-dir=./myrepo_git/.git notes show # error: No note found for object 04051f98ece25cff67e62d13c548dacbee6c1e33. $ git --git-dir=./myrepo_git/.git notes --ref=linrev show # error: No note found for object 04051f98ece25cff67e62d13c548dacbee6c1e33. ### iterate through rev-list three, oldest first, ### create a cmdline adding a revision count as note to each revision $ ix=0; for ih in $(git --git-dir=./myrepo_git/.git rev-list --reverse HEAD); do \ TCMD="git --git-dir=./myrepo_git/.git notes --ref linrev"; \ TCMD="$TCMD add $ih -m \"(r$((++ix)))\""; \ echo "$TCMD"; \ eval "$TCMD"; \ done # git --git-dir=./myrepo_git/.git notes --ref linrev add 6886bbb7be18e63fc4be68ba41917b48f02e09d7 -m "(r1)" # git --git-dir=./myrepo_git/.git notes --ref linrev add f34910dbeeee33a40806d29dd956062d6ab3ad97 -m "(r2)" # ... # git --git-dir=./myrepo_git/.git notes --ref linrev add 04051f98ece25cff67e62d13c548dacbee6c1e33 -m "(r15)" ### check status - adding notes seem to not affect it: $ cd myrepo_git/ $ git status # # On branch master # nothing to commit (working directory clean) $ cd ../ ### check notes again: $ git --git-dir=./myrepo_git/.git notes show # error: No note found for object 04051f98ece25cff67e62d13c548dacbee6c1e33. $ git --git-dir=./myrepo_git/.git notes --ref=linrev show # (r15) ### note is saved - now let's issue a `git log` command, using a format string and notes: $ git --git-dir=./myrepo_git/.git --no-pager log --notes=linrev --format=format:"%h: %an: %ad: >>%s< < %N" HEAD # 04051f9: _user_: Sun Apr 21 18:29:02 2013 +0000: >>test message 15 < < (r15) # 77f3902: _user_: Sun Apr 21 18:29:00 2013 +0000: >>test message 14< < (r14) # ... # 6886bbb: _user_: Sun Apr 21 17:11:52 2013 +0000: >>initial test message 1< < (r1) ### test git log with range: $ git --git-dir=./myrepo_git/.git --no-pager log --notes=linrev --format=format:"%h: %an: %ad: >>%s< < %N" HEAD^..HEAD # 04051f9: _user_: Sun Apr 21 18:29:02 2013 +0000: >>test message 15 < < (r15) ### erase notes - again must iterate through rev-list $ ix=0; for ih in $(git --git-dir=./myrepo_git/.git rev-list --reverse HEAD); do \ TCMD="git --git-dir=./myrepo_git/.git notes --ref linrev"; \ TCMD="$TCMD remove $ih"; \ echo "$TCMD"; \ eval "$TCMD"; \ done # git --git-dir=./myrepo_git/.git notes --ref linrev remove 6886bbb7be18e63fc4be68ba41917b48f02e09d7 # Removing note for object 6886bbb7be18e63fc4be68ba41917b48f02e09d7 # git --git-dir=./myrepo_git/.git notes --ref linrev remove f34910dbeeee33a40806d29dd956062d6ab3ad97 # Removing note for object f34910dbeeee33a40806d29dd956062d6ab3ad97 # ... # git --git-dir=./myrepo_git/.git notes --ref linrev remove 04051f98ece25cff67e62d13c548dacbee6c1e33 # Removing note for object 04051f98ece25cff67e62d13c548dacbee6c1e33 ### check notes again: $ git --git-dir=./myrepo_git/.git notes show # error: No note found for object 04051f98ece25cff67e62d13c548dacbee6c1e33. $ git --git-dir=./myrepo_git/.git notes --ref=linrev show # error: No note found for object 04051f98ece25cff67e62d13c548dacbee6c1e33. 

Quindi, almeno nel mio caso specifico di cronologia completamente lineare senza rami, i numeri di revisione sembrano corrispondere a questo approccio - e inoltre, sembra che questo approccio consentirà l'uso di git log con intervalli di revisione, ottenendo comunque i numeri di revisione corretti - YMMV con un contesto diverso, sebbene ...

Spero che questo aiuti qualcuno,
Saluti!


EDIT: Ok, qui è un po 'più facile, con git alias per i loop sopra, chiamati setlinrev e unsetlinrev ; quando nella cartella del tuo repository git, fai ( nota la brutta fuga di bash , vedi anche # 16136745 - Aggiungi un alias Git contenente un punto e virgola ):

 cat >> .git/config < <"EOF" [alias] setlinrev = "!bash -c 'ix=0; for ih in $(git rev-list --reverse HEAD); do \n\ TCMD=\"git notes --ref linrev\"; \n\ TCMD=\"$TCMD add $ih -m \\\"(r\\$((++ix)))\\\"\"; \n\ #echo \"$TCMD\"; \n\ eval \"$TCMD\"; \n\ done; \n\ echo \"Linear revision notes are set.\" '" unsetlinrev = "!bash -c 'ix=0; for ih in $(git rev-list --reverse HEAD); do \n\ TCMD=\"git notes --ref linrev\"; \n\ TCMD=\"$TCMD remove $ih\"; \n\ #echo \"$TCMD\"; \n\ eval \"$TCMD 2>/dev/null\"; \n\ done; \n\ echo \"Linear revision notes are unset.\" '" EOF 

... quindi puoi semplicemente invocare git setlinrev prima di provare a fare il log che coinvolge le note di revisione lineari; e git unsetlinrev per eliminare quelle note quando hai finito; un esempio dalla directory git repo:

 $ git log --notes=linrev --format=format:"%h: %an: %ad: >>%s< < %N" HEAD^..HEAD 04051f9: _user_: Sun Apr 21 18:29:02 2013 +0000: >>test message 15 < < $ git setlinrev Linear revision notes are set. $ git log --notes=linrev --format=format:"%h: %an: %ad: >>%s< < %N" HEAD^..HEAD 04051f9: _user_: Sun Apr 21 18:29:02 2013 +0000: >>test message 15 < < (r15) $ git unsetlinrev Linear revision notes are unset. $ git log --notes=linrev --format=format:"%h: %an: %ad: >>%s< < %N" HEAD^..HEAD 04051f9: _user_: Sun Apr 21 18:29:02 2013 +0000: >>test message 15 < < 

Il tempo impiegato dalla shell per completare questi alias dipende dalla dimensione della cronologia del repository.

Per le persone che hanno un processo di build Ant , puoi generare un numero di versione per un progetto su git con questa destinazione:

                  Revision : ${version.revision}      Hash : ${version.hash}      Branch : ${version.branch}          Date : ${version.date}  Version : ${version} version = ${version}  

Il risultato è simile a questo:

 generate-version: [echo] Generate version [echo] Revision : 47 [echo] Hash : 2af0b99 [echo] Branch : master [echo] Date : 2015-04-20.15:04:03 [echo] Version : 47.2af0b99.master-dirty.2015-04-20.15:04:03 

Il flag dirty è qui quando i file non vengono impegnati quando si genera il numero di versione. Perché di solito, quando costruisci / pacchetti la tua applicazione, ogni modifica del codice deve essere nel repository.

Insieme all’ID SHA-1 del commit, la data e l’ora del tempo del server avrebbero aiutato?

Qualcosa come questo:

il commit è avvenuto alle 11:30:25 del 19 agosto 2013 come 6886bbb7be18e63fc4be68ba41917b48f02e09d7_19aug2013_113025

Dal manuale Git, i tag sono una brillante risposta a questo problema:

Creare un tag annotato in Git è semplice. Il modo più semplice è specificare -a quando si esegue il comando tag:

$ git tag -a v1.4 -m 'my version 1.4'

 $ git tag v0.1 v1.3 v1.4 

Scopri 2.6 Nozioni di base su Git – Tagging

Dopo aver ricercato a lungo i repository online ho scoperto che logicamente non c’è differenza tra un numero di revisione e un numero di commit in Git.