L'eliminazione di un ramo in git lo rimuove dalla cronologia?


190

Proveniente da svn, ho appena iniziato a familiarizzare con git.

Quando un ramo viene eliminato in Git, viene rimosso dalla cronologia?

In svn, è possibile ripristinare facilmente un ramo ripristinando l'operazione di eliminazione (unione inversa). Come tutte le eliminazioni in svn, il ramo non viene mai veramente cancellato, viene semplicemente rimosso dall'albero corrente.

Se il ramo viene effettivamente eliminato dalla cronologia in git, cosa succede alle modifiche che sono state unite da quel ramo? Sono conservati?

Risposte:


251

I rami sono solo indicazioni per eseguire il commit in git. In git ogni commit ha un albero dei sorgenti completo, è una struttura molto diversa da svn in cui tutti i rami e tag (per convenzione) vivono in "cartelle" separate del repository accanto allo speciale "trunk".

Se il ramo è stato unito in un altro ramo prima di essere eliminato, tutti i commit saranno comunque raggiungibili dall'altro ramo quando il primo ramo viene eliminato. Rimangono esattamente come erano.

Se il ramo viene eliminato senza essere unito in un altro ramo, i commit in quel ramo (fino al punto in cui il fork di un commit che è ancora raggiungibile) cesserà di essere visibile.

I commit verranno comunque conservati nel repository ed è possibile recuperarli immediatamente dopo l'eliminazione, ma alla fine verranno raccolti in modo inutile.


3
Grazie per la risposta. Potresti chiarire cosa intendi con "ogni commit ha un albero dei sorgenti completo"? A quanto ho capito, ogni commit in git è un insieme di delta che fanno riferimento a un commit parent, non a un intero albero.
Ken Liu,

2
@Ken Liu: un commit contiene puntatori a zero o più commit parent, un oggetto albero e alcuni metadati sul commit. Il commit, pertanto, identifica in modo univoco sia un albero di origine di coppia che, se considerato rispetto ai suoi genitori, le modifiche introdotte.
CB Bailey

9
@Ken Liu: dipende esattamente da cosa sei stato "contenuto", ma sì, essenzialmente ogni commit contiene un albero completo. Nel database degli oggetti gli oggetti sono indicizzati da id in modo che gli oggetti siano condivisi tra tutti gli oggetti (alberi e commit) che li fanno riferimento in modo che il sovraccarico di archiviazione implicito non sia così grave come sembra inizialmente. git ha anche un'ottimizzazione dell'archiviazione efficiente (file pack) che rendono ancora più efficiente l'utilizzo dello spazio su disco.
CB Bailey,

22
"alla fine saranno spazzati via" - Alla fine, quando?
BadHorsie,

7
@BadHorsie, dipende .
AliOli,

86

In Git, i rami sono solo puntatori (riferimenti) a commit in un grafico aciclico diretto (DAG) di commit. Ciò significa che l'eliminazione di un ramo rimuove solo i riferimenti ai commit, il che potrebbe rendere irraggiungibili alcuni commit nel DAG, quindi invisibili. Ma tutti i commit che si trovavano su un ramo eliminato rimarrebbero comunque nel repository, almeno fino a quando i commit non raggiungibili verranno eliminati (ad es. Utilizzando git gc).

Si noti che git branch -dsi rifiuta di eliminare una succursale se non si è certi che la sua eliminazione non lascerebbe commit irraggiungibili. È necessario utilizzare il più forte git branch -Dper forzare l'eliminazione di un ramo se potrebbe lasciare commit irraggiungibili.

Si noti inoltre che i commit non raggiungibili, se presenti, sono solo quei commit tra l'ultimo suggerimento di un ramo eliminato e un commit che è stato unito a un altro ramo esistente, qualsiasi commit con tag o punto di branching; qualunque sia dopo. Ad esempio nella seguente situazione:

---- O ---- * ---- * ---- / M ---- * <- master <- HEAD
     \ /
      \ --. ---- .-- / - x --- y <- ramo eliminato

solo i commit 'x' e 'y' diventerebbero irraggiungibili dopo aver cancellato il ramo.

Se hai operato su un ramo eliminato entro il gc.reflogExpireperiodo, 90 giorni predefiniti, avresti l'ultimo suggerimento di un ramo eliminato registrato nel registro HEAD (vedi git reflog show HEAD, o git log --oneline --walk-reflogs HEAD). Dovresti essere in grado di utilizzare HEAD reflog per recuperare il puntatore eliminato. Si noti inoltre che in questo caso, i commit non raggiungibili in un solo ramo eliminato sarebbero protetti dalla potatura (rimozione) entro il gc.reflogExpireUnreachableperiodo, che per impostazione predefinita è di 30 giorni.

Se non riesci a trovare la punta di un ramo appena cancellato nel reflog di HEAD, puoi provare a utilizzare git fsckper trovare "commit non raggiungibile <sha1>" ed esaminare quelli (tramite git show <sha1>o git log <sha1>) per trovare la punta del ramo eliminato.

Indipendentemente da come trovi la punta di un ramo eliminato, puoi annullare la cancellazione o piuttosto ricreare un ramo appena eliminato usando

git branch <deleted-branch> <found-sha1-id>

Si noti tuttavia che il reflog per un ramo andrebbe perso.


Esiste anche lo script git-resurrect.sh in contrib/cui aiuta a trovare tracce di una diramazione con un determinato nome e resuscitarlo (ripristinarlo).


1
Eccezionale! git reflog show HEADelencato il commit e ho creato un nuovo ramo proprio come hai detto tu, perfetto.
Steven Almeroth,

2

Se sei preoccupato per le filiali cancellate accidentalmente e non hai più una copia locale del tuo repository, ci sono estensioni ai server Git aziendali come Gerrit che rileveranno le riscritture della cronologia e le cancellazioni dei rami, eseguiranno il backup con un riferimento speciale in modo che può essere ripristinato se necessario e non sarà potato dalla raccolta dei rifiuti. Gli amministratori di Gerrit possono comunque rimuovere gli commit selezionati se necessario per motivi legali.

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.