Entfernt das Löschen eines Zweigs in Git ihn aus dem Verlauf?

189

Ich komme von svn und fange gerade an, mich mit git vertraut zu machen.

Wenn ein Zweig in Git gelöscht wird, wird er aus dem Verlauf entfernt?

In svn können Sie einen Zweig einfach wiederherstellen, indem Sie den Löschvorgang zurücksetzen (Reverse Merge). Wie alle Löschungen in svn wird der Zweig nie wirklich gelöscht, sondern nur aus dem aktuellen Baum entfernt.

Was passiert mit den Änderungen, die aus diesem Zweig zusammengeführt wurden, wenn der Zweig tatsächlich aus dem Verlauf in git gelöscht wird? Werden sie behalten?

Ken Liu
quelle

Antworten:

249

Zweige sind nur Zeiger auf Commits in Git. In git hat jedes Commit einen vollständigen Quellbaum. Es ist eine ganz andere Struktur als svn, bei der alle Zweige und Tags (gemäß Konvention) in separaten "Ordnern" des Repositorys neben dem speziellen "Trunk" gespeichert sind.

Wenn der Zweig vor dem Löschen in einem anderen Zweig zusammengeführt wurde, sind alle Commits weiterhin vom anderen Zweig aus erreichbar, wenn der erste Zweig gelöscht wird. Sie bleiben genau so wie sie waren.

Wenn der Zweig gelöscht wird, ohne mit einem anderen Zweig zusammengeführt zu werden, sind die Commits in diesem Zweig (bis zu dem Punkt, an dem der von einem Commit gegabelte, der noch erreichbar ist) nicht mehr sichtbar.

Die Commits bleiben weiterhin im Repository erhalten und können sofort nach dem Löschen wiederhergestellt werden. Letztendlich werden sie jedoch durch Müll gesammelt.

CB Bailey
quelle
3
Danke für die Antwort. Können Sie klarstellen, was Sie unter "Jedes Commit hat einen vollständigen Quellbaum" verstehen? So wie ich es verstehe, ist jedes Commit in Git eine Reihe von Deltas, die sich auf ein übergeordnetes Commit beziehen, nicht auf einen ganzen Baum.
Ken Liu
2
@ Ken Liu: Ein Commit enthält Zeiger auf null oder mehr übergeordnete Commits, ein Baumobjekt und einige Metadaten zum Commit. Das Commit identifiziert daher sowohl einen Paar-Quellbaum als auch, wenn es mit seinen übergeordneten Elementen verglichen wird, die von ihm eingeführten Änderungen eindeutig.
CB Bailey
9
@ Ken Liu: Es hängt genau davon ab, was Sie mit "enthalten" gemacht haben, aber ja, im Wesentlichen enthält jedes Commit einen vollständigen Baum. In der Objektdatenbank werden Objekte nach ID indiziert, sodass Objekte von allen Objekten (Bäumen und Commits) gemeinsam genutzt werden, die auf sie verweisen, sodass der implizite Speicheraufwand nicht so hoch ist, wie er zunächst klingt. git verfügt außerdem über eine effiziente Speicheroptimierung (Pack-Dateien), mit der der Speicherplatz noch effizienter genutzt werden kann.
CB Bailey
22
"Irgendwann werden sie Müll gesammelt" - Irgendwann wann?
BadHorsie
7
@BadHorsie, es kommt darauf an .
AliOli
86

In Git sind Zweige nur Zeiger (Verweise) auf Commits in einem gerichteten azyklischen Graphen (DAG) von Commits. Dies bedeutet, dass beim Löschen eines Zweigs nur Verweise auf Commits entfernt werden, wodurch einige Commits in der DAG möglicherweise nicht erreichbar und somit unsichtbar werden. Alle Commits, die sich in einem gelöschten Zweig befanden, befinden sich jedoch weiterhin im Repository, zumindest bis nicht erreichbare Commits entfernt werden (z git gc. B. mithilfe von ).

Beachten Sie, dass git branch -ddas Löschen eines Zweigs abgelehnt wird, wenn nicht sicher ist, dass beim Löschen keine nicht erreichbaren Commits hinterlassen werden. Sie müssen die stärkere verwenden git branch -D, um das Löschen eines Zweigs zu erzwingen, wenn dadurch möglicherweise nicht erreichbare Commits zurückbleiben.

Beachten Sie auch, dass nicht erreichbare Commits, sofern vorhanden, nur die Commits zwischen dem letzten Tipp eines gelöschten Zweigs und entweder einem Commit, das mit einem anderen vorhandenen Zweig zusammengeführt wurde, einem mit Tags versehenen Commit oder dem Verzweigungspunkt sind. was auch immer später ist. Zum Beispiel in der folgenden Situation:

---- O ---- * ---- * ---- / M ---- * <- master <- HEAD
     \ /
      \ --. ---- .-- / - x --- y <- Zweig gelöscht

Nur Commits 'x' und 'y' sind nach dem Löschen des Zweigs nicht mehr erreichbar.

Wenn Sie einen gelöschten Zweig innerhalb des gc.reflogExpireZeitraums von standardmäßig 90 Tagen bearbeitet haben, wird der letzte Tipp eines gelöschten Zweigs im HEAD-Reflog aufgezeichnet (siehe git reflog show HEADoder git log --oneline --walk-reflogs HEAD). Sie sollten HEAD-Reflog verwenden können, um den gelöschten Zeiger wiederherzustellen. Beachten Sie auch, dass in diesem Fall nicht erreichbare Commits in nur einem gelöschten Zweig innerhalb des gc.reflogExpireUnreachableZeitraums von standardmäßig 30 Tagen vor dem Beschneiden (Entfernen) geschützt sind .

Wenn Sie die Spitze eines gerade gelöschten Zweigs im Reflog für HEAD nicht finden können, können Sie versuchen, git fsck"nicht erreichbares Commit <sha1>" zu finden, und diese (über git show <sha1>oder git log <sha1>) untersuchen, um die Spitze des gelöschten Zweigs zu finden.

Unabhängig davon, wie Sie die Spitze eines gelöschten Zweigs finden, können Sie das Löschen rückgängig machen oder vielmehr einen gerade gelöschten Zweig mit neu erstellen

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

Beachten Sie jedoch, dass ein Reflog für einen Zweig verloren gehen würde.


Es gibt auch das Skript git-resurrect.sh, mit contrib/dem Spuren einer Verzweigungsspitze mit Vorname gefunden und wiederbelebt (wiederhergestellt) werden können.

Jakub Narębski
quelle
1
Genial! git reflog show HEADIch habe das Commit aufgelistet und einen neuen Zweig erstellt, genau wie Sie gesagt haben, perfekt.
Steven Almeroth
2

Wenn Sie sich Sorgen über versehentlich gelöschte Zweige machen und keine lokale Kopie Ihres Repos mehr haben, gibt es Erweiterungen für Enterprise-Git-Server wie Gerrit, die Verlaufsumschreibungen und Zweiglöschungen erkennen und unter einem speziellen Verweis sichern, damit sie kann bei Bedarf wiederhergestellt werden und wird nicht durch Speicherbereinigung beschnitten. Gerrit-Administratoren können ausgewählte Commits bei Bedarf aus rechtlichen Gründen weiterhin entfernen.

Johanned Nicolai
quelle