Altro
Cos'è git tag, come creare tag & come fare il checkout dei tag remoti di git
quando faccio il checkout del tag git remoto uso un comando come questo:
git checkout -b local_branch_name origin/remote_tag_name
Ho ottenuto un errore come questo:
error: pathspec `origin/remote_tag_name` did not match any file(s) known to git.
Posso trovare remote_tag_name quando uso il comando git tag.
467
3
Cominciamo a spiegare cos'è un tag in git
Un tag è usato per etichettare e contrassegnare uno specifico commit nella storia.
Di solito è usato per contrassegnare i punti di rilascio (es. v1.0, ecc.).
Sebbene un tag possa apparire simile ad un ramo, un tag, tuttavia, non cambia.
Punta direttamente ad un specifico commit nella storia.
Non sarai in grado di fare il checkout dei tag se non è localmente nel tuo repository, quindi prima devi "recuperare" i tag nel tuo repository locale.
Prima di tutto, assicurati che il tag esista localmente facendo
Poi controlla il tag eseguendo
Invece di
origin
usa il prefissotags/
.In questo esempio hai 2 tag versione 1.0 & versione 1.1 puoi controllarli con uno dei seguenti:
Tutti i precedenti faranno lo stesso, poiché il tag è solo un puntatore a un dato commit.
Come vedere l'elenco di tutti i tag?
Come creare i tag?
Ci sono 2 modi per creare un tag:
La differenza tra i 2 è che quando si crea un tag annotato si possono aggiungere metadati come in un commit git:
nome, e-mail, data, commento & firma
Come cancellare i tag?
Come clonare un tag specifico?
Per prendere il contenuto di un dato tag puoi usare il comando
checkout
.Come spiegato sopra i tag sono come qualsiasi altro commit, quindi possiamo usare
checkout
e invece di usare lo SHA-1 sostituirlo semplicemente con tag_nameOpzione 1:
Opzione 2:
Usando il comando clone
Dato che git supporta shallow clone aggiungendo il
--branch
al comando clone possiamo usare il nome del tag invece del nome del ramo. Git sa come "tradurre" lo SHA-1 dato al relativo commitCome spingere i tag?
`
git push --tags
Per spingere tutti i tag:
Per spingere i tag annotati e i tag della catena della storia corrente usa::
`
git push --follow-tags
Questo flag
--follow-tags
spinge sia i commits che i soli tag che sono entrambi:Da Git 2.4 puoi impostarlo usando la configurazione
(Questa risposta ha richiesto un po' di tempo per essere scritta, e la risposta di codeWizard's è corretta nello scopo e nell'essenza, ma non del tutto completa, quindi la posterò comunque).
Non esiste un "tag Git remoto". Ci sono solo "tag". Faccio notare tutto questo non per essere pedante,1 ma perché c'è molta confusione su questo con gli utenti occasionali di Git, e la documentazione di Git non è molto utile2 ai principianti. (Non è chiaro se la confusione viene a causa della scarsa documentazione, o la scarsa documentazione viene perché questo è intrinsecamente un po' confuso, o cosa). Ci sono "rami remoti", più propriamente chiamati "rami di tracciamento remoto", ma vale la pena notare che questi sono in realtà entità locali. Non ci sono tag remoti, però (a meno che non li si (ri)inventi). Ci sono solo tag locali, quindi è necessario ottenere il tag localmente per poterlo utilizzare. La forma generale per i nomi per specifici commit - che Git chiama references - è una qualsiasi stringa che inizia con
refs/
. Una stringa che inizia conrefs/heads/
nomina un ramo; una stringa che inizia conrefs/remotes/
nomina un ramo con tracciamento remoto; e una stringa che inizia conrefs/tags/
nomina un tag. Il nomerefs/stash
è il riferimento allo stash (come usato dagit stash
; nota la mancanza di una barra finale). Ci sono alcuni nomi speciali insoliti che non iniziano conrefs/
:HEAD
,ORIG_HEAD
,MERGE_HEAD
, eCHERRY_PICK_HEAD
in particolare sono tutti nomi che possono riferirsi a specifici commit (anche seHEAD
normalmente contiene il nome di un ramo, cioè contieneref: refs/heads/branch
). Ma in generale, i riferimenti iniziano conrefs/
. Una cosa che Git fa per rendere questo confuso è che ti permette di omettere ilrefs/
, e spesso la parola dopo ilrefs/
. Per esempio, puoi omettererefs/heads/
orefs/tags/
quando ti riferisci ad un ramo locale o ad un tag - e infatti devi omettererefs/heads/
quando fai il check-out di un ramo locale! Puoi farlo ogni volta che il risultato non è ambiguo, o - come abbiamo appena notato - quando devi farlo (pergit checkout branch
). È vero che i riferimenti esistono non solo nel proprio repository, ma anche in repository remoti. Tuttavia, Git ti dà accesso ai riferimenti di un repository remoto solo in momenti molto specifici: cioè, durante le operazioni difetch
epush
. Puoi anche usaregit ls-remote
ogit remote show
per vederli, mafetch
epush
sono i punti di contatto più interessanti.Refspecs
Durante il
fetch
e ilpush
, Git usa delle stringhe che chiama refspecs per trasferire i riferimenti tra il repository locale e quello remoto. Quindi, è in questi momenti, e attraverso le refspecs, che due repository Git possono essere sincronizzati tra loro. Una volta che i vostri nomi sono sincronizzati, potete usare lo stesso nome che qualcuno con il remoto usa. C'è qualche magia speciale qui sufetch
, però, e riguarda sia i nomi dei rami che i nomi dei tag. Dovresti pensare agit fetch
come se dirigessi il tuo Git a richiamare (o forse a mandare un messaggio di testo) un altro Git-il "remote"-e avere una conversazione con esso. All'inizio di questa conversazione, il remoto elenca tutti i suoi riferimenti: tutto inrefs/heads/
e tutto inrefs/tags/
, insieme a qualsiasi altro riferimento che ha. Il tuo Git fa una scansione di questi e (basandosi sulla solita fetch refspec) rinomina i loro rami. Diamo un'occhiata al normale refspec per il remoto chiamatoorigin
:Questo refspec istruisce il tuo Git a prendere ogni nome che corrisponde a
refs/heads/*
- cioè, ogni ramo sul remoto - e cambiare il suo nome inrefs/remotes/origin/*
, cioè, mantenere la parte corrispondente allo stesso, cambiando il nome del ramo (refs/heads/
) in un nome di ramo che traccia il remoto (refs/remotes/
, in particolare,refs/remotes/origin/
). È attraverso questo refspec che i rami diorigin
'diventano i tuoi rami di tracciamento remoto per il remotoorigin
. Il nome del ramo diventa il nome del ramo di tracciamento remoto, con il nome del remoto, in questo casoorigin
, incluso. Il segno più+
davanti al refspec imposta il flag "force", cioè, il tuo ramo di remote-tracking sarà aggiornato per corrispondere al nome del ramo remoto, indipendentemente da ciò che serve per farlo corrispondere. (Senza il+
, gli aggiornamenti del ramo sono limitati alle modifiche "fast forward" e gli aggiornamenti dei tag sono semplicemente ignorati dalla versione 1.8.2 di Git o giù di lì - prima di allora si applicavano le stesse regole di fast-forward).Tag
Ma che dire dei tag? Non c'è un refspec per loro, almeno non di default. Puoi impostarne uno, nel qual caso la forma del refspec dipende da te; oppure puoi eseguire
git fetch --tags
. Usare--tags
ha l'effetto di aggiungererefs/tags/*:refs/tags/*
al refspec, cioè, porta sopra tutti i tag (ma non aggiorna il tuo tag se hai già un tag con quel nome, a prescindere da ciò che dice il tag del remoto' Edit, Jan 2017: a partire da Git 2.10, i test mostrano che--tags
aggiorna forzatamente i tuoi tag dai tag remoti, come se la refspec leggesse+refs/tags/*:refs/tags/*
; questa potrebbe essere una differenza di comportamento da una versione precedente di Git). Nota che non c'è nessuna ridenominazione qui: se il remotoorigin
ha il tagxyzzy
, e tu no, e tugit fetch origin "refs/tags/*:refs/tags/*"
, avrairefs/tags/xyzzy
aggiunto al tuo repository (che punta allo stesso commit del remoto). Se usi+refs/tags/*:refs/tags/*
allora il tuo tagxyzzy
, se ne hai uno, viene sostituito da quello diorigin
. Cioè, il flag di forza+
su un refspec significa "sostituisci il valore del mio riferimento'con quello che il mio Git riceve dal loro Git".Tag automatici durante il fetch
Per ragioni storiche,3 se non usi né l'opzione
--tags
né l'opzione--no-tags
,git fetch
compie azioni speciali. Ricorda che abbiamo detto sopra che il remoto inizia mostrando al tuo Git locale tutti i suoi riferimenti, che il tuo Git locale voglia vederli o meno.4 Il tuo Git prende nota di tutti i tag che vede a questo punto. Poi, mentre inizia a scaricare qualsiasi oggetto commit di cui ha bisogno per gestire qualsiasi cosa stia recuperando, se uno di quei commit ha lo stesso ID di uno di quei tag, git aggiungerà quel tag - o quei tag, se più tag hanno quell'ID - al tuo repository; Modifica, gennaio 2017: i test mostrano che il comportamento in Git 2.10 è ora: Se il loro Git fornisce un tag chiamato T, e tu non hai un tag chiamato T, e l'ID di commit associato a T è un antenato di uno dei loro rami che il tuogit fetch
sta esaminando, il tuo Git aggiunge T ai tuoi tag con o senza--tags
. L'aggiunta di--tags
fa sì che il tuo Git ottenga tutti i loro tag, e forzi l'aggiornamento.Linea di fondo
Potresti dover usare
git fetch --tags
per ottenere i loro tag. Se i loro nomi di tag sono in conflitto con i tuoi nomi di tag esistenti, potresti (a seconda della versione di Git) anche dover cancellare (o rinominare) alcuni dei tuoi tag, e poi eseguiregit fetch --tags
, per ottenere i loro tag. Poiché i tag - a differenza dei rami remoti - non hanno una ridenominazione automatica, i tuoi nomi di tag devono corrispondere ai loro nomi di tag, ed è per questo che puoi avere problemi di conflitti. Nella maggior parte dei casi normali, comunque, un semplicegit fetch
farà il lavoro, portando i loro commit e i loro tag corrispondenti, e poiché loro - chiunque essi siano - etichetteranno i commit nel momento in cui li pubblicano, tu sarai al passo con i loro tag. Se non crei i tuoi propri tag, né mischi i loro repository con altri repository (tramite telecomandi multipli), non avrai nemmeno collisioni di nomi di tag, quindi non dovrai preoccuparti di cancellare o rinominare i tag per ottenere i loro tag.Quando hai bisogno di nomi qualificati
Ho detto sopra che puoi omettere
refs/
quasi sempre, erefs/heads/
erefs/tags/
e così via la maggior parte delle volte. Ma quando non si può? La risposta completa (o quasi) è nella documentazione digitrevisions
. Git risolverà un nome in un ID di commit usando la sequenza di sei passi data nel link. Curiosamente, i tag sovrascrivono i rami: se c'è un tagxyzzy
e un ramoxyzzy
, e puntano a commit diversi, allora:ti darà l'ID a cui punta il tag. Tuttavia - e questo è ciò che manca a
gitrevisions
-git checkout
preferisce i nomi dei rami, quindigit checkout xyzzy
ti metterà sul ramo, ignorando il tag. In caso di ambiguità, puoi quasi sempre scrivere il nome del ref usando il suo nome completo,refs/heads/xyzzy
orefs/tags/xyzzy
. (Nota che questo funziona congit checkout
, ma in un modo forse inaspettato:git checkout refs/heads/xyzzy
provoca un checkout detached-HEAD piuttosto che un checkout del ramo. Questo è il motivo per cui devi solo notare chegit checkout
userà prima il nome breve come nome del ramo: è così che si fa il checkout del ramoxyzzy
anche se il tagxyzzy
esiste. Se vuoi fare il checkout del tag, puoi usarerefs/tags/xyzzy
). Poiché (come notagitrevisions
) Git proveràrefs/name
, puoi anche semplicemente scriveretags/xyzzy
per identificare il commit con tagxyzzy
. (Se qualcuno è riuscito a scrivere un riferimento valido chiamatoxyzzy
in$GIT_DIR
, tuttavia, questo si risolverà come$GIT_DIR/xyzzy
. Ma normalmente solo i vari nomi*HEAD
dovrebbero essere in$GIT_DIR
).11Ok, ok, "non solo per essere pedante". :-) 22Alcuni direbbero "molto poco utile", e tenderei ad essere d'accordo, in effetti. Fondamentalmente,
git fetch
, e l'intero concetto di remote e refspecs, è stato un po' un'aggiunta tardiva a Git, avvenuta intorno al tempo di Git 1.5. Prima di allora c'erano solo alcuni casi speciali ad-hoc, e il tag-fetching era uno di questi, quindi è stato introdotto tramite codice speciale. 44Se aiuta, pensa al Git remoto come ad un flasher, nel significato gergale.Per ottenere il codice specifico del tag prova a creare un nuovo ramo e aggiungi il codice del tag in esso. L'ho fatto con il comando:
$git checkout -b newBranchName tagName
.