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.
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
# --all will fetch all the remotes.
# --tags will fetch all tags as well
git fetch --all --tags --prune
Poi controlla il tag eseguendo
git checkout tags/<tag_name> -b <branch_name>
Invece di origin
usa il prefisso tags/
.
In questo esempio hai 2 tag versione 1.0 & versione 1.1 puoi controllarli con uno dei seguenti:
git checkout A ...
git checkout version 1.0 ...
git checkout tags/version 1.0 ...
Tutti i precedenti faranno lo stesso, poiché il tag è solo un puntatore a un dato commit.
origine: https://backlog.com/git-tutorial/img/post/stepup/capture_stepup4_1_1.png
# list all tags
git tag
# list all tags with given pattern ex: v-
git tag --list 'v-*'
Ci sono 2 modi per creare un tag:
# lightweight tag
git tag
# annotated tag
git tag -a
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
# delete any given tag
git tag -d <tag name>
# Don't forget to remove the deleted tag form the server with push tags
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_name
Opzione 1:
# Update the local git repo with the latest tags from all remotes
git fetch --all
# checkout the specific tag
git checkout tags/<tag> -b <branch>
Opzione 2:
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 commit
# Clone a specific tag name using git clone
git clone <url> --branch=<tag_name>
git clone --branch=
--branch
può anche prendere i tag e stacca l'HEAD a quel commit nel repository risultante.
git push --tags
Per spingere tutti i tag:
git push --tags
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
git config --global push.followTags true
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 con refs/heads/
nomina un ramo; una stringa che inizia con refs/remotes/
nomina un ramo con tracciamento remoto; e una stringa che inizia con refs/tags/
nomina un tag. Il nome refs/stash
è il riferimento allo stash (come usato da git stash
; nota la mancanza di una barra finale).
Ci sono alcuni nomi speciali insoliti che non iniziano con refs/
: HEAD
, ORIG_HEAD
, MERGE_HEAD
, e CHERRY_PICK_HEAD
in particolare sono tutti nomi che possono riferirsi a specifici commit (anche se HEAD
normalmente contiene il nome di un ramo, cioè contiene ref: refs/heads/branch
). Ma in generale, i riferimenti iniziano con refs/
.
Una cosa che Git fa per rendere questo confuso è che ti permette di omettere il refs/
, e spesso la parola dopo il refs/
. Per esempio, puoi omettere refs/heads/
o refs/tags/
quando ti riferisci ad un ramo locale o ad un tag - e infatti devi omettere refs/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 (per git 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 di fetch
e push
. Puoi anche usare git ls-remote
o git remote show
per vederli, ma fetch
e push
sono i punti di contatto più interessanti.
Durante il fetch
e il push
, 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 su fetch
, però, e riguarda sia i nomi dei rami che i nomi dei tag.
Dovresti pensare a git 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 in refs/heads/
e tutto in refs/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 chiamato origin
:
$ git config --get-all remote.origin.fetch
+refs/heads/*:refs/remotes/origin/*
$
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 in refs/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 di origin
'diventano i tuoi rami di tracciamento remoto per il remoto origin
. Il nome del ramo diventa il nome del ramo di tracciamento remoto, con il nome del remoto, in questo caso origin
, 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).
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 aggiungere refs/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 remoto origin
ha il tag xyzzy
, e tu no, e tu git fetch origin "refs/tags/*:refs/tags/*"
, avrai refs/tags/xyzzy
aggiunto al tuo repository (che punta allo stesso commit del remoto). Se usi +refs/tags/*:refs/tags/*
allora il tuo tag xyzzy
, se ne hai uno, viene sostituito da quello di origin
. 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".
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 tuo git 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.
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 eseguire git 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 semplice git 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.
Ho detto sopra che puoi omettere refs/
quasi sempre, e refs/heads/
e refs/tags/
e così via la maggior parte delle volte. Ma quando non si può?
La risposta completa (o quasi) è nella documentazione di gitrevisions
. 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 tag xyzzy
e un ramo xyzzy
, e puntano a commit diversi, allora:
git rev-parse xyzzy
gitrevisions
- git checkout
preferisce i nomi dei rami, quindi git 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
o refs/tags/xyzzy
. (Nota che questo funziona con git 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 che git checkout
userà prima il nome breve come nome del ramo: è così che si fa il checkout del ramo xyzzy
anche se il tag xyzzy
esiste. Se vuoi fare il checkout del tag, puoi usare refs/tags/xyzzy
).
Poiché (come nota gitrevisions
) Git proverà refs/name
, puoi anche semplicemente scrivere tags/xyzzy
per identificare il commit con tag xyzzy
. (Se qualcuno è riuscito a scrivere un riferimento valido chiamato xyzzy
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.