In che modo un tag è diverso da un ramo in Git? Quale dovrei usare qui?


616

Ho delle difficoltà a capire come usare i tag rispetto ai rami in.

Ho appena spostato la versione corrente del nostro codice da per e ora lavorerò su un sottoinsieme di quel codice per una particolare funzione. Alcuni altri sviluppatori lavoreranno anche su questo, ma non tutti gli sviluppatori del nostro gruppo si preoccuperanno di questa funzionalità. Devo creare un ramo o un tag? In quali situazioni dovrei usare l'uno rispetto all'altro?


4
Dal momento che ricerca sul web per come utilizzare tag git mi ha portato a quel link prima, aggiungo che c'è una migliore (IMHO) risposta su un tag: stackoverflow.com/questions/35979642/...
Alexei Martianov

Risposte:


520

Un tag rappresenta una versione di un particolare ramo in un momento nel tempo. Un ramo rappresenta un thread separato di sviluppo che può essere eseguito contemporaneamente ad altri sforzi di sviluppo sulla stessa base di codice. Le modifiche a un ramo possono eventualmente essere nuovamente riunite in un altro ramo per unificarle.

Di solito si contrassegnare una particolare versione in modo da poter ricreare, ad esempio, questa è la versione che abbiamo spedito a XYZ Corp . Un ramoè più una strategia per fornire aggiornamenti continui su una particolare versione del codice, pur continuando a svilupparlo. Creerai un ramo della versione consegnata, proseguirai lo sviluppo sulla linea principale, ma apporterai correzioni di bug al ramo che rappresenta la versione consegnata. Alla fine, unirai queste correzioni di bug nella riga principale. Spesso utilizzerai sia la ramificazione che la codifica insieme. Avrai vari tag che possono essere applicati sia alla linea principale sia ai suoi rami che contrassegnano versioni particolari (quelle consegnate ai clienti, ad esempio) lungo ogni ramo che potresti voler ricreare - per consegna, diagnosi di bug, ecc.

In realtà è più complicato di così - o complicato come vuoi farlo - ma questi esempi dovrebbero darti un'idea delle differenze.


40
nel suo caso vuole usare i rami, forse dovresti anche notare questo nella tua risposta;)
knittl

13
AFAIK, i tag non sono univoci per ramo. Quindi non puoi assegnare gli stessi nomi a diversi commit in rami separati.
IL MIO

5
@MY Certamente non è una brutta cosa, IMHO. Soprattutto nel modo descritto da tvanfosson, avere più di un tag con lo stesso nome su diversi rami potrebbe diventare difficile da mantenere. Dato l'esempio, riterrei che se si potessero avere tag con lo stesso nome su diversi rami, si sarebbe rapidamente stabilito come una cattiva pratica. Buono a sapersi che non puoi, però. Grazie MIO!
Swivel

28
Un tag è solo un alias per un hash di commit. Come puoi fare il checkout di un commit con git checkout 88c9f229fte puoi fare qualcosa di simile git checkout your_tage verrai verificato il commit che è stato aliasato dal tag.
jterm,

6
@jterm, anche gli alias dei rami non sono? L'unica differenza è che un alias di succursale si ripone automaticamente al commit più recente nella catena.
Viktor Molokostov,

529

Dal punto di vista teorico :

  • i tag sono nomi simbolici per una data revisione . Indicano sempre lo stesso oggetto (di solito: la stessa revisione); non cambiano.
  • i rami sono nomi simbolici per la linea di sviluppo . I nuovi commit vengono creati in cima al ramo. Il puntatore del ramo avanza naturalmente, indicando impegni sempre più recenti.

Dal punto di vista tecnico :

  • i tag risiedono nello refs/tags/spazio dei nomi e possono puntare a oggetti tag ( tag con annotazioni e facoltativamente con firma GPG) o direttamente per eseguire il commit di oggetti (tag leggero meno utilizzato per nomi locali) o, in casi molto rari, anche ad albero o oggetto BLOB (ad esempio firma GPG ).
  • i rami risiedono nello refs/heads/spazio dei nomi e possono puntare solo al commit di oggetti . Il HEADpuntatore deve fare riferimento a un ramo (riferimento simbolico) o direttamente a un commit (HEAD distaccato o ramo senza nome).
  • i rami di tracciamento remoto risiedono nello refs/remotes/<remote>/spazio dei nomi e seguono i rami ordinari nel repository remoto <remote>.

Vedi anche la manpage gitglossary :

ramo

Un "ramo" è una linea di sviluppo attiva. Il commit più recente su un ramo è indicato come la punta di quel ramo. La punta del ramo è indicata da una testa del ramo, che si sposta in avanti man mano che si procede allo sviluppo aggiuntivo sul ramo. Un singolo repository git può tracciare un numero arbitrario di rami, ma il tuo albero di lavoro è associato ad uno solo di essi (il ramo "corrente" o "estratto") e HEAD punta a quel ramo.

etichetta

Un riferimento che punta a un tag o oggetto commit. Contrariamente a un capo, un tag non viene modificato da un commit. I tag (non gli oggetti tag) sono memorizzati in $GIT_DIR/refs/tags/. [...]. Un tag viene generalmente utilizzato per contrassegnare un punto particolare nella catena di origini di commit.

oggetto tag

Un oggetto contenente un riferimento che punta a un altro oggetto, che può contenere un messaggio proprio come un oggetto commit. Può anche contenere una firma (PGP), nel qual caso viene chiamato "oggetto tag firmato".


36
Domanda: se tratti un ramo come un tag (cioè lo crei, quindi non lo aggiorni mai), c'è qualche vera differenza?
Steve Bennett,

30
@SteveBennett assolutamente. Ci sono diverse informazioni (puoi firmare un tag, puoi aggiungere una descrizione a un ramo). Puoi spostare un ramo (quindi anche se non lo aggiorni mai, puoi ancora rifarlo.). Non è possibile spostare un tag (è collegato a un commit specifico). Puoi scegliere di spingere un ramo. I tag non vengono inviati per impostazione predefinita. Non dovresti mai usare l'uno per l'altro (a meno che tu non sia davvero in una mentalità SVN, nel qual caso devi "disimparare" così velocemente se vuoi continuare con git).
VonC,

19
@SteveBennett: c'è una differenza nel modo in cui Git tratta i rami rispetto a come tratta i tag. Oltre a ciò che ha detto VonC, non puoi avanzare tag per errore: " git checkout <tag>" genererebbe un ramo anonimo senza nome (il cosiddetto "HEAD distaccato") e selezionerebbe lo stato del tag. La creazione di un nuovo commit lo fa su questo ramo senza nome e non cambia il tag a cui punta.
Jakub Narębski,

60
IMO, i rami sono linee temporali separate (mondo parallelo) e i tag sono momenti specifici di una linea temporale.
Eonil,

25
Nessuno qui lo ha ancora menzionato, ma puoi usare un tag come punto per iniziare un ramo:git checkout -b <branch name> <tag name>

143

Se pensi al tuo repository come a un libro che racconta i progressi del tuo progetto ...

filiali

Puoi pensare a un ramo come uno di quei segnalibri appiccicosi :

inserisci qui la descrizione dell'immagine

Un repository nuovo di zecca ha solo uno di quelli (chiamati master), che passa automaticamente all'ultima pagina (pensa al commit ) che hai scritto. Tuttavia, sei libero di creare e utilizzare più segnalibri, al fine di contrassegnare altri punti di interesse nel libro, in modo da poterli tornare rapidamente.

Inoltre, puoi sempre spostare un particolare segnalibro in un'altra pagina del libro (usando git-reset, ad esempio); i punti di interesse in genere variano nel tempo.

tag

Puoi pensare ai tag come intestazioni di capitolo .

segnalibri

Può contenere un titolo (pensa ai tag con annotazioni ) oppure no. Un tag è simile ma diverso da un ramo, in quanto segna un punto di interesse storico nel libro. Per mantenere il suo aspetto storico, una volta che hai condiviso un tag (cioè lo hai spinto su un telecomando condiviso), non dovresti spostarlo in qualche altra parte del libro.


16
Immagino che un ramo sarebbe un libro e i segnalibri sono tag. Puoi continuare a scrivere un libro, ma non puoi modificarlo. Il tag è solo un momento fisso nel libro.
Mārtiņš Briedis,

5
@Jubobs Mi è piaciuta la spiegazione del ramo come una linea di sviluppo. Un libro sarebbe un ramo. Puoi iniziare un nuovo libro in base al luogo in cui ha lasciato il ramo principale. Puoi scriverli in parallelo e poi provare a unire in un libro / ramo.
Mārtiņš Briedis,

2
@ MārtiņšBriedis Capisco il modo in cui ti piace pensare a un ramo, ma trovo che, in Git, sia effettivamente fuorviante. Vedere stackoverflow.com/questions/25068543/...
jub0bs

2
questa è davvero una risposta che fa risparmiare tempo
Ali Foroughi il

2
Se inizi a scrivere un libro e hai le prime 50 pagine, puoi copiarlo (creare un nuovo ramo da esso) e continuare a scrivere due libri contemporaneamente (o dare la copia del libro a qualche altro scrittore - sviluppatore) e infine puoi unire il cambia dall'altro libro al tuo libro.
barella il

42

Quello che devi realizzare, proveniente da CVS, è che non crei più directory quando crei una filiale.
Non più "tag sticky" (che può essere applicato a un solo file) o "tag branch".
Branch e tag sono due oggetti diversi in Git e si applicano sempre a tutti i repository.

Non dovresti più (con SVN questa volta) strutturare esplicitamente il tuo repository con:

branches
   myFirstBranch
     myProject
       mySubDirs
   mySecondBranch
     ...
tags
   myFirstTag
     myProject
       mySubDirs
   mySecondTag
   ...

Tale struttura deriva dal fatto che CVS è un sistema di revisione e non un sistema di versione (vedi Controllo del codice sorgente rispetto al controllo della revisione? ).
Ciò significa che i rami sono emulati attraverso tag per CVS, copie di directory per SVN.

La tua domanda ha senso se sei abituato a fare il checkout di un tag e inizi a lavorarci .
Che non dovresti;)
Un tag dovrebbe rappresentare un contenuto immutabile , utilizzato solo per accedervi con la garanzia di ottenere lo stesso contenuto ogni volta.

In Git, la storia delle revisioni è una serie di commit, che formano un grafico.
Un ramo è un percorso di quel grafico

x--x--x--x--x # one branch
    \ 
     --y----y # another branch
       1.1
        ^
        |
        # a tag pointing to a commit
  • Se esegui il checkout di un tag, dovrai creare un ramo per iniziare a lavorare da esso.
  • Se esegui il checkout di un ramo, vedrai direttamente l'ultimo commit ('HEAD') di quel ramo.

Vedi la risposta di Jakub Narębski per tutti i tecnicismi, ma francamente, a questo punto, non hai bisogno (ancora) di tutti i dettagli;)

Il punto principale è: un tag essendo un semplice puntatore a un commit, non sarai mai in grado di modificarne il contenuto. Hai bisogno di un ramo.


Nel tuo caso, ogni sviluppatore lavora su una funzionalità specifica:

  • dovrebbe creare il proprio ramo nel rispettivo repository
  • tenere traccia dei rami dai repository dei loro colleghi (quello che lavora sulla stessa funzione)
  • tirare / spingere per condividere il tuo lavoro con i tuoi pari.

Invece di tracciare direttamente i rami dei tuoi colleghi, puoi tracciare solo il ramo di un repository centrale "ufficiale" al quale ognuno spinge il proprio lavoro al fine di integrare e condividere il lavoro di tutti per questa particolare funzione.


1
grazie per aver chiarito come funzionano i rami e i tag :) Non sarei in grado di capirlo completamente senza il tuo esempio.
UFK

3
@VonC: penso che intendi "SVN" nella tua risposta e non "CVS". CVS non ha la struttura delle directory; SVN lo fa. In effetti, tagging in git mi ricorda molto di più di tagging in RCS / CVS che tagging in SVN (dove tag == ramo degenerato).
Chris Cleeland,

1
@ChrisCleeland buon punto. Ho provato a separare un po 'più punti CVS e SVN nella risposta (modificata).
VonC,

37

I rami sono fatti di legno e crescono dal tronco dell'albero. Le etichette sono fatte di carta (derivata del legno) e pendono come ornamenti natalizi da vari punti dell'albero.

Il tuo progetto è l'albero e la tua caratteristica che verrà aggiunta al progetto crescerà su un ramo. La risposta è ramo.


3
amore per l'analogia
doz87

16

Sembra che il modo migliore per spiegare è che i tag agiscono come rami di sola lettura. È possibile utilizzare un ramo come tag, ma è possibile inavvertitamente aggiornarlo con nuovi commit. I tag garantiscono lo stesso commit purché esistano.


11
I tag garantiscono lo stesso commit purché esistano. Non del tutto vero. Puoi effettivamente spostare un tag con git tag -f.
jub0bs,

14

I tag possono essere firmati o non firmati ; i rami non sono mai firmati.

I tag firmati non possono mai spostarsi perché sono crittografati (con una firma) a un determinato commit. I tag non firmati non sono associati ed è possibile spostarli (ma lo spostamento dei tag non è un caso d'uso normale).

Le filiali non possono solo passare a un commit diverso ma ci si aspetta che lo facciano. È necessario utilizzare un ramo per il progetto di sviluppo locale. Non ha molto senso affidare il lavoro a un repository Git "su un tag".


12

Mi piace pensare ai rami come a dove stai andando , ai tag come a dove sei stato .

Un tag sembra un segnalibro di un punto particolarmente importante in passato, come una versione.

Considerando che un ramo è un percorso particolare il progetto sta andando giù, e quindi l'indicatore di ramo avanza con te. Al termine, unisci / elimina il ramo (ovvero l'indicatore). Certo, a quel punto potresti scegliere di taggare quel commit.


10

La parabola Git spiega come viene creato un tipico DVCS e perché i loro creatori hanno fatto quello che hanno fatto. Inoltre, potresti dare un'occhiata a Git for Computer Scientist ; spiega cosa fa ogni tipo di oggetto in Git, inclusi rami e tag.


6

Un tag viene utilizzato per contrassegnare una versione, più specificamente fa riferimento a un punto nel tempo su un ramo. Un ramo viene in genere utilizzato per aggiungere funzionalità a un progetto.


4

semplice:

I tag dovrebbero puntare sempre alla stessa versione di un progetto, mentre i responsabili dovrebbero avanzare man mano che lo sviluppo avanza.

Manuale utente Git


4

la semplice risposta è:

branch: il puntatore di branch corrente si sposta con ogni commit nel repository

ma

tag: il commit che un tag punta non cambia, infatti il ​​tag è un'istantanea di quel commit.

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.