web-dev-qa-db-fra.com

Gestion de gros fichiers binaires avec Git

Je recherche des opinions sur la façon de gérer des fichiers binaires volumineux dont dépend mon code source (application Web). Nous discutons actuellement de plusieurs alternatives:

  1. Copiez les fichiers binaires à la main.
    • Pro: Pas sûr.
    • Contra: Je suis tout à fait contre, car cela augmente le risque d’erreurs lors de la configuration d’un nouveau site/de la migration de l’ancien. Crée un autre obstacle à franchir.
  2. Gérez-les tous avec Git.
    • Pro: Supprime la possibilité d'oublier de copier un fichier important
    • Contra: gonfle le référentiel et réduit la flexibilité pour gérer la base de code et les extractions, clones, etc. prendront un certain temps.
  3. Dépôts séparés.
    • Pro: L'extraction/le clonage du code source est rapide et les images sont correctement archivées dans leur propre référentiel.
    • Contra: Supprime la simplicité d'avoir le seul et unique référentiel Git sur le projet. Cela introduit sûrement d'autres choses auxquelles je n'ai pas pensé.

Quelles sont vos expériences/pensées à ce sujet?

Aussi: quelqu'un a-t-il déjà utilisé plusieurs référentiels Git et les gère-t-il dans un seul projet?

Les fichiers sont des images pour un programme qui génère des PDF avec ces fichiers. Les fichiers ne changeront pas très souvent (comme dans les années), mais ils sont très pertinents pour un programme. Le programme ne fonctionnera pas sans les fichiers.

514
pi.

Si le programme ne fonctionne pas sans les fichiers, il semble que les séparer dans un dépôt séparé est une mauvaise idée. Nous avons de grandes suites de tests que nous séparons dans un dépôt séparé mais ce sont vraiment des fichiers "auxiliaires".

Cependant, vous pourrez peut-être gérer les fichiers dans un référentiel séparé, puis utiliser git-submodule pour les insérer dans votre projet de manière rationnelle. Donc, vous auriez toujours l'historique complet de toutes vos sources mais, si je comprends bien, vous n'auriez qu'une révision pertinente de votre sous-module d'images. La fonction _git-submodule_ devrait vous aider à conserver la version correcte du code en ligne avec la version correcte des images.

Voici un bon introduction aux sous-modules de Git Book.

177
Pat Notz

J'ai découvert git-annex récemment, ce que je trouve génial. Il a été conçu pour gérer efficacement les gros fichiers. Je l'utilise pour mes collections photo/musique (etc.). Le développement de git-annex est très actif. Le contenu des fichiers peut être supprimé du référentiel Git, seule la hiérarchie de l'arborescence est suivie par Git (via des liens symboliques). Cependant, pour obtenir le contenu du fichier, une deuxième étape est nécessaire après avoir tiré/poussé, par exemple:

$ git annex add mybigfile
$ git commit -m'add mybigfile'
$ git Push myremote
$ git annex copy --to myremote mybigfile ## This command copies the actual content to myremote
$ git annex drop mybigfile ## Remove content from local repo
...
$ git annex get mybigfile ## Retrieve the content
## or to specify the remote from which to get:
$ git annex copy --from myremote mybigfile

Il existe de nombreuses commandes disponibles et une excellente documentation sur le site Web. Un paquet est disponible sur Debian .

309
rafak

Une autre solution, depuis avril 2015, est ( Stockage de fichiers volumineux Git (LFS)) (par GitHub).

Il utilise git-lfs (voir git-lfs.github .com) et testé avec un serveur le supportant: lfs-test-server :
Vous pouvez stocker des métadonnées uniquement dans le référentiel git et le fichier volumineux ailleurs.

https://cloud.githubusercontent.com/assets/1319791/7051226/c4570828-ddf4-11e4-87eb-8fc165e5ece4.gif

47
VonC

Jetez un oeil à git bup qui est une extension Git pour stocker intelligemment de gros fichiers binaires dans un référentiel Git.

Vous voudriez l'avoir en tant que sous-module, mais vous n'aurez pas à vous soucier de la difficulté à gérer le référentiel. L'un de leurs exemples d'utilisation est le stockage d'images VM dans Git.

Je n'ai pas réellement vu de meilleurs taux de compression, mais mes référentiels ne contiennent pas de très gros fichiers binaires.

Votre kilométrage peut varier.

30
sehe

Vous pouvez également utiliser git-fat . J'aime que cela ne dépende que du stock Python et rsync . Il prend également en charge le flux de travail Git habituel, avec les commandes explicites suivantes:

git fat init
git fat Push
git fat pull

En outre, vous devez archiver un fichier .gitfat dans votre référentiel et modifier vos fichiers .gitattributes pour spécifier les extensions de fichier que vous souhaitez que git fat gère.

Vous ajoutez un fichier binaire en utilisant le git add normal, qui appelle à son tour git fat en fonction de vos règles de gitattributes.

Enfin, l'avantage est que l'emplacement où vos fichiers binaires sont réellement stockés peut être partagé entre les référentiels et les utilisateurs et prend en charge tout ce que rsync permet de faire.

MISE À JOUR: N'utilisez pas git-fat si vous utilisez un pont Git-SVN. Il finira par supprimer les fichiers binaires de votre référentiel Subversion. Toutefois, si vous utilisez un référentiel Git pur, cela fonctionne à merveille.

27
Carl

J'utiliserais des sous-modules (comme Pat Notz) ou deux référentiels distincts. Si vous modifiez trop souvent vos fichiers binaires, j'essaie de minimiser l'impact de l'énorme référentiel qui nettoie l'historique:

Il y a plusieurs mois, j'avais un problème très similaire: environ 21 Go de fichiers MP3, non classés (mauvais noms, mauvais identifiants, ne sais pas si j'aime ce fichier MP3 ou non ...), et répliqués sur trois ordinateurs.

J'ai utilisé un disque dur externe avec le référentiel principal Git et je l'ai cloné sur chaque ordinateur. Ensuite, j'ai commencé à les classer de la manière habituelle (pousser, tirer, fusionner ... supprimer et renommer plusieurs fois).

À la fin, je n'avais que ~ 6 Go de fichiers MP3 et environ 83 Go dans le répertoire .git. J'ai utilisé git-write-tree et git-commit-tree pour créer un nouveau commit, sans ancêtre de commit, et j'ai démarré une nouvelle branche pointant vers ce commit. Le "journal git" de cette branche ne contenait qu'un seul commit.

Ensuite, j'ai supprimé l'ancienne branche, je n'ai gardé que la nouvelle branche, j'ai supprimé les journaux de référence et exécuté "git Prune": après cela, mes dossiers .git ne pesaient que ~ 6 Go ...

Vous pouvez "purger" l'énorme référentiel de temps en temps de la même manière: votre "clone git" sera plus rapide.

25
Daniel Fanjul

À mon avis, si vous êtes susceptible de modifier souvent ces fichiers volumineux, ou si vous avez l’intention de créer beaucoup de git clone ou git checkout, vous devriez sérieusement envisager d’utiliser un autre référentiel Git (ou peut-être un autre moyen d'accéder à ces fichiers).

Mais si vous travaillez comme nous, et si vos fichiers binaires ne sont pas souvent modifiés, le premier clonage/extraction sera long, mais après cela, il devrait être aussi rapide que vous le souhaitez (compte tenu du fait que vos utilisateurs continuent à utiliser le premier avait).

12
claf

La solution que je voudrais proposer est basée sur les branches orphelines et un léger abus du mécanisme de balise, désormais appelé * stockage binaire de balises orphelines (OTABS)

TL; DR 12-01-2017 Si vous pouvez utiliser l'EFT de github ou un autre tiers, vous devriez le faire. Si vous ne pouvez pas, alors lisez la suite. Soyez averti, cette solution est un hack et doit être traitée comme telle.

Propriétés souhaitables d'OTABS

  • il s'agit d'une solution pure git ​​et git seulement ​​- le travail est effectué sans logiciel tiers (comme git-annex) ni infrastructure tierce (comme LFS de github) .
  • il stocke les fichiers binaires efficacement, c’est-à-dire qu’il ne gonfle pas l’historique de votre référentiel.
  • git pull et git fetch, y compris git fetch --all sont toujours largeur de bande efficace, c’est-à-dire que tous les fichiers binaires volumineux ne sont pas extraits par défaut.
  • cela fonctionne sur Windows.
  • il stocke tout dans un référentiel unique git.
  • cela permet de suppression des binaires obsolètes (contrairement à bup).

Propriétés indésirables d'OTABS

  • cela rend git clone potentiellement inefficace (mais pas nécessairement, selon votre utilisation). Si vous déployez cette solution, vous devrez peut-être conseiller à vos collègues d'utiliser git clone -b master --single-branch <url> au lieu de git clone. Ceci est dû au fait que git clone littéralement clone tout ​​référentiel, y compris des éléments sur lesquels vous ne voudriez normalement pas gaspiller votre bande passante, tels que les commits non référencés. Tiré de SO 4811434 .
  • cela rend git fetch <remote> --tags bande passante inefficace, mais pas nécessairement inefficace en termes de stockage. Vous pouvez toujours conseiller à vos collègues de ne pas l'utiliser.
  • vous devrez périodiquement utiliser une astuce git gc pour nettoyer votre référentiel de tous les fichiers dont vous ne voulez plus.
  • ce n'est pas aussi efficace que bup ou git-bigfiles . Mais il est respectivement plus adapté à ce que vous essayez de faire et plus disponible. Vous rencontrerez probablement des problèmes avec des centaines de milliers de petits fichiers ou avec des fichiers de plusieurs gigaoctets, mais lisez la suite pour contourner le problème.

Ajout des fichiers binaires

Avant de commencer, assurez-vous que toutes vos modifications ont été validées, votre arborescence de travail est à jour et votre index ne contient aucune modification non validée. Il peut être judicieux de transférer toutes vos succursales locales sur votre télécommande (github, etc.) en cas de sinistre.

  1. Créez une nouvelle branche orpheline. git checkout --Orphan binaryStuff fera l'affaire. Cela produit une branche qui est entièrement déconnectée de toute autre branche et le premier commit que vous ferez dans cette branche n'aura pas de parent, ce qui en fera un commit racine.
  2. Nettoyez votre index en utilisant git rm --cached * .gitignore.
  3. Prenez une profonde respiration et supprimez tout l’arbre de travail en utilisant rm -fr * .gitignore. Le répertoire interne .git reste inchangé, car le caractère générique * ne lui correspond pas.
  4. Copiez dans votre VeryBigBinary.exe ou dans votre VeryHeavyDirectory /.
  5. Ajoutez-le && engagez-le.
  6. Maintenant, cela devient délicat - si vous l'enfoncez dans la télécommande en tant que branche, tous vos développeurs la téléchargeront la prochaine fois qu'ils invoqueront git fetch pour obstruer leur connexion. Vous pouvez éviter cela en poussant une balise au lieu d'une branche. Cela peut toujours avoir un impact sur la bande passante et le stockage du système de fichiers de votre collègue s'il a l'habitude de taper git fetch <remote> --tags, mais continuez à lire pour trouver une solution de contournement. Allez-y et git tag 1.0.0bin
  7. Poussez votre tag Orphan git Push <remote> 1.0.0bin.
  8. Juste pour ne jamais pousser votre branche binaire par accident, vous pouvez la supprimer git branch -D binaryStuff. Votre commit ne sera pas marqué pour le garbage collection, car une balise orpheline pointant dessus 1.0.0bin suffit à le maintenir en vie.

Vérification du fichier binaire

  1. Comment puis-je (ou mes collègues) obtenir l'extraction de VeryBigBinary.exe dans l'arborescence de travail actuelle? Si votre branche de travail actuelle est par exemple maître, vous pouvez simplement git checkout 1.0.0bin -- VeryBigBinary.exe.
  2. Cela échouera si vous n'avez pas téléchargé la balise orpheline 1.0.0bin, auquel cas vous devrez au préalable git fetch <remote> 1.0.0bin.
  3. Vous pouvez ajouter le VeryBigBinary.exe dans le .gitignore de votre maître, de sorte que personne de votre équipe ne pollue accidentellement l'historique principal du projet avec le binaire.

Suppression complète du fichier binaire

Si vous décidez de purger complètement VeryBigBinary.exe de votre référentiel local, de votre référentiel distant et des référentiels de vos collègues, vous pouvez simplement:

  1. Supprimer la balise orpheline sur la télécommande git Push <remote> :refs/tags/1.0.0bin
  2. Supprimer localement la balise orpheline (supprime toutes les autres balises non référencées) git tag -l | xargs git tag -d && git fetch --tags. Extrait de SO 1841341 avec une légère modification.
  3. Utilisez une astuce git gc pour supprimer localement votre commit maintenant non référencé. git -c gc.reflogExpire=0 -c gc.reflogExpireUnreachable=0 -c gc.rerereresolved=0 -c gc.rerereunresolved=0 -c gc.pruneExpire=now gc "$@". Il supprimera également tous les autres commits non référencés. Tiré de SO 190486
  4. Si possible, répétez l'astuce git gc sur la télécommande. Cela est possible si vous hébergez vous-même votre référentiel et que cela ne sera peut-être pas possible avec certains fournisseurs git, comme github ou dans certains environnements d'entreprise. Si vous hébergez chez un fournisseur qui ne vous donne pas accès ssh à la télécommande, laissez-le être. Il est possible que l'infrastructure de votre fournisseur nettoie votre commit non référencé au moment opportun. Si vous êtes dans un environnement d'entreprise, vous pouvez conseiller à votre service informatique d'exécuter une tâche cron afin de récupérer votre télécommande une fois par semaine environ. Qu'ils le fassent ou non, cela n'aura aucun impact sur votre équipe en termes de bande passante et de stockage, tant que vous conseillez à vos collègues de toujours git clone -b master --single-branch <url> au lieu de git clone.
  5. Tous vos collègues qui souhaitent se débarrasser des balises orphelines obsolètes n'ont qu'à appliquer les étapes 2 et 3.
  6. Vous pouvez ensuite répéter les étapes 1 à 8 de Ajout des fichiers binaires pour créer une nouvelle balise orpheline 2.0.0bin. Si vos collègues craignent de taper git fetch <remote> --tags, vous pouvez le nommer à nouveau 1.0.0bin. Cela garantira que la prochaine fois qu'ils récupèreront toutes les balises, l'ancien 1.0.0bin ne sera pas référencé et marqué pour le ramassage ultérieur des ordures (étape 3). Lorsque vous essayez d'écraser une balise sur la télécommande, vous devez utiliser -f comme ceci: git Push -f <remote> <tagname>

Postface

  • OTABS ne touche pas votre maître ni aucun autre secteur de code source/développement. Les hachages de validation, toute l’histoire et la petite taille de ces branches ne sont pas affectés. Si vous avez déjà surchargé l’historique de votre code source avec des fichiers binaires, vous devrez le nettoyer séparément. Ce script pourrait être utile.

  • Confirmé de travailler sur Windows avec git-bash.

  • C'est une bonne idée d'appliquer un ensemble de trics standard pour rendre le stockage de fichiers binaires plus efficace. L'exécution fréquente de git gc (sans aucun argument supplémentaire) permet à git d'optimiser le stockage sous-jacent de vos fichiers en utilisant des deltas binaires. Cependant, s'il est peu probable que vos fichiers restent similaires de commit à commit, vous pouvez désactiver complètement les deltas binaires. De plus, comme il n’a aucun sens de compresser des fichiers déjà compressés ou chiffrés, tels que .Zip, .jpg ou .crypt, git vous permet de désactiver la compression du stockage sous-jacent. Malheureusement, c'est un paramètre "tout ou rien" qui affecte également votre code source.

  • Vous voudrez peut-être créer un script pour certaines parties d'OTABS afin de permettre une utilisation plus rapide. En particulier, les étapes de script 2-3 de Suppression complète de fichiers binaires dans un update git hook peuvent donner une sémantique convaincante mais peut-être dangereuse à git fetch ("fetch and delete tout ce qui est obsolète ").

  • Vous voudrez peut-être ignorer l'étape 4 de Suppression complète des fichiers binaires pour conserver un historique complet de toutes les modifications binaires sur la télécommande, au détriment du référentiel central. Les dépôts locaux resteront maigres au fil du temps.

  • Dans le monde Java, il est possible de combiner cette solution avec maven --offline pour créer une construction hors ligne reproductible entièrement stockée dans votre contrôle de version (c'est plus facile avec maven qu'avec gradle). Dans le monde Golang, il est possible de s'appuyer sur cette solution pour gérer votre GOPATH au lieu de go get. Dans python world, il est possible de combiner ceci avec virtualenv pour créer un environnement de développement autonome, sans recourir aux serveurs PyPi pour chaque construction à partir de rien.

  • Si vos fichiers binaires changent très souvent, comme des artefacts de construction, il peut être judicieux de créer une solution qui stocke les 5 versions les plus récentes des artefacts dans les balises orphelines monday_bin, tuesday_bin, ... , friday_bin, ainsi qu'une balise orpheline pour chaque version 1.7.8bin2.0.0bin, etc. Vous pouvez faire pivoter le weekday_bin et supprimer les anciens fichiers binaires quotidiennement. De cette façon, vous obtenez le meilleur de deux mondes: vous conservez l'historique complet ​​de votre code source mais uniquement l'historique pertinent ​​de vos dépendances binaires. Il est également très facile d’obtenir les fichiers binaires d’une balise donnée sans obtenir le code source complet avec tout son historique: git init && git remote add <name> <url> && git fetch <name> <tag> devrait le faire pour vous.

11
Adam Kurkiewicz

SVN semble gérer les deltas binaires plus efficacement que Git.

Je devais choisir un système de gestion des versions pour la documentation (fichiers JPEG, fichiers PDF et fichiers .odt). Je viens de tester l'ajout d'un fichier JPEG et sa rotation quatre fois de 90 degrés (pour vérifier l'efficacité des deltas binaires). Le référentiel Git a augmenté de 400%. Le référentiel de SVN n'a augmenté que de 11%.

Il semble donc que SVN soit beaucoup plus efficace avec les fichiers binaires.

Donc, mon choix est Git pour le code source et SVN pour les fichiers binaires comme la documentation.

9
Tony Diep

git clone --filter de Git 2.19 + clones peu profonds

Cette nouvelle option pourrait éventuellement devenir la solution finale au problème de fichier binaire, si Git et GitHub le développaient et le rendaient assez convivial (ce qu’ils pourraient soutenir n’ont toujours pas atteint pour les sous-modules par exemple).

Il permet uniquement d'extraire les fichiers et les répertoires de votre choix pour le serveur. Il a été introduit avec une extension de protocole à distance.

Avec cela, nous pourrions d’abord faire un clone peu profond, puis automatiser les blobs à récupérer avec le système de construction pour chaque type de construction.

Il existe même déjà un --filter=blob:limit<size> qui permet de limiter la taille maximale de blob à extraire.

J'ai fourni un exemple détaillé minimal de la manière dont la fonctionnalité se présente à l'adresse suivante: Comment cloner un sous-répertoire uniquement d'un référentiel Git?

Je recherche des opinions sur la façon de gérer des fichiers binaires volumineux dont dépend mon code source (application Web). Quelles sont vos expériences/pensées à ce sujet?

J'ai personnellement rencontré des échecs de synchronisation avec Git avec certains de mes hôtes cloud une fois que les données binaires de mes applications Web ont été notées ci-dessus. la marque de 3 Go . Je considérais BFT Repo Cleaner à l'époque, mais cela ressemblait à un hack. Depuis lors, j'ai commencé à ne conserver que des fichiers en dehors de la surveillance Git, mais à utiliser des outils dédiés , tels qu'Amazon S3 pour la gestion des fichiers, la gestion des versions, etc. -up.

Quelqu'un a-t-il déjà utilisé plusieurs référentiels Git et les gère-t-il dans un seul projet?

Oui. thèmes Hugo sont principalement gérés de cette façon. C'est un peu kudgy, mais ça fait le travail.


Ma suggestion est de choisir le bon outil pour le travail . Si c'est pour une entreprise et que vous gérez votre codeline sur GitHub, payez de l'argent et utilisez Git-LFS. Sinon, vous pourriez explorer d'autres options créatives telles que décentralisée, cryptée stockage de fichiers à l'aide de la chaîne de blocs .

Les options supplémentaires à considérer sont Minio et s3cmd .

2
Josh Habdas