Git et les fichiers zip

01/08/2015

Si un projet se base sur un fichier zip (pas seulement les fichier “.zip”, mais tout fichier qui zipe le contenu comme les fichiers libreoffice, openoffice, vym, etc…) alors vous allez vous confronter au souci de versionnement par Git. Car celui-ci les gère comme étant des fichiers binaires. Or vous voulez versionner le contenu. Et bien voilà ma méthode (certes pas des plus jolies mais ça marche)

Je me suis trouvé confronté à cette situation en voulant versionner un livre sur le langage Go que je tape depuis pas mal de temps. Jusqu’ici je versionnais le fichier “.vym” (car j’utilise vym pour ça, je parle bien de View Your Mind hein, mais j’en reparelarai bientôt de tout ça) qui est ni plus ni moins qu’un fichier zippé et renommé en “.vym”. Or, je me suis fais une bonne frayeur en écransant connement mon fichier après un “git pull” trop rapidement validé.

Résultat, git a écrasé le fichier sans faire de “diff” - ce qui est logique car il ne le fait pas pour les fichier binaires.

Bref, pour éviter ce genre de boulette je me suis simplement ateler à versionner non plus le fichier, mais son contenu. Ça vous parait peut-être barbarre mais ça marche.

Premier chose à faire, on teste !

Testons la construction

On commence par se placer dans un dossier et on va décompresser le contenu du fichier (vous pouvez le faire avec un fichier .odt, un .vym ou un .docx si vous êtes nostalgique de Word…)

mkdir ~/test/constructor && cd ~/test/constructor
unzip /chemin/vers/fichier.vym

On voit alors quelques fichiers et répertoires, on reconstruit:

zip -r test ./*
mv test.zip ../fichier-reconstruit.vym

Et on ouvre ce fichier (placé dans “~/test/”). Tout à l’air ok ! Bien on passe à la suite.

Automatison

Dans mon répertoire git, j’ai donc créé un Makefile, et voilà ce que j’ai entré:


FILE="monfichier.vym"

explode:
    mkdir src/ || :
    cd src && unzip ../$(FILE)
    
implode:
    cd src && zip -r ../temp ./*
    mv temp.zip $(FILE)

Ainsi, quand je tape “make explode” le contenu de mon projet est décompressé dans le répertoire “src” que je vais pouvoir versionner. Et quand je récupère le projet depuis “git” (”git pull”) alors je tape simplement “make implode” pour reconstruire mon fichier.

Coté git

Coté git, je ne sauvegarde pas le fichier de travail (ici mon fichier “.vym”) car il va être reconstruit par le makefile. Donc mon fichier .gitignore est de la forme:

*.vym

Du coup, je suis tranquile, et surtout que la suite des opérations va engendrer une création de fichiers de sauvgarde, par conséquent on les ignorera aussi puisqu’ils utiliseront l’extension “.vym” (encore une fois, adaptez mes exemples à votre type de fichier)

Maintenant… les problèmes commencent…

Les problèmes et les solutions

Il se peut que votre “fichier zip” ait besoin de répertoires vides, par exemple Vym demande un répertoire “flags” et un autre “images” non vide. Or, git ne les versionne pas. Git ne peut gérer que des fichiers en fonction de leur chemin, et par conséquent un répertoire “vide” n’est pas un fichier, il va le zapper.

La solution, est simplement de créer des fichiers vides dans ces répertoires. Ainsi dans le Makefile, on va créer une cible de préparation “_prep” (le underscore pour éviter de le faire apparaitre dans l’autocompletion de bash) qui va écrire des fichiers nommés “.gitkeep” seulement dans les répertoires de projet (en évitant donc .git). Je remercie cette réponse de StackOverFlow.


FILE="monfichier.vym"

explode: _explode _prep

_explode:
    mkdir src/ || :
    cd src && unzip ../$(FILE)
    
implode:
    cd src && zip -r ../temp ./*
    mv temp.zip $(FILE)

_prep:
    find . -type d -empty -not -path "./.git/*" -exec touch \{\}/.gitkeep \;

J’ai décalé la cible “explode” en “_explode” pour changer l’ordre d’appel. Si vous suivez bien le Makefile, “make explode” va appeler “_explode” qui va decompresser le zip, puis “_prep” qui prépare les répertoires en “touchant” des fichier “.gitkeep”.

Autre chose, j’ai décidé de sauvegarder mon fichier de travail avant de le recréer. On ajoute une dernière règle nommée “_backup” qui copie le fichier en le datant à la seconde.

J’ajoute aussi un peu de propreté en séparant le nom de fichier et son extension.


BASE:="monfichier"
EXT:=".vym"
FILE:=$(BASE)$(EXT)
DATE=$(shell date "+%Y%m%d-%H%M%S")

explode: _explode _prep

_explode:
    mkdir src/ || :
    cd src && unzip ../$(FILE)
    
implode: _backup
    cd src && zip -r ../temp ./*
    mv temp.zip $(FILE)

_prep:
    find . -type d -empty -not -path "./.git/*" -exec touch \{\}/.gitkeep \;

_backup:
    cp $(FILE) $(BASE)-$(DATE)$(EXT)

Comme ça, chaque fois que j’appelle “make implode” pour reconstruire mon fichier “vym”, j’ai une sauvegarde de faite.

Petite parenthèse, dans un makefile on peut assigner une variable en utilisant “:=” ou “=”. La différence est que “:=” var interpréter “de suite” la valeur à assigner; alors que “=” attendra qu’on appelle la variable pour que sa valeur soit interprétée. Du coup, ici, la variable “$(DATE)” sera interprété au moment de l’appel dans “_backup”. C’est pas super utile ici mais par habitude…

Et dans la vie réelle ?

Dans la vie réelle, j’ai testé et ça se passe bien ! Voici ce qu’il peut arriver (et qui d’ailleurs m’ait arrivé):

  • je prend mon pc portable et je commence à toucher mon fichier vym
  • je suis content, je me dis que je peux pousser tout ça sur mon serveur git
  • je lance “make explode” puis “git commit src && git push” et là… le drame !

Git me dit que je suis pas à jour ! ça veut dire que j’ai oublié de faire un “pull” avant de pousser. Effectivement, la veille j’ai travaillé sur mon pc de bureau et j’avais poussé. Mais tête en l’ait que je suis, j’ai oublié cette scéance de boulot.

Il va se passer quoi ?

En premier lieu, je pull ! et je reconstruit mon fichier avec “make implode”. Vym recharge mon fichier. Deux possibilités:

  • Ça a l’air pas mal - auquel cas on peut refaire un “make explode” et pousser les le merge.
  • Tout est pété - là on transpire…

Si tout est pété, comme on a été intelligent, on a une sauvegarde qui a été créé lors du “make implode” dont le nom est la date d’aujourd’hui + l’heure de sauvegarde. Je peux reprendre cette version, me débrouiller pour reconstruire le fichier et commiter.

Au pire, on peut toucher le fichier XML contenu dans “src” car, je vous le rappelle, on travaille désormais avec des fichiers non compressés ce qui a pour effet de vous donner les “diffs”, voir les lignes qui ont sautées, etc.

Donc en clair, ma méthode de décompression + makefile qui fait le travaille de sauvegarde à ma place, ça me sauve des heures de travail et ma tension me remercie.

Notez aussi que cette technique peut s’appliquer aux fichier “.tar”, “.tar.gz” ou encore “.7z”. Le tout étant simplement de s’adapter au format. Le principe, je vous le rapelle, étant de versionner le contenu du fichier compressé et non pas le fichier compressé lui-même.

D’autres solutions ? d’autres méthodes ? faites le moi savoir !

Ça peut vous intéresser aussi


Git color graph

Suite à deux excellents billets proposés par Gérald - Introduction à Git Partie 1 - ...


Xmonad et les tiling desktop

On se l’accorde tous, Gnome ou KDE sont de ...


Python map zip lambda et filter

Python est un langage fort de principes de développement permettant ...


Ubuntu et Debian, pourquoi je les évite

Debian et Ubuntu sont aujourd’hui des distributions extrêmement bien ...

Merci de m'aider à financer mes services

Si vous avez apprécié cet article, je vous serai reconnaissant de m'aider à me payer une petite bière :)

Si vous voulez en savoir plus sur l'utilisation de flattr sur mon blog, lisez cette page: Ayez pitié de moi

Commentaires

Ajouter un commentaire

Jokester - 24/02/2016

J’ai peut-être pas bien saisi la manip’, mais dans mon cas quand je produis un zip / binaire / produit d’une transformation de fichiers sources : je ne le commite pas (.gitignore). Ça peut néanmoins poser problème lors de la conception de librairies directement utilisables par un tiers, sans outils de compilation. Par exemple fournir sur github des fichiers js dans ./dist/malib.js et ./dist/malib.min.js qui ont été générés à partir des sources de ./src

Ajouter un commentaire

(*) Votre e-mail ne sera ni revendu, ni rendu public, ni utilisé pour vous proposer des mails commerciaux. Il n'est utilisé que pour vous contacter en cas de souci avec le contenu du commentaire, ou pour vous prévenir d'un nouveau commentaire si vous avez coché la case prévue à cet effet.