2008-10-30 5 views
79

Nous avons un projet git qui a une grande histoire. Plus précisément, au début du projet, il y avait beaucoup de fichiers de ressources binaires dans le projet, ceux-ci ont maintenant été supprimés car il s'agit de ressources externes efficaces.Réduire l'historique d'un dépôt git

Cependant, la taille de notre référentiel est> 200MB (la vérification totale est actuellement de ~ 20MB) en raison de la présence de ces fichiers précédemment validés. Ce que nous aimerions faire, c'est "replier" l'historique de sorte que le référentiel semble avoir été créé à partir d'une révision ultérieure. Par exemple

1-----2-----3-----4-----+---+---+ 
        \  /
        +-----+---+---+ 
  1. référentiel créé
  2. ensemble grand nombre de fichiers binaires ajouté
  3. ensemble grand nombre de fichiers binaires supprimé
  4. Nouveau but « début » du dépôt

donc efficacement nous vouloir perdre l'historique du projet avant un certain point. À ce stade, il n'y a qu'une seule branche, donc il n'y a pas de complication à essayer de gérer plusieurs points de départ, etc. Cependant, nous ne voulons pas perdre tout l'historique et démarrer un nouveau référentiel avec la version actuelle.

Est-ce possible, ou sommes-nous condamnés à avoir un référentiel gonflé pour toujours?

Répondre

88

Vous pouvez supprimer le ballonnement binaire et conserver le reste de votre historique. Git vous permet de réorganiser et d'écraser les commits antérieurs, de sorte que vous pouvez combiner uniquement les validations qui ajoutent et suppriment vos gros fichiers binaires. Si les ajouts ont tous été effectués dans un commit et les suppressions dans un autre, cela sera beaucoup plus facile que de traiter chaque fichier.

$ git log --stat  # list all commits and commit messages 

Rechercher ce pour les commits qui ajoutent et supprimer vos fichiers binaires et de noter leurs SHA1s, disent 2bcdef et 3cdef3.

Ensuite, pour éditer l'historique des repo, utilisez la commande rebase -i avec son option interactive, en commençant par le parent du commit où vous avez ajouté vos binaires.Il va lancer votre éditeur $ et vous verrez une liste des commits commençant par 2bcdef:

$ git rebase -i 2bcdef^ # generate a pick list of all commits starting with 2bcdef 
# Rebasing zzzzzz onto yyyyyyy 
# 
# Commands: 
# pick = use commit 
# edit = use commit, but stop for amending 
# squash = use commit, but meld into previous commit 
# 
# If you remove a line here THAT COMMIT WILL BE LOST. 
# 
pick 2bcdef Add binary files and other edits 
pick xxxxxx Another change 
    . 
    . 
pick 3cdef3 Remove binary files; link to them as external resources 
    . 
    . 

Insérer squash 3cdef3 comme la deuxième ligne et de supprimer la ligne qui dit pick 3cdef3 de la liste. Vous avez maintenant une liste d'actions pour le rebase interactif qui combinera les commits qui ajoutent et suppriment vos binaires dans une validation dont le diff est juste n'importe quels autres changements dans ces commits. Ensuite, il appliquera de nouveau tous les commits suivantes dans l'ordre, quand vous dites à compléter:

$ git rebase --continue 

Cela prendra une minute ou deux.
Vous avez maintenant un repo qui n'a plus les binaires à venir ou à venir. Mais ils prendront tout de même de l'espace car, par défaut, Git conserve les changements pendant 30 jours avant de pouvoir être récupérés, afin que vous puissiez changer d'avis. Si vous voulez les supprimer maintenant:

$ git reflog expire --expire=1.minute refs/heads/master 
     #all deletions up to 1 minute ago available to be garbage-collected 
$ git fsck --unreachable  # lists all the blobs(files) that will be garbage-collected 
$ git prune 
$ git gc      

Maintenant vous avez supprimé le ballonnement, mais a gardé le reste de votre histoire.

+1

Bonne réponse. – JesperE

+7

Vous avez juste à vous rappeler si d'autres ont déjà tiré de ce référentiel, réécrire l'histoire va confondre leur attraction. Le manuel de git-rebase explique comment récupérer ces autres repos. http://www.kernel.org/pub/software/scm/git/docs/git-rebase.html – Otto

+0

Ceci est une excellente réponse pour le problème spécifique de l'utilisateur, mais pas pour la question réelle! La réponse de davitenio est une excellente réponse à la question. –

6

Est-ce que git-fast-export est ce que vous cherchez?

NAME 
    git-fast-export - Git data exporter 

SYNOPSIS 
    git-fast-export [options] | git-fast-import 

DESCRIPTION 
    This program dumps the given revisions in a form suitable to be piped into git-fast- 
    import(1). 

    You can use it as a human readable bundle replacement (see git-bundle(1)), or as a kind 
    of an interactive git-filter-branch(1). 
21

Merci au poste de JesperE je regardais dans git-filter-branch - qui peut effectivement être ce que vous voulez. Il semblerait que vous puissiez également conserver vos validations antérieures, sauf qu'elles seraient modifiées depuis la suppression de vos Big Files. De l'git-filter-branch man page:

Supposons que vous voulez supprimer un fichier (contenant des informations confidentielles ou de violation du droit d'auteur) de tous les engage:

git filtre-branche --tree-tête de filtre 'rm nom'

Assurez-vous de lire cette page de manuel ... évidemment, vous voudrez le faire sur un clone de rechange de votre dépôt pour vous assurer qu'il fonctionne comme prévu.

+2

Vérifiez le lien de github ... a quelques options puissantes avec la commande git-filter-branch: https://help.github.com/articles/remove-sensitive-data – ricosrealm

25

Vous pouvez utiliser git filter-branch avec des greffes pour que le numéro de validation 4 soit la nouvelle validation racine de votre branche. Il suffit de créer le fichier .git/info/grafts avec juste une ligne dans ce contenant le SHA1 de commettre le numéro 4.

Si vous faites maintenant un git log ou gitk vous verrez que ces commandes affichent engagent le numéro 4 comme la racine de votre branche. Mais rien n'aura changé dans votre dépôt. Vous pouvez supprimer .git/info/grafts et la sortie de git log ou gitk sera comme avant. Pour réellement faire commettre numéro 4 la nouvelle racine, vous devrez exécuter git filter-branch, sans arguments.

+0

C'est beaucoup mieux qu'un rebase car il n'a pas de problèmes préservant les commits de fusion, et ne provoque pas de changements d'horodatage. Plus facile et plus rapide que toutes les méthodes de rebasage aussi. – mmrobins

+0

Cela fonctionne très bien, merci! – Verhogen

+0

En fait, existe-t-il un moyen de supprimer physiquement toutes les validations qui ne font plus partie de cette branche? 'git gc --prune = 0' ne semble pas les nettoyer. – Verhogen