81 votes

Réduire l'historique d'un dépôt git

Nous avons un projet git qui a un historique assez important.

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 effectivement des ressources externes.

Cependant, la taille de notre dépôt est >200MB (le checkout total est actuellement ~20MB) en raison de ces fichiers précédemment livrés.

Ce que nous aimerions faire, c'est "réduire" l'historique de sorte que le référentiel semble avoir été créé à partir d'une révision plus récente qu'il ne l'était. Par exemple

1-----2-----3-----4-----+---+---+
                   \       /
                    +-----+---+---+
  1. Référentiel créé
  2. Ajout d'un grand nombre de fichiers binaires
  3. Suppression d'un grand nombre de fichiers binaires
  4. Nouveau "début" de dépôt prévu

Donc, effectivement, nous voulons 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 commencer un nouveau dépôt avec la version actuelle.

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

88voto

Paul Points 12977

Vous pouvez supprimer le bloat binaire et garder le reste de votre histoire. Git vous permet de réorganiser et d'écraser les commits précédents, de sorte que vous pouvez combiner uniquement les commits qui ajoutent et suppriment vos gros fichiers binaires. Si les ajouts ont tous été faits 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 commits qui ajoutent et suppriment vos fichiers binaires et notez leurs SHA1, par exemple 2bcdef y 3cdef3 .

Ensuite, pour éditer l'historique du repo, utilisez rebase -i avec son option interactive, en commençant par le parent du commit où vous avez ajouté vos binaires. Cela 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 supprimer la ligne qui dit pick 3cdef3 de la liste. Vous disposez maintenant d'une liste d'actions pour l'interactif rebase qui combinera les commits qui ajoutent et suppriment vos binaires en un seul commit dont le diff est juste tout autre changement dans ces commits. Ensuite, il réappliquera tous les commits suivants dans l'ordre, lorsque vous lui direz de terminer :

$ git rebase --continue

Cela prendra une minute ou deux.
Vous avez maintenant un repo qui n'a plus les binaires qui arrivent ou partent. Mais ils continueront à occuper de l'espace parce que, par défaut, Git conserve les modifications pendant 30 jours avant qu'elles ne puissent être récupérées, 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 bloat mais gardé le reste de votre histoire.

26voto

davitenio Points 1089

Vous pouvez utiliser git filter-branch avec grafts 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 dépôt. 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 arguments.

20voto

Pat Notz Points 46841

Grâce au post de JesperE, j'ai regardé dans git-filter-branch -- c'est peut-être ce que vous voulez. Il semble que vous pourriez également conserver vos commits antérieurs, sauf qu'ils auraient été modifiés depuis la suppression de vos Big Files. Depuis le Page de manuel de git-filter-branch :

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

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

Assurez-vous de lire cette page de manuel... évidemment vous voudrez faire cela sur un clone de votre dépôt pour être sûr que cela fonctionne comme prévu.

5voto

JesperE Points 34356

Est git-fast-export ce que vous recherchez ?

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

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