J'ai un dépôt Git avec beaucoup de commits qui ne sont pas liés à une branche particulière, je peux git show
_ eux, mais lorsque j'essaie de lister les branches qui les contiennent, rien ne s'affiche.
Je pensais que c'était la question des commits/arbres (suite à la branche -D), alors j'ai élagué le référentiel, mais je vois toujours le même comportement après cela:
$ git fetch Origin
$ git fsck --unreachable
$ git fsck
Pas de sortie, rien ne balance (non?). Mais le commit existe
$ git show 793db7f272ba4bbdd1e32f14410a52a412667042
commit 793db7f272ba4bbdd1e32f14410a52a412667042
Author: ...
et il n'est pas accessible par n'importe quelle branche
$ git branch --contains 793db7f272ba4bbdd1e32f14410a52a412667042
ne donne pas de sortie.
Quel est exactement l'état de ce commit? Comment puis-je lister tous les commits dans un état similaire? Comment puis-je supprimer des commits comme ceux-là?
Pas de sortie, rien ne balance (non?)
Notez que les commits auxquels il est fait référence dans votre reflet sont considérés comme accessibles.
Quel est exactement l'état de ce commit? Comment puis-je lister tous les commits avec un état similaire
Passer --no-reflogs
convaincre git fsck
pour vous les montrer.
Comment puis-je supprimer des commits comme ceux-là?
Une fois que vos entrées de reflog sont expirées, ces objets seront également nettoyés par git gc
.
L'expiration est réglée par le gc.pruneexpire
, gc.reflogexpire
, et gc.reflogexpireunreachable
paramètres. Cf. git help config
.
Les valeurs par défaut sont toutes raisonnables.
Pour supprimer tous les commits en suspens, procédez comme suit:
git reflog expire --expire-unreachable=now --all
git gc --Prune=now
Mais soyez certain que c'est ce que vous voulez. Je vous recommande de lire les pages de manuel mais voici le Gist:
git gc
remove les objets inaccessibles (commits, arbres, blobs (fichiers)). Un objet est inaccessible s'il ne fait pas partie de l'histoire d'une branche. En fait, c'est un peu plus compliqué:
git gc
fait d'autres choses, mais elles ne sont pas pertinentes ici et ne sont pas dangereuses.
Les objets inaccessibles âgés de moins de deux semaines ne sont pas supprimés. Nous utilisons donc --Prune=now
qui signifie "supprimer les objets inaccessibles créés auparavant".
Les objets peuvent également être atteints par le biais du reflog. Tandis que les branches enregistrent l’histoire de certains projets, les réflexions enregistrent l’histoire de ces branches. Si vous modifiez, réinitialisez, etc., les commits sont supprimés de l'historique de la branche, mais git les conserve au cas où vous vous rendriez compte que vous avez commis une erreur. Les réflexions sont un moyen pratique de savoir quelles opérations destructives (et autres) ont été effectuées sur une branche (ou HEAD), ce qui facilite l'annulation d'une opération destructive.
Nous devons donc également supprimer les reflogs pour supprimer tout ce qui n’est pas accessible depuis une branche. Nous le faisons en expirant --all
reflogs. Encore une fois, git garde un peu de reflogs pour protéger les utilisateurs, nous devons donc lui dire de ne pas le faire: --expire-unreachable=now
.
Comme je me sers principalement du reflog pour me remettre d’opérations destructives, j’utilise habituellement --expire=now
à la place, ce qui zappe complètement les réflexions.
J'ai eu le même problème, toujours après avoir suivi tous les conseils dans ce fil:
git reflog expire --expire-unreachable=now --all
git gc --Prune=now
git fsck --unreachable --no-reflogs # no output
git branch -a --contains <commit> # no output
git show <commit> # still shows up
Si ce n'est pas un reflog et pas une branche, ... ça doit être ne balise!
git tag # showed several old tags created before the cleanup
J'ai enlevé les balises avec git tag -d <tagname>
et a refait le nettoyage, et les vieux commits ont disparu.
git branch --contains 793db7f272ba4bbdd1e32f14410a52a412667042
probablement juste besoin d'être
git branch -a --contains 793db7f272ba4bbdd1e32f14410a52a412667042
signaler également les branches des télécommandes
J'ai eu un problème similaire. Iran git branch --contains <commit>
, et il n’a renvoyé aucun résultat, comme dans la question.
Mais même après avoir couru
git reflog expire --expire-unreachable=now --all
git gc --Prune=now
mon commit était toujours accessible en utilisant git show <commit>
. Cela était dû au fait que l'un des commits de sa "branche" détachée/pendante était marqué. J'ai enlevé la balise, relancé les commandes ci-dessus et j'étais dorée. git show <commit>
revenu fatal: bad object <commit>
- exactement ce dont j'avais besoin. Espérons que cela aide quelqu'un d'autre qui était aussi bloqué que moi.
J'ai accidentellement rencontré la même situation et découvert que mes cachettes contenaient une référence au commit inaccessible. Ainsi, le commit présumé inaccessible était accessible à partir des cachettes.
C’est ce que j’ai fait pour le rendre vraiment inaccessible.
git stash clear
git reflog expire --expire-unreachable=now --all
git fsck --unreachable
git gc --Prune=now
git gc --Prune=<date>
Par défaut, les objets sont supprimés depuis plus de deux semaines. Vous pouvez définir une date plus récente. Cependant, les commandes git qui créent des objets desserrés exécutent généralement git gc --auto (qui élague les objets perdus si leur nombre dépasse la valeur de la variable de configuration gc.auto).
Êtes-vous sûr de vouloir supprimer ces commits? Le paramètre par défaut de gc.auto garantit que les objets en vrac ne prennent pas une quantité de mémoire déraisonnable, et le stockage d'objets vides pendant un certain temps est généralement une bonne idée. Ainsi, si vous vous rendez compte demain que votre branche supprimée contient le commit dont vous aviez besoin, vous pouvez le récupérer.