Git钩子用于差异化sqlite表

11

我在Git仓库中有一个Sqlite数据库。今天,我想对比两个不同提交中的视图差异。我的做法如下:

$ sqlite3 -list file.sqlite "SELECT * FROM contact_list_detailed" >/tmp/newlist
$ git checkout 51c24d13c file.sqlite
$ sqlite3 -list file.sqlite "SELECT * FROM contact_list_detailed" >/tmp/oldlist
$ git checkout -- file.sqlite
$ diff /tmp/oldlist /tmp/newlist

这个方法是有效的,如果需要的话也可以编写脚本。但是,有没有使用钩子的“好”方法呢?

3个回答

40

这里介绍如何使用Git的textconv功能显示SQLite文件版本间的差异。它只是执行了一个转储,对于大型数据库可能不是超级高效的方式。无需挂钩。

由于该链接似乎已不存在,因此我使用存档版本。

其要点是,在Git属性文件(.gitattributes .git/info/attributes)中添加一个模式匹配以强制进行SQLite3差异(假设您的数据库文件具有扩展名.sqlite3):

*.sqlite3 diff=sqlite3

接着在你的 Git 配置文件(~/.gitconfig.git/config)中添加以下内容:

[diff "sqlite3"]
    binary = true
    textconv = "echo .dump | sqlite3"

如果你只想追踪模式更改,请使用.schema而不是.dump


1
我猜无论如何将其保存为文本格式都是一个好习惯。但这仍然是一个不错的解决方案。+1 - Niclas Nilsson
3
我不得不使用这个 textconv = "f(){ sqlite3 -batch \"$1\" .dump; }; f" - CMCDragonkai

6

如果想要在git中跟踪二进制数据库文件,会遇到一些问题。由于SQLite数据库可能不同,即使其中存储的数据没有改变,git status的输出也无法确定是否应该提交,而git diff只会显示像“Binary files a/foo.sql and b/foo.sql differ”这样的内容。为了从git diff中得到正确的输出,基本上有两种方法可以比较相应的文件:

  1. 使用textconv将文件转换为纯文本,如Biran Minton的答案所示。
  2. 设置一个自定义的diff应用程序,能够直接创建差异。

下面我将概述第二种方法,使用SQLite附带的sqldiff。与textconv方法一样,需要更改属性和配置文件。

attributes:

*.sql* diff=sqldiff

配置:

[diff "sqldiff"]
    command = gitsqldiff

上面的 gitsqldiff 字符串是一个包装脚本,它需要安排由git提供的参数以便让 sqldiff 使用。该脚本必须是可执行的,并且可以通过 PATH 环境变量访问(将其放在 ~/bin 中应该没问题)。 因为(截至目前)sqldiff 的退出值始终为0,因此相当无用,我们必须检查它打印了什么以向用户提供反馈 - 特别是在数据库中没有任何更改时的情况下,sqldiff 不会产生任何输出。 为了这样做并向用户显示完整的输出,我们使用一个技巧,将输出重定向到附加文件描述符和 stdout 通过 teegitsqldiff:
#!/bin/sh
echo "$1:"

# Duplicate sqldiff's output for consumption by wc and stdout.
# This enables us to check for an empty output but still see
# sqldiffs messages if there are any.
sqldiff "$2" "$5" 2>&1 | {
    tee /dev/fd/3 |
        if [ $(wc -c) -eq 0 ]; then
            echo "  nothing changed according to sqldiff"
        fi
} 3>&1

当然,这并不意味着将sql文件置于git仓库中是首选,但可能有助于实现一个可行的工作流程。

5
您可以使用 HEADHEAD^ 访问之前和当前的版本;有关示例,请参见 git post-commit hook - script on committed files
使用 git show 将文件提取到临时目录,而不覆盖工作副本。
我不会在 git 中存储二进制文件,除非绝对必要。 如果您使用 sqlite3 file.sqlite .dump 创建 SQL 命令的文本文件,并将其放入 git 中,则可以避免许多麻烦,只需将二进制数据库作为生成的文件即可。 (但是需要在必要时注意重新生成 SQL 文件。)

1
我可以将我的db文件放入.gitignore文件中,然后使用pre-commit-hook将内容转储到一个我添加到git repo的文件中吗?然后我使用某种pre-pull-hook从这个转储的内容创建sqlite二进制文件? - Niclas Nilsson
2
是的(但我猜你想要“post-checkout”)。 - CL.
你说的真的很有道理,我猜这确实是正确的做事方式。我现在没有时间真正实施这个。但我会将你的答案标记为已接受。 - Niclas Nilsson
@NiclasNilsson 回复了一个非常古老的帖子,但是你能够让它工作吗?如果可以的话,如果您能包括步骤,那将是很好的。 - C. Binair

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接