web-dev-qa-db-fra.com

Réduire l'historique d'un référentiel git

Nous avons un projet git qui a une assez 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 ils sont en fait des ressources externes.

Cependant, la taille de notre référentiel est> 200 Mo (le paiement total est actuellement ~ 20 Mo) en raison de la validation préalable de ces fichiers.

Ce que nous aimerions faire, c'est "réduire" l'historique afin 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. Grand ensemble de fichiers binaires ajoutés
  3. Grand ensemble de fichiers binaires supprimés
  4. Nouveau "début" prévu du référentiel

Donc, effectivement, nous voulons perdre l'historique du projet avant un certain point. À ce stade, il n'y a qu'une seule branche, il n'y a donc aucune complication à essayer de traiter 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?

80
Gareth

Vous pouvez supprimer le ballonnement binaire et conserver le reste de votre historique. Git vous permet de réorganiser et de `` supprimer '' les validations précédentes, vous pouvez donc 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, ce sera beaucoup plus facile que de traiter chaque fichier.

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

Recherchez les validations qui ajoutent et suppriment vos fichiers binaires et notez leurs SHA1, dites 2bcdef et 3cdef3.

Ensuite, pour modifier l'historique du dépôt, utilisez rebase -i avec son option interactive, en commençant par le parent du commit où vous avez ajouté vos binaires. Il lancera votre $ EDITOR et vous verrez une liste de 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 deuxième ligne et supprimez 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 en un commit dont le diff est juste toute autre modification de ces commits. Ensuite, il réappliquera tous les validations suivantes dans l'ordre, lorsque vous lui demanderez de terminer:

$ git rebase --continue

Cela prendra une minute ou deux.
Vous avez maintenant un dépôt qui n'a plus de binaires à venir ou à faire. Mais ils prendront toujours de la place car, par défaut, Git conserve les modifications pendant 30 jours avant de pouvoir les récupérer, afin que vous puissiez changer d'avis. Si vous souhaitez 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                      

Vous avez maintenant supprimé le ballonnement mais gardé le reste de votre historique.

88
Paul

Vous pouvez utiliser git filter-branch avec des greffons pour faire du commit numéro 4 le nouveau commit racine de votre branche. Créez simplement le fichier .git/info/grafts avec une seule ligne contenant le SHA1 du commit numéro 4.

Si vous faites maintenant un git log ou gitk vous verrez que ces commandes afficheront le commit numéro 4 comme racine de votre branche. Mais rien n'aura réellement changé dans votre référentiel. Vous pouvez supprimer .git/info/grafts et la sortie de git log ou gitk sera comme avant. Pour faire du commit numéro 4 la nouvelle racine, vous devrez exécuter git filter-branch, sans argument.

26
davitenio

Grâce au post de JesperE, j'ai examiné git-filter-branch - c'est peut-être ce que vous voulez. Il semble que vous puissiez également conserver vos validations antérieures, sauf qu'elles seraient modifiées depuis la suppression de vos fichiers volumineux. Depuis la page de manuel git-filter-branch :

Supposons que vous souhaitiez supprimer un fichier (contenant des informations confidentielles ou une violation des droits d'auteur) de toutes les validations:

git filter-branch --tree-filter 'rm filename' HEAD

Assurez-vous de lire cette page de manuel ... vous voudrez évidemment le faire sur un clone de rechange de votre référentiel pour vous assurer qu'il fonctionne comme prévu.

20
Pat Notz

Est git-fast-export Qu'est-ce que tu cherches?

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).
5
JesperE