294 votes

Comment supprimer l'ancien historique d'un dépôt git ?

J'ai bien peur de n'avoir rien trouvé qui ressemble à ce scénario particulier.

J'ai un dépôt git avec beaucoup d'historique : 500+ branches, 500+ tags, remontant à mi-2007. Il contient ~19 500 commits. Nous aimerions supprimer tout l'historique antérieur au 1er janvier 2010, pour le rendre plus petit et plus facile à gérer (nous conserverions une copie complète de l'historique dans un dépôt d'archives).

Je connais le commit que je veux voir devenir la racine du nouveau dépôt. Cependant, je n'arrive pas à trouver le bon git mojo pour tronquer le dépôt et commencer avec ce commit. Je suppose qu'une variante de

git filter-branch

impliquant des greffes serait nécessaire ; il pourrait également être nécessaire de traiter chacune des plus de 200 branches que nous voulons conserver séparément, puis de patcher le repo ensemble (quelque chose que je faire savent comment faire).

Quelqu'un a-t-il déjà fait quelque chose comme ça ? J'ai git 1.7.2.3 si ça compte.

131voto

apenwarr Points 4956

Vous pouvez créer un greffe du parent de votre nouveau commit racine vers aucun parent (ou vers un commit vide, par exemple le vrai commit racine de votre dépôt). Par exemple echo "<NEW-ROOT-SHA1>" > .git/info/grafts

Après avoir créé la greffe, elle prend effet immédiatement ; vous devriez être en mesure de voir git log et voir que les anciens commits indésirables ont disparu :

$ echo 4a46bc886318679d8b15e05aea40b83ff6c3bd47 > .git/info/grafts
$ git log --decorate | tail --lines=11
commit cb3da2d4d8c3378919844b29e815bfd5fdc0210c
Author: Your Name <your.email@example.com>
Date:   Fri May 24 14:04:10 2013 +0200

    Another message

commit 4a46bc886318679d8b15e05aea40b83ff6c3bd47 (grafted)
Author: Your Name <your.email@example.com>
Date:   Thu May 23 22:27:48 2013 +0200

    Some message

Si tout se passe comme prévu, vous pouvez utiliser git filter-branch -- --all pour le rendre permanent.

PRUDENCE : après avoir fait le filtre-branche tous les identifiants de commit auront changé, donc toute personne utilisant l'ancien repo ne doit jamais fusionner avec une personne utilisant le nouveau repo.

1 votes

Eh bien, après avoir créé un fichier '.git/info/grafts' et une branche de filtrage, j'avais encore besoin d'une copie 'git clone --no-local --no-hardlinks' (faites toutes vos branches de suivi locales avant cela). Supprimer simplement '.git/info/grafts' ne fait pas l'affaire !

2 votes

Vous voulez probablement vérifier stackoverflow.com/questions/7654822/ lorsque vous voulez réduire la taille de votre référentiel.

7 votes

Je devais faire git filter-branch --tag-name-filter cat -- --all pour mettre à jour les balises. Mais j'ai aussi des balises plus anciennes qui pointent vers l'ancien historique et que je veux supprimer. Comment puis-je me débarrasser de toutes ces anciennes balises ? Si je ne les supprime pas, l'ancien historique ne disparaîtra pas et je pourrai toujours le voir avec la commande gitk --all .

88voto

Chris Maes Points 1912

Ce site méthode est facile à comprendre et fonctionne bien. L'argument du script ( $1 ) est une référence (tag, hash, ...) au commit à partir duquel vous souhaitez conserver votre historique.

#!/bin/bash
git checkout --orphan temp $1 # create a new branch without parent history
git commit -m "Truncated history" # create a first commit on this branch
git rebase --onto temp $1 master # now rebase the part of master branch that we want to keep onto this branch
git branch -D temp # delete the temp branch

# The following 2 commands are optional - they keep your git repo in good shape.
git prune --progress # delete all the objects w/o references
git gc --aggressive # aggressively collect garbage; may take a lot of time on large repos

NOTE que les anciennes balises resteront présentes ; vous devrez donc peut-être les supprimer manuellement

remarque : Je sais que c'est presque la même réponse que @yoyodin, mais il y a quelques commandes et informations supplémentaires importantes ici. J'ai essayé d'éditer la réponse, mais comme il s'agit d'un changement substantiel à la réponse de @yoyodin, mon édition a été rejetée, donc voici l'information !

1 votes

J'apprécie les explications données pour les git prune y git gc commandes. Y a-t-il une explication pour le reste des commandes dans le script ? En l'état, les arguments qui lui sont passés et ce que fait chaque commande ne sont pas clairs. Merci.

2 votes

@user5359531 merci pour votre remarque, j'ai ajouté quelques commentaires supplémentaires pour chaque commande. J'espère que cela vous aidera.

0 votes

@ChrisMaes est git prune --progress pour une ancienne version de git ? Selon la documentation, "dans la plupart des cas, les utilisateurs n'auront pas besoin d'appeler git prune directement, mais devraient plutôt appeler git gc, qui gère l'élagage ainsi que de nombreuses autres tâches ménagères".

63voto

yoyodyn Points 233

Essayez cette méthode Comment tronquer l'historique git :

#!/bin/bash
git checkout --orphan temp $1
git commit -m "Truncated history"
git rebase --onto temp $1 master
git branch -D temp

Aquí $1 est le SHA-1 du commit que vous voulez garder et le script va créer une nouvelle branche qui contient tous les commits entre $1 y master et toute l'histoire ancienne est abandonnée. Notez que ce simple script suppose que vous n'avez pas de branche existante appelée temp . Notez également que ce script n'efface pas les données git pour l'ancien historique. Exécuter git gc --prune=all && git repack -a -f -F -d après avoir vérifié que vous voulez vraiment perdre toute l'histoire. Vous pouvez également avoir besoin rebase --preserve-merges mais sachez que l'implémentation de cette fonctionnalité dans git n'est pas parfaite. Inspectez les résultats manuellement si vous l'utilisez.

0 votes

Cela fonctionne pour moi, sauf que j'ai dû contourner l'absence de "git checkout --orphan" sur ma version de git : bogdan.org.ua/2011/03/28/…

27 votes

J'ai essayé cela, mais j'ai eu des conflits de fusion dans le fichier rebase étape. Étrange - je ne m'attendais pas à ce que des conflits de fusion soient possibles dans ces circonstances.

2 votes

Utilice git commit --allow-empty -m "Truncate history" si le commit que vous avez extrait ne contient pas de fichiers.

38voto

Jeff Bowman Points 9712

Comme alternative à la réécriture de l'histoire, envisagez d'utiliser git replace dans le cas de cet article du Pro Git livre . L'exemple discuté implique le remplacement d'un commit parent pour simuler le début d'un arbre, tout en gardant l'historique complet dans une branche séparée pour plus de sécurité.

0 votes

Oui, je pense que vous pourriez probablement faire ce que nous voulions avec ça, si vous supprimez aussi la branche séparée de l'histoire complète. (Nous essayions de réduire le référentiel).

2 votes

J'ai été découragé par le fait que la réponse était hors site, mais elle renvoie au site de GitScm et le tutoriel auquel elle renvoie est très bien écrit et semble répondre directement à la question de l'OP.

1 votes

@ThorSummoner Désolé pour ça ! Je vais développer la réponse de manière un peu plus complète sur place.

8voto

EnabrenTane Points 5262
git clone --depth 200 repo --branch branch

Faire une copie superficielle uniquement des 200 derniers commits pour une branche.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X