(Questa risposta ha impiegato un po 'di tempo a scrivere e la risposta di codeWizard è corretta per finalità ed essenza, ma non è del tutto completa, quindi pubblicherò comunque.)
Non esiste un "tag Git remoto". Ci sono solo "tag". Sottolineo tutto ciò non per essere pedante, 1 ma perché c'è molta confusione al riguardo con gli utenti Git casuali e la documentazione Git non è molto utile 2 per i principianti. (Non è chiaro se la confusione deriva dalla scarsa documentazione o dalla scarsa documentazione perché ciò è intrinsecamente un po 'confuso, o cosa.)
Ci sono "rami remote", più propriamente chiamati "remote-tracciamento rami", ma vale la pena notare che questi sono in realtà gli enti locali. Non ci sono tag remoti, però (a meno che tu non li reinventi). Esistono solo tag locali, quindi è necessario ottenere il tag localmente per poterlo utilizzare.
Il modulo generale per i nomi di commit specifici, che Git chiama riferimenti, è qualsiasi stringa che inizia con refs/
. Una stringa che inizia con i refs/heads/
nomi di un ramo; una stringa che inizia con i refs/remotes/
nomi di un ramo di tracciamento remoto; e una stringa che inizia con i refs/tags/
nomi di un tag. Il nome refs/stash
è il riferimento stash (come usato da git stash
; notare la mancanza di una barra finale).
Ci sono alcuni nomi speciali di casi insoliti che non iniziano con refs/
: HEAD
, ORIG_HEAD
, MERGE_HEAD
, e CHERRY_PICK_HEAD
, in particolare, sono tutti anche nomi che possono fare riferimento a specifici commit (anche se HEAD
di solito contiene il nome di un ramo, ad esempio, contiene ). Ma in generale, i riferimenti iniziano con .ref: refs/heads/branch
refs/
Una cosa che Git fa per rendere questo confuso è che ti permette di omettere refs/
, e spesso la parola dopo refs/
. Ad esempio, puoi omettere refs/heads/
o refs/tags/
quando ti riferisci a una filiale o tag locale, e infatti devi ometterti refs/heads/
quando controlli una filiale 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: vale a dire durante fetch
e durante le push
operazioni. Puoi anche usarli git ls-remote
o git remote show
vederli, ma fetch
e push
sono i punti di contatto più interessanti.
Refspecs
Durante fetch
e push
, Git usa stringhe che chiama refspecs per trasferire riferimenti tra il repository locale e remoto. Pertanto, è in questi momenti, e tramite refspecs, che due repository Git possono sincronizzarsi tra loro. Una volta che i tuoi nomi sono sincronizzati, puoi usare lo stesso nome usato da qualcuno con il telecomando. C'è un po 'di magia speciale qui fetch
, e influenza sia i nomi dei rami che i nomi dei tag.
Dovresti pensare di git fetch
indirizzare il tuo Git a richiamare (o forse a un messaggio di testo) un altro Git — il "remoto" —e avere una conversazione con esso. All'inizio di questa conversazione, il telecomando elenca tutti i suoi riferimenti: tutto dentro refs/heads/
e tutto dentro refs/tags/
, insieme a tutti gli altri riferimenti che ha. Git esegue la scansione di questi e (in base al solito refspec fetch) rinomina i loro rami.
Diamo un'occhiata al normale refspec per il telecomando chiamato origin
:
$ git config --get-all remote.origin.fetch
+refs/heads/*:refs/remotes/origin/*
$
Questo refspec indica a Git di prendere ogni corrispondenza del nome refs/heads/*
—ie, ogni ramo sul telecomando — e cambiare il suo nome in refs/remotes/origin/*
, cioè mantenere la parte abbinata uguale, cambiando il nome del ramo ( refs/heads/
) in un nome di ramo di tracciamento remoto ( refs/remotes/
, in particolare , refs/remotes/origin/
).
È attraverso questo refspec che origin
i rami diventano i tuoi rami di localizzazione remota per remoto origin
. Il nome del ramo diventa il nome del ramo di tracciamento remoto, con il nome del telecomando, in questo caso origin
incluso. Il segno più +
nella parte anteriore di refspec imposta il flag "force", ovvero il ramo di tracciamento remoto verrà aggiornato in modo che corrisponda al nome del ramo del telecomando, indipendentemente da ciò che serve per farlo corrispondere. (Senza +
, gli aggiornamenti di diramazione sono limitati alle modifiche "avanzamento rapido" e gli aggiornamenti dei tag sono semplicemente ignorati dalla versione 1.8.2 di Git o giù di lì, prima di applicare le stesse regole di avanzamento rapido.)
tag
E i tag? Non c'è refspec per loro, almeno non di default. Puoi impostarne uno, nel qual caso la forma del refspec dipende da te; oppure puoi correre git fetch --tags
. L'utilizzo --tags
ha l'effetto di aggiungere refs/tags/*:refs/tags/*
a refspec, ovvero porta tutti i tag ( ma non aggiorna il tag se hai già un tag con quel nome, indipendentemente da ciò che dice il tag del telecomando Modifica, gennaio 2017: da Git 2.10 , i test mostrano che --tags
aggiorna forzatamente i tag dai tag del telecomando, come se refspec leggesse +refs/tags/*:refs/tags/*
; questa potrebbe essere una differenza di comportamento rispetto a una versione precedente di Git).
Si noti che non è possibile rinominare qui: se remote origin
ha tag xyzzy
, e tu no, e tu git fetch origin "refs/tags/*:refs/tags/*"
, vieni refs/tags/xyzzy
aggiunto al tuo repository (indicando lo stesso commit del telecomando). Se usi, il +refs/tags/*:refs/tags/*
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 ottiene dal loro Git".
Tag automagic durante il recupero
Per motivi storici, 3 se non si utilizza né l' --tags
opzione né l' --no-tags
opzione, git fetch
viene eseguita un'azione speciale. Ricorda che abbiamo detto sopra che il telecomando inizia visualizzando al tuo Git locale tutti i suoi riferimenti, indipendentemente dal fatto che il tuo Git locale voglia vederli o meno. 4 Il tuo Git prende nota di tutti i tag che vede a questo punto. Quindi, non appena inizia a scaricare qualsiasi oggetto commit necessario per gestire qualunque cosa stia recuperando, se uno di questi commit ha lo stesso ID di uno di quei tag, git aggiungerà quel tag - o quei tag, se più tag hanno quell'ID - a il tuo repository.
Modifica, gennaio 2017: il test mostra che il comportamento in Git 2.10 è ora: Se il loro Git fornisce un tag di nome T , e non si dispone di un tag di nome T , e il commit ID associato a T è un antenato di uno dei loro rami che git fetch
stai esaminando, Git aggiunge T ai tuoi tag con o senza --tags
. L'aggiunta --tags
fa sì che Git ottenga tutti i loro tag e imponga anche l'aggiornamento.
Linea di fondo
Potrebbe essere necessario utilizzare git fetch --tags
per ottenere i loro tag. Se i loro nomi dei tag sono in conflitto con i nomi dei tag esistenti, potrebbe essere necessario (a seconda della versione di Git) persino eliminare (o rinominare) alcuni dei tag e quindi eseguirli git fetch --tags
per ottenere i tag. Poiché i tag, a differenza dei rami remoti, non hanno una ridenominazione automatica, i nomi dei tag devono corrispondere ai nomi dei tag, motivo per cui si possono avere problemi con conflitti.
Nella maggior parte dei casi normali, tuttavia, un semplice git fetch
eseguirà il lavoro, portando a termine i propri commit e i tag corrispondenti, e dal momento che, chiunque essi siano, taggeranno i commit nel momento in cui pubblicano tali commit, continuerai con i loro tag. Se non crei i tuoi tag, né mescoli il loro repository e altri repository (tramite più telecomandi), non avrai nemmeno collisioni di nomi di tag, quindi non dovrai preoccuparti di eliminare o rinominare i tag per ottenere i loro tag.
Quando hai bisogno di nomi qualificati
Ho già detto che è possibile omettere refs/
quasi sempre, ed refs/heads/
e refs/tags/
e così via la maggior parte del tempo. Ma quando non puoi?
La (in ogni caso o quasi completa) risposta completa è la gitrevisions
documentazione . Git risolverà un nome in un ID commit usando la sequenza in sei passaggi indicata nel collegamento. 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
ti darà l'ID a cui punta il tag. Tuttavia - e questo è ciò che manca 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 sillabare il nome di riferimento usando il suo nome completo refs/heads/xyzzy
o refs/tags/xyzzy
. (Si noti che questo fa il lavoro con git checkout
, ma in un modo forse inaspettato: git checkout refs/heads/xyzzy
provoca una cassa indipendente-testa, piuttosto che un checkout ramo Questo è il motivo per cui è sufficiente notare che. git checkout
Utilizzerà il nome breve come un nome di primo ramo: è così che si controlla il ramo xyzzy
anche se xyzzy
esiste il tag . Se vuoi controllare il tag, puoi usarlo refs/tags/xyzzy
.)
Poiché (come gitrevisions
note) Git proverà , puoi anche semplicemente scrivere per identificare il commit taggato . (Se qualcuno è riuscito a scrivere un riferimento valido nominato in , tuttavia, questo si risolverà come . Ma normalmente dovrebbero essere presenti solo i vari nomi .)refs/name
tags/xyzzy
xyzzy
xyzzy
$GIT_DIR
$GIT_DIR/xyzzy
*HEAD
$GIT_DIR
1 Va bene, va bene, "non solo per essere pedanti". :-)
2 Alcuni direbbero "molto inutile", e in realtà tenderei ad essere d'accordo.
3 Fondamentalmente, git fetch
e l'intero concetto di telecomandi e refspec, è stato un po 'in ritardo con Git, accadendo all'epoca di Git 1.5. Prima di allora c'erano solo alcuni casi speciali ad hoc, e il recupero dei tag era uno di questi, quindi è stato nonno tramite codice speciale.
4 Se aiuta, pensa a Git remoto come un lampeggiatore , nel significato gergale.
git checkout A
. che cos'èA
? Come hai creatoA
?