La suppression d'une branche dans git la supprime-t-elle de l'historique?

190

Venant de svn, je commence tout juste à se familiariser avec git.

Lorsqu'une branche est supprimée dans git, est-elle supprimée de l'historique?

Dans svn, vous pouvez facilement récupérer une branche en annulant l'opération de suppression (fusion inverse). Comme toutes les suppressions dans svn, la branche n'est jamais vraiment supprimée, elle est simplement supprimée de l'arborescence actuelle.

Si la branche est effectivement supprimée de l'historique dans git, qu'advient-il des modifications qui ont été fusionnées à partir de cette branche? Sont-ils conservés?

Ken Liu
la source

Réponses:

251

Les branches ne sont que des pointeurs vers des commits dans git. Dans git, chaque commit a une arborescence source complète, c'est une structure très différente de svn où toutes les branches et balises (par convention) vivent dans des «dossiers» séparés du référentiel à côté du «tronc» spécial.

Si la branche a été fusionnée dans une autre branche avant d'être supprimée, tous les validations seront toujours accessibles depuis l'autre branche lorsque la première branche sera supprimée. Ils restent exactement tels qu'ils étaient.

Si la branche est supprimée sans être fusionnée dans une autre branche, alors les commits dans cette branche (jusqu'au point où le fork d'un commit qui est toujours accessible) cesseront d'être visibles.

Les validations seront toujours conservées dans le référentiel et il est possible de les récupérer immédiatement après la suppression, mais elles seront finalement récupérées.

CB Bailey
la source
3
Merci d'avoir répondu. Pourriez-vous clarifier ce que vous entendez par "chaque commit a un arbre source complet"? Si je comprends bien, chaque commit dans git est un ensemble de deltas qui renvoient à un commit parent, pas à un arbre entier.
Ken Liu
2
@Ken Liu: Un commit contient des pointeurs vers zéro ou plus de commits parents, un objet d'arborescence et des métadonnées sur le commit. Le commit identifie donc de manière unique à la fois un couple arbre source et, lorsqu'il est vu par rapport à son (ses) parent (s), les changements qu'il a introduits.
CB Bailey
9
@Ken Liu: Cela dépend exactement de ce que vous avez été par «contenir», mais oui, essentiellement chaque commit contient un arbre complet. Dans la base de données d'objets, les objets sont indexés par id afin que les objets soient partagés entre tous les objets (arborescences et commits) qui les référencent, de sorte que la surcharge de stockage implicite n'est pas aussi mauvaise qu'elle le semble initialement. git dispose également d'une optimisation efficace du stockage (fichiers de pack) qui permet une utilisation encore plus efficace de l'espace disque.
CB Bailey
22
"finalement ils seront ramassés" - Finalement quand?
BadHorsie
7
@BadHorsie, ça dépend .
AliOli
86

Dans Git, les branches ne sont que des pointeurs (références) vers des commits dans un graphe acyclique dirigé (DAG) de commits. Cela signifie que la suppression d'une branche supprime uniquement les références aux commits, ce qui peut rendre certains commits dans le DAG inaccessibles, donc invisibles. Mais tous les commits qui étaient sur une branche supprimée seraient toujours dans le référentiel, au moins jusqu'à ce que les commits inaccessibles soient élagués (par exemple en utilisant git gc).

Notez que git branch -dcela refuserait de supprimer une branche s'il ne peut pas être sûr que sa suppression ne laisserait pas de commits inaccessibles. Vous devez utiliser le plus fort git branch -Dpour forcer la suppression d'une branche si elle risque de laisser des commits inaccessibles.

Notez également que les commits inaccessibles, s'ils sont présents, ne sont que les commits entre le dernier bout d'une branche supprimée et soit un commit qui a été fusionné avec une autre branche existante, un commit balisé, ou le point de branchement; selon la dernière éventualité. Par exemple dans la situation suivante:

---- O ---- * ---- * ---- / M ---- * <- maître <- HEAD
     \ /
      \ --. ---- .-- / - x --- y <- branche supprimée

seuls les commits «x» et «y» deviendraient inaccessibles après la suppression de la branche.

Si vous avez opéré sur une succursale supprimée pendant la gc.reflogExpirepériode, 90 jours par défaut, vous auriez le dernier conseil d'une succursale supprimée enregistré dans HEAD reflog (voir git reflog show HEAD, ou git log --oneline --walk-reflogs HEAD). Vous devriez pouvoir utiliser le reflog HEAD pour récupérer le pointeur supprimé. Notez également que dans ce cas, les commits inaccessibles dans une seule branche supprimée seraient protégés contre l'élagage (suppression) dans le gc.reflogExpireUnreachabledélai, qui par défaut est de 30 jours.

Si vous ne trouvez pas la pointe d'une branche qui vient d'être supprimée dans reflog pour HEAD, vous pouvez essayer d'utiliser git fsckpour trouver "commit inaccessible <sha1>", et les examiner (via git show <sha1>ou git log <sha1>) pour trouver la pointe de la branche supprimée.

Indépendamment de la façon dont vous trouvez la pointe d'une branche supprimée, vous pouvez annuler la suppression, ou plutôt recréer une branche qui vient d'être supprimée en utilisant

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

Notez cependant que le reflog d'une branche serait perdu.


Il existe également un script git-resurrect.shcontrib/ qui permet de trouver des traces d'une pointe de branche avec un nom donné et de la ressusciter (annuler la suppression).

Jakub Narębski
la source
1
Impressionnant! git reflog show HEADlisté le commit et j'ai créé une nouvelle branche comme vous l'avez dit, parfait.
Steven Almeroth
2

Si vous vous inquiétez des branches supprimées accidentellement et que vous n'avez plus de copie locale de votre dépôt, il existe des extensions pour les serveurs Git d'entreprise comme Gerrit qui détecteront les réécritures d'historique et les suppressions de branches, les sauvegarderont sous une référence spéciale afin qu'elles peut être restauré si nécessaire et ne sera pas élagué par le ramasse-miettes. Les administrateurs Gerrit peuvent toujours supprimer les commits sélectionnés si nécessaire pour des raisons juridiques.

Johanned Nicolai
la source