web-dev-qa-db-fra.com

Répertorier et supprimer les commits Git ne se trouvant sous aucune branche (en suspens?)

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à?

129
Samer Buna

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.

70
Aristotle Pagaltzis

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 gcremove 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.

239
tarsius

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.

16
jakub.g
git branch --contains 793db7f272ba4bbdd1e32f14410a52a412667042

probablement juste besoin d'être

git branch -a --contains 793db7f272ba4bbdd1e32f14410a52a412667042

signaler également les branches des télécommandes

13
sehe

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.

5
Andrew Larsson

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
2
Lei Zhao

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.

2
dublev