2010-02-12 6 views
16

Voici le problème:Est-il possible de garder un fichier non versionné dans un dépôt git

J'ai créé git nue chez moi partenaire d'hébergement, que je l'utilise comme référentiel de référence de tous les emplacements/ordinateurs que je maintiens mon projet de.

La chose est que mon projet utilise un fichier db sqlite, qui ne cesse de croître régulièrement (il est sur le point 150Mo pour l'instant). Au fil du temps, mon dossier .git devient de plus en plus gros (environ 1 Go récemment). Et mon espace d'hébergement est limité.

J'ai besoin du dépôt nu pour contenir la version HEAD de ce fichier db mais je ne ai pas vraiment besoin de garder son histoire de version.

Ainsi, pour gagner un peu d'espace, de temps en temps, je supprimer le fichier db de l'histoire, nettoyer le dépôt et recréez la version nue. Cela fonctionne, mais c'est assez pénible.

Est-il possible de dire git pour ne garder que la dernière version d'un fichier et déposer son histoire?

+1

question connexe: http://stackoverflow.com/questions/540535/managing-large-binary-files-with-git – jfs

+0

cela peut ne pas être une solution directe mais pourquoi ne pas garder le fichier de base de données non-tracé et faire un script que synchroniser votre fichier avec le fichier dans le référentiel principal? –

+0

Pourquoi avez-vous besoin de ce fichier db pour conserver une copie du schéma ou des données? Ou les deux? –

Répondre

5

Courte réponse: non. Réponse plus utile: Git ne suit pas les fichiers individuellement, donc lui demander de jeter l'historique d'un seul fichier signifierait qu'il devrait réécrire complètement tout son historique sur chaque commit, et cela mène à tous sortes de problèmes laids.

Vous pouvez stocker un fichier dans une balise annotée, mais ce n'est pas très pratique. Il va essentiellement comme ceci:

ID=`git hash-object -w yourfile.sqlite` 
git tag -a -m "Tag database file" mytag $ID 

En aucun cas, cette mise à jour ne pratique (ou même créer) le fichier de base de données dans l'arborescence de travail pour vous ... vous auriez à utiliser des scripts de crochet pour émuler cela.

La divulgation complète: Je ne suis pas complètement sûr que ce soit effectivement possible de pousser blobs marqués qui ne sont pas couverts par l'histoire normale. Je soupçonne que ce n'est pas le cas, auquel cas cette recette serait beaucoup moins utile.

3

Vous pouvez toujours utiliser .gitignore fichier de configuration pour cela - depuis le début.

Et ... (à partir this thread: Coup de coeur pour Björn Steinbrink)

Utiliser un filtre-branche à la chute des parents le premier vous vous engagez voulez garder, puis déposer l'ancien cochonneries.

Disons $drop est le hachage du dernier engagement que vous voulez laisser tomber. Pour garder les choses saine et simple, assurez-vous le premier engagement que vous voulez garder, ie. l'enfant de $drop, n'est pas une fusion valider. Ensuite, vous pouvez utiliser:

git filter-branch --parent-filter "sed -e 's/-p $drop//'" \ 
    --tag-name-filter cat -- \ 
    --all ^$drop 

Les réécritures au-dessus des parents de tous les commits qui viennent « après » $drop.

Vérifiez les résultats avec gitk.

Ensuite, pour nettoyer tous les vieux cruft.

D'abord, les références de sauvegarde de filtre branche:

git for-each-ref --format='%(refname)'refs/original | \ 
    while read ref 
    do 
      git update-ref -d "$ref" 
    done 

Ensuite, nettoyer votre reflogs:

git reflog expire --expire=0 --all 

Et enfin, remballer et laisser tomber tous les objets anciens inatteignables: git remballer git pruneau # -ad Pour les objets qui remballer -ad aurait pu laisser autour

À ce moment-là, tous les chose menant à et incluant $ drop devrait être disparu.

+0

Je cherche une solution qui * garde * une copie de la base de données dans le dépôt –

+0

Ensuite, vous pouvez créer un script qui supprime l'historique après chaque validation. –

4

Il semble que vous cherchiez la solution au mauvais problème.

Les fichiers binaires volumineux doivent souvent être stockés dans des référentiels, mais je ne pense pas qu'une base de données SQLite doive vraiment être stockée sous sa forme binaire dans un référentiel. Au lieu de cela, vous devriez garder le schéma en contrôle de version, et si vous avez besoin de conserver des données, mettez-le en série (vers XML, JSON, YAML ...) et la version aussi. Un script de construction peut créer la base de données et désérialiser les données si nécessaire. Comme un format de sérialisation basé sur du texte peut être suivi efficacement par Git, vous ne vous soucierez pas de l'espace disponible pour conserver les versions antérieures même si vous ne pensez pas avoir besoin d'y accéder.

+0

ce qui permettrait à git d'appliquer ses techniques habituelles de compression et de différentiation, ce qui rendrait cette opération beaucoup moins douloureuse. La seule chose à prendre en compte serait de créer un format de sérialisation correctement trié qui minimiserait la taille du diff. –

+0

Je ne suis pas d'accord. Si vous regardez le format Slite, ce n'est pas ce binaire. Git est parfaitement capable de générer des différences utilisables avec lui. Le seul avantage serait que les différences seraient plus faciles à lire en cas de conflit. Avoir à gérer une couche de sérialisation de texte est beaucoup trop de travail si vous me demandez –

+0

Ceci est une bonne idée ... y a-t-il un script préféré que vous avez pour faire de la sérialisation à base de texte? – AlexMA

0

Si je comprends bien votre question, je pense avoir une solution simple.

  1. Première sauvegarde le fichier quelque part,
  2. supprimer de votre répertoire/arbre de travail. Pas git rm, juste rm.
  3. Ne commit.
  4. Assurez-vous que le fichier est ajouté à .gitignore.

Lors de validations ultérieures, GIT n'essaiera plus d'ajouter ce fichier. Notez que vous aurez toujours le fichier stocké dans les validations précédentes. C'est juste que vous ne l'ajouterez pas à chaque engagement que vous ferez dans le futur. Afin de le supprimer des commits antérieurs, vous aurez besoin des conseils de quelqu'un avec plus d'expérience GIT que j'ai.

0

Ajouter à votre sqlite.db .gitignore.

Pour vérifier dans le db actuel (potentiel) poussant avec la branche courante:

branch="$(sed 's,.*refs/heads/,,' "$(git rev-parse --git-dir)"/HEAD)" 
objectname=$(git hash_object -w "$(git rev-parse --show-toplevel)/sqlite.db") 
git tag -f db_heads/$branch $objectname 

en poussant une branche:

git push origin $branch +db_heads/$branch 

Lorsque vous lisez une branche:

git fetch origin $branch tags/db_heads/$branch:tags/db_heads/$branch 

lors de la vérification d'une branche:

git checkout $branch 
git cat-file -p db_heads/$branch >"$(git rev-parse --show_toplevel)/sqlite.db" 

Et cela devrait le faire, je pense.

Questions connexes