使用Git合并的SQLite表

时间:2009-02-15 09:10:33

标签: git sqlite

我有一个存储在SQLite数据库中的日志文件,我想在git存储库中分发。

稍后我希望更改日志文件以自动与原始文件合并。

这会起作用吗?将自动二进制合并到SQLite文件中会更频繁地爆炸吗?

6 个答案:

答案 0 :(得分:17)

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

这只是在转储上进行简单的文本合并,因此它可以很好地产生完全废话。你绝对需要检查它的工作,以确保它做正确的事情它应该从简单的合并中解脱出来。

在.git / config中:

[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 $@; 
}

也在您的路径中,名为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 $@; 
}

我现在只是把它们砍掉了,现在你可能不得不解决这些问题。

请参阅:http://git-scm.com/docs/gitattributeshttp://git-scm.com/docs/git-config

答案 1 :(得分:6)

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

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

答案 2 :(得分:5)

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

sqlite3 .dump > dump_file.txt

可以创建重新创建数据库所需的所有sql语句,然后你对转储文件做东西,然后用

创建一个sqlite数据库
sqlite3 newdatabase.db < modified_dump_file.txt

你应该能够使用某种git钩子自动化它(我对git不太熟悉)。

答案 3 :(得分:2)

即使这个问题在8年多前被问过,我也发布了一个可以满足您要求的工具。它使用自定义diff驱动程序,利用sqlite项目工具'sqldiff',UUID作为主键,并且不使用sqlite rowid。它仍处于alpha状态,因此感谢您的反馈。

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

答案 4 :(得分:1)

在一般情况下,无法正确合并二进制文件,因此git不能也不会这样做。

通过一些努力,您可以使用git来版本化数据库转储,但除了非常简单的情况之外,您必须做的不仅仅是使用直接转储。您至少需要考虑基于关键列对转储行的排序方式。否则,你会得到虚假的冲突,或合并产生代表垃圾数据库的语法上有效的转储。

F.ex。,如果具有相同键的行的不同版本显示在转储的不同版本的不同行区域中,git可能认为保持它们两者是合理的。生成的转储将有两个同一行的表示,这是无意义的。

简而言之,您可能会因为使用源代码管理系统对数据库进行版本控制而感到不快。

答案 5 :(得分:1)

我在shell脚本中重新实现了上面的diff驱动程序,发现它在所有情况下都无法正常工作。该脚本假设前两个参数为文件提供差异,但根据man git,给脚本的参数是:

路径旧文件旧十六进制旧模式新文件新十六进制新模式

这是为我做的差异:

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