2009-02-15 8 views
6

Ho un file di registro memorizzato in un database SQLite che vorrei distribuire in un repository git.Tabella SQLite con fusione Git

Successivamente, vorrei che le modifiche al file di registro si unissero automaticamente con l'originale.

Funzionerà? Una fusione binaria automatica in un file SQLite esploderà il più delle volte?

+1

Sarà davvero una fusione? Cioè, il file cambierà in modo diverso su due rami separati? –

risposta

6

Non sono convinto che git sia davvero lo strumento per il tuo lavoro. git è uno strumento di gestione del codice sorgente distribuito, non uno strumento di replica del database.

L'unica fusione automatica che git tenterà è l'unione di file di testo. Un file di registro è (di solito) un file di testo, quindi perché non inserirlo direttamente in git e non in un database?

+0

Grazie per il suggerimento. –

5

Dubito che qualsiasi sistema di controllo di versione generica (git, svn, cvs, etc.) in grado di gestire database in modi che hai descritto. Se insisti a utilizzare git per unire i database, la soluzione migliore è convertire il database in un file di testo, unire il file di testo e ricreare il database. Ad esempio,

sqlite3 .dump > dump_file.txt 

possibile creare tutte le istruzioni SQL necessarie per rifare il database, poi si fa roba per il file scaricato, quindi fare un database SQLite con

sqlite3 newdatabase.db < modified_dump_file.txt 

Si dovrebbe essere in grado di automatizzare questo usando una sorta di git hook (non ho molta familiarità con git).

1

Non v'è alcun modo per unire i file binari in modo corretto questo nel caso generale, in modo da git non può e non lo farà.

Con qualche sforzo, si potrebbe usare git per discariche di database versione, ma ad eccezione di casi molto semplici, si dovrà fare di più che usare dritto discariche. Dovrai pensare a come le righe di dumping sono ordinate in base alle colonne chiave, per lo meno. Altrimenti si ottengono conflitti spuri o fusioni che producono dump sintatticamente validi che rappresentano un database di dati inutili.

p.es., se diverse versioni di fila con la stessa chiave presentarsi in diverse regioni Linea di diverse versioni della discarica, git potrebbe pensare ragionevole per tenerli entrambi. Il dump risultante avrebbe due rappresentazioni della stessa riga, che non ha senso.

In breve, probabilmente sarete infelice cercando di mantenere un database di versione utilizzando un sistema di controllo del codice sorgente.

17

è necessario definire merge costume e driver diff nella vostra configurazione git, e poi utilizzare gli attributi per associarli con i file.

Questo semplifica l'unione di un semplice testo sui dump, quindi potrebbe produrre molto sciocchezze. Avrai assolutamente bisogno di controllare il suo lavoro per assicurarti che abbia fatto la cosa giusta Tuttavia, dovresti toglierti dalla semplicità.

Nel vostro .git/config:

[merge "sqlite3"] 
    name = sqlite3 merge driver 
    driver = merge-sqlite3 %O %A %B 

[diff "sqlite3"] 
    name = sqlite3 diff driver 
    command = diff-sqlite3 

in.gitattributes:

signons.sqlite diff=sqlite3 merge=sqlite3 

e da qualche parte nel vostro percorso, chiamato diff-sqlite3

#!/usr/bin/perl -w 

use File::Temp qw/ :POSIX /; 
use IPC::Run qw/run/ ; 

@ARGV == 7 or die sprintf 'wtf %s', join(' ', @ARGV); 

my ($name, $x, $y) = ($ARGV[0], $ARGV[1], $ARGV[4]); 

my ($a, $b); 

eval { 
    $a = tmpnam(); 
    $b = tmpnam(); 

    run ['sqlite3', $x, '.dump'], '>', $a or die 'sqlite3 failed'; 
    run ['sqlite3', $y, '.dump'], '>', $b or die 'sqlite3 failed'; 

    print "diff-sqlite3 a/$name b/$name\n"; 
    run ['diff', '-u', $a, $b, '--label', "a/$name", '--label', "b/$name"], '>', \*STDOUT; 

    unlink $a; 
    unlink $b; 
    1; 
} or do { 
    unlink $a if defined $a; 
    unlink $b if defined $b; 
    die [email protected]; 
} 

anche nel percorso, chiamato merge-sqlite3

#!/usr/bin/perl -w 

use File::Temp qw/ :POSIX /; 
use IPC::Run qw/run/ ; 

@ARGV == 3 or die sprintf 'wtf %s', join(' ', @ARGV); 

my ($o, $a, $b) = @ARGV; 

print "MERGEING SQLITE FILES $o $a $b\n"; 


eval { 
    $ad = tmpnam(); 
    $bd = tmpnam(); 
    $od = tmpnam(); 

    run ['sqlite3', $o, '.dump'], '>', $od or die 'sqlite3 failed'; 
    run ['sqlite3', $a, '.dump'], '>', $ad or die 'sqlite3 failed'; 
    run ['sqlite3', $b, '.dump'], '>', $bd or die 'sqlite3 failed'; 

    run ['merge', $ad, $od, $bd] or do { 
    my $newname = "$a.dump"; 
    my $n = 0; 
    while (-e $newname) { 
     ++$n; 
     $newname = "$a.dump.$n"; 
    } 
    print "merge failed, saving dump in $newname\n"; 
    rename $ad, $newname; 
    undef $ad; 
    die 'merge failed'; 
    }; 

    unlink $a or die $!; 
    my $err; 
    run ['sqlite3', $a], '>', \*STDOUT, '2>', \$err, '<', $ad; 
    if ('' ne $err) { 
    print STDERR $err; 
    die 'sqlite3 failed'; 
    } 

    unlink $ad if defined $ad; 
    unlink $bd; 
    unlink $od; 
    1; 
} or do { 
    unlink $ad if defined $ad; 
    unlink $bd if defined $bd; 
    unlink $od if defined $od; 

    die [email protected]; 
} 

Ho appena hackerato questi in su in questo momento, ora così potresti dover stirare i nodi.

vedere: http://git-scm.com/docs/gitattributes e http://git-scm.com/docs/git-config

+0

Questo è fantastico! Grazie, @smoofra! Molto utile! – lindes

1

ho reimplementato il driver diff sopra in shell script e ha scoperto che non funziona correttamente in tutti i casi. Lo script assume i primi due parametri danno i file diff, ma secondo man git i parametri indicati allo script sono:

percorso nuovo-vecchio file-mode old-esadecimale vecchio-nuovo file-hex nuova modalità

Ecco il diff che ha fatto per me:

#!/bin/sh 

FILE_PATH=$1 
OLD_FILE=$2 
OLD_HEX=$3 
OLD_MODE=$4 
NEW_FILE=$5 
NEW_HEX=$6 
NEW_MODE=$7 

A=`tempfile` 
B=`tempfile` 
test -f ${A} && test -f ${B} || exit 1 

sqlite3 ${OLD_FILE} .dump > ${A} && 
sqlite3 ${NEW_FILE} .dump > ${B} && 
diff -u ${A} ${B} --label "${FILE_PATH}@${OLD_HEX}" --label "${FILE_PATH}@${NEW_HEX}" 

rm ${A} 
rm ${B} 
2

Anche se questa domanda è stato chiesto 8+ anni fa, ho rilasciato uno strumento che fa esattamente quello che stai chiedendo. Utilizza un driver diff personalizzato che sfrutta lo sqlite project tool 'sqldiff', UUID come chiavi primarie e abbandona il rowid sqlite. È ancora in alpha, quindi il feedback è apprezzato.

https://github.com/cannadayr/git-sqlite