2009-02-15 62 views
6

我有一个日志文件存储在SQLite数据库,我想分布在一个Git仓库。与Git合并SQLite表

后来我想改变日志文件自动与原来的合并。

这是否正常工作?自动二进制文件合并成一个SQLite文件会不会更频繁?

+1

它真要合并?也就是说,文件在两个独立的分支上会有不同的变化吗? – 2009-02-15 09:32:58

回答

6

我不相信git真的是你工作的工具。 git是一个分布式源代码管理工具,而不是数据库复制工具。

git将尝试的唯一自动合并是合并文本文件。日志文件通常是一个文本文件,为什么不直接把它直接放到git中,而是先放到数据库中呢?

+0

感谢您的建议。 – 2009-02-15 09:57:09

5

我怀疑任何通用版本控制系统(git,svn,cvs等)都可以用你描述的方式处理数据库。如果你坚持使用git来合并数据库,最好的办法是将数据库转换为文本文件,合并文本文件并重新创建数据库。例如,

sqlite3 .dump > dump_file.txt 

可以建立必要的所有SQL语句重新使数据库,那么你做的东西到转储文件,然后做一个SQLite数据库与

sqlite3 newdatabase.db < modified_dump_file.txt 

您应该能够使用某种类型的git hook来自动执行此操作(我对git不太熟悉)。

1

在一般情况下,没有办法正确地合并二进制文件,所以git不能也不会这样做。

通过一些努力,您可以使用git来版本化数据库转储,但除非是非常简单的情况,您必须做的不仅仅是使用直接转储。您至少需要考虑转储的行如何根据您的关键列进行排序。否则你会得到虚假的冲突,或者合并产生代表垃圾数据库的语法上有效的转储。 F.ex.,如果具有相同关键字的行的不同版本显示在不同版本转储的不同行区域中,git可能认为保留它们两者都是合理的。由此产生的转储将具有同一行的两个表示,这是无稽之谈。

简而言之,您可能会不高兴尝试使用源代码管理系统保持数据库版本。

17

您需要在git配置中定义自定义合并和差异驱动程序,然后使用属性将它们与文件相关联。

这只是在垃圾堆上做一个简单的文本合并,所以它可能会产生完全的废话。你绝对需要检查它的工作,以确保它做了正确的事情。它应该从简单的合并中解脱出来。

在你的.git /配置:

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

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

。gitattributes:

signons.sqlite diff=sqlite3 merge=sqlite3 
在你的路径

而且某处,一个名为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]; 
} 

也是在你的路径,命名合并-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]; 
} 

我砍死这些了,现在,现在你可能不得不解决问题了。

看到:http://git-scm.com/docs/gitattributeshttp://git-scm.com/docs/git-config

+0

这太棒了!谢谢@smoofra!很有帮助! – lindes 2012-05-17 14:45:49

1

我在shell脚本重新实现上面的差异驱动程序,发现它并非在所有情况下正常工作。脚本假设前两个参数给出的文件差异,但根据man git给脚本的参数是:

路径旧文件旧六角旧模式的新文件新六角新模式

下面是为我做的DIFF:

#!/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

即使这个问题被问8+年前,我已经发布了一个工具,做你问什么了。它使用一个自定义比较驱动程序,利用sqlite项目工具'sqldiff',UUID作为主键,并离开sqlite rowid。它仍然在阿尔法,所以反馈表示赞赏。

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