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:
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.
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.
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 .
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.
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.
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.
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.
À 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).
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
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.Propriétés indésirables d'OTABS
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 .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.git gc
pour nettoyer votre référentiel de tous les fichiers dont vous ne voulez plus.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.
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.git rm --cached * .gitignore
.rm -fr * .gitignore
. Le répertoire interne .git
reste inchangé, car le caractère générique *
ne lui correspond pas.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
git Push <remote> 1.0.0bin
.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
git checkout 1.0.0bin -- VeryBigBinary.exe
.1.0.0bin
, auquel cas vous devrez au préalable git fetch <remote> 1.0.0bin
.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:
git Push <remote> :refs/tags/1.0.0bin
git tag -l | xargs git tag -d && git fetch --tags
. Extrait de SO 1841341 avec une légère modification.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 190486git clone -b master --single-branch <url>
au lieu de git clone
.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.8bin
2.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.
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.
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 .