├── .gitignore ├── LICENSE ├── Makefile.am ├── README.md ├── configure.ac ├── contrib └── db_config.php ├── reconf └── src ├── Makefile.am ├── git-sqlite-diff.in ├── git-sqlite-merge.in ├── git-sqlite.in ├── schema.sql.in └── util.sh /.gitignore: -------------------------------------------------------------------------------- 1 | *.tar.gz 2 | *.swp 3 | git-sqlite-alpha 4 | Makefile 5 | Makefile.in 6 | aclocal.m4 7 | autom4te.cache/ 8 | config.log 9 | config.status 10 | configure 11 | install-sh 12 | missing 13 | git-sqlite 14 | git-sqlite-diff 15 | git-sqlite-diff-parse 16 | git-sqlite-merge 17 | schema.sql 18 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) [2017] [Rowan Cannaday] 4 | Copyright (c) [2017] [Ryan Murphy] 5 | Copyright (c) [2015] [Assaf Gordon] 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. 24 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | AUTOMAKE_OPTIONS = foreign 2 | SUBDIRS = src 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## SYNOPSIS 2 | git-sqlite is a collection of shell scripts that allows a sqlite database 3 | to be tracked using the git version control system. 4 | 5 | It can be used on an existing database, however, UUIDs will make 6 | multi-master distribution substantially easier. 7 | 8 | See src/schema.sql after building the project for an example. 9 | 10 | ## USAGE GUIDE 11 | create a new database using the git-sqlite example schema: 12 | ``` 13 | git-sqlite init newdatabase.db 14 | ``` 15 | 16 | attach the database to your repository (has to be done once for each repo): 17 | ``` 18 | git-sqlite attach newdatabase.db 19 | ``` 20 | 21 | show a diff using the git-sqlite diff driver: 22 | ``` 23 | git show-sql 24 | ``` 25 | 26 | resolve a merge conflict (after manually editing the merge_file) 27 | ``` 28 | git apply-sql 29 | ``` 30 | 31 | ## INSTALLING GIT-SQLITE 32 | Dependencies: 33 | * sqlite3 34 | * sqldiff 35 | * bash 36 | * git 37 | * autotools (build-essential debian repositories) 38 | 39 | As of Debian Stretch (release 9), sqldiff is included with the default sqlite3 apt package. 40 | 41 | If it is not available for your distribution, see `INSTALLING SQLDIFF` below. 42 | 43 | If you are installing from the git src: 44 | ``` 45 | ./reconf 46 | ./configure 47 | sudo make install 48 | ``` 49 | 50 | If you are installing from a release, do this: 51 | ``` 52 | ./configure 53 | sudo make install 54 | ``` 55 | 56 | ## INSTALLING SQLDIFF 57 | 58 | ``` 59 | wget https://www.sqlite.org/src/tarball/sqlite.tar.gz?r=release 60 | tar xzf sqlite.tar.gz?r=release 61 | cd sqlite 62 | ./configure 63 | make sqldiff 64 | sudo install sqldiff /usr/local/bin/ 65 | ``` 66 | 67 | See https://www.sqlite.org/download.html for more information 68 | 69 | ## KNOWN ISSUES 70 | * can't detect diffed triggers and views (should be resolved upstream in sqldiff) 71 | * new columns from alter table dont have explicit types 72 | * merge conflicts don't interleave 73 | 74 | ## TODOS 75 | * uuid version 1 style 76 | * cleanup diff headers to be closer to what git does 77 | * test cherry-picking 78 | 79 | ## NOTES 80 | * `git gc` may need to be run periodically 81 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([git-sqlite], [alpha], [cannadayr]@gmail.com) 2 | AM_INIT_AUTOMAKE([foreign]) 3 | 4 | # check for bash 5 | AC_CHECK_PROG(bash,[bash],[bash],[no]) 6 | test "$bash" == "no" && AC_MSG_ERROR([Required program 'bash' not found.]) 7 | 8 | # check for sqlite3 9 | AC_CHECK_PROG(sqlite3,[sqlite3],[sqlite3],[no]) 10 | test "$sqlite3" == "no" && AC_MSG_ERROR([Required program 'sqlite3' not found.]) 11 | 12 | # check for sqldiff 13 | AC_CHECK_PROG(sqldiff,[sqldiff],[sqldiff],[no]) 14 | test "$sqldiff" == "no" && AC_MSG_ERROR([Required program 'sqldiff' not found.]) 15 | 16 | # check for git 17 | AC_CHECK_PROG(git,[git],[git],[no]) 18 | test "$git" == "no" && AC_MSG_ERROR([Required program 'git' not found.]) 19 | 20 | # summary 21 | summary="a diff & merge driver for sqlite" 22 | AC_SUBST([summary]) 23 | 24 | # uuid_v4 25 | uuidv4=m4_normalize(" 26 | lower(hex(randomblob(4))) 27 | || '-' 28 | || lower(hex(randomblob(2))) 29 | || '-4' 30 | || substr(lower(hex(randomblob(2))),2) 31 | || '-' 32 | || substr('89ab',abs(random()) % 4 + 1, 1) 33 | || substr(lower(hex(randomblob(2))),2) 34 | || '-' 35 | || lower(hex(randomblob(6))) 36 | ") 37 | AC_SUBST([uuidv4]) 38 | 39 | # Auto-generated warnings. 40 | # Add '@autogenerated_warnging@' and '@autogenerated_timestamp@' to the 41 | # source scripts. 42 | autogenerated_warning="DO NOT EDIT. This is an auto-generated file." 43 | AC_SUBST([autogenerated_warning]) 44 | autogenerated_timestamp="Created on $(date)" 45 | AC_SUBST([autogenerated_timestamp]) 46 | 47 | # include src files 48 | AC_CONFIG_FILES([Makefile 49 | src/Makefile 50 | src/schema.sql:src/schema.sql.in 51 | src/git-sqlite:src/git-sqlite.in 52 | src/git-sqlite-diff:src/git-sqlite-diff.in 53 | src/git-sqlite-merge:src/git-sqlite-merge.in]) 54 | AC_OUTPUT 55 | -------------------------------------------------------------------------------- /contrib/db_config.php: -------------------------------------------------------------------------------- 1 | array( 12 | 'id', 13 | 'time_added', 14 | 'tag_id', 15 | 'entity_id', 16 | ), 17 | ); 18 | -------------------------------------------------------------------------------- /reconf: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | autoreconf -if 3 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | # scripts to install 2 | bin_SCRIPTS = \ 3 | git-sqlite \ 4 | git-sqlite-diff \ 5 | git-sqlite-merge 6 | 7 | # files to install in /usr/local/share/PACKAGE/ 8 | utildir = $(datadir)/git-sqlite 9 | 10 | utilities = \ 11 | util.sh \ 12 | schema.sql 13 | 14 | dist_util_DATA = $(utilities) 15 | EXTRA_DIST = $(utilities) 16 | 17 | # clean files 18 | CLEANFILES = $(bin_SCRIPTS) 19 | -------------------------------------------------------------------------------- /src/git-sqlite-diff.in: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ## @autogenerated_warning@ 3 | ## @autogenerated_timestamp@ 4 | 5 | prefix="@prefix@" 6 | pkgdatadir="@datarootdir@/@PACKAGE@" # e.g. /usr/local/share/PACKAGE/ 7 | 8 | . "$pkgdatadir/util.sh" 9 | 10 | # we get the /tmp/ param in a different spot depending on 11 | # what kind of diff logic/context git is performing 12 | # sometimes it's in $2, sometimes in $5 13 | # if we don't choose the /tmp/ file, we just end up diffing 14 | # the same file against itself and lose the proper diff. 15 | # even weirder, we sometimes have to swap the arguments (see below) 16 | getFirstTmpFileIdx() 17 | { 18 | local path1="$1" 19 | local path2="$2" 20 | local path1start=${path1:0:1} 21 | local path2start=${path2:0:1} 22 | 23 | # not actually looking in /tmp/ because MacOS stores its temp files elsewhere 24 | # just look for any absolute path 25 | if [ "$path1start" = '/' ] \ 26 | && [ "$path2start" = "/" ] 27 | then 28 | # we are probably doing a `git show-sql` 29 | echo 0 30 | elif [ "$path1start" = '/' ]; then 31 | echo 1 32 | elif [ "$path2start" = '/' ]; then 33 | echo 2 34 | else 35 | printErr "getFirstTmpFileVal ERROR: neither '$path1' nor '$path2' are /tmp/ values" 36 | fi 37 | } 38 | 39 | #printErr "$@" 40 | toDbCandidate1="$2" 41 | toDbCandidate2="$5" 42 | #printErr "toDbCandidate1 = $toDbCandidate1" 43 | #printErr "toDbCandidate2 = $toDbCandidate2" 44 | 45 | # we are always interested in the /tmp/ file which has the version we're comparing to 46 | # depending on which arg has the /tmp/ file, we need to change the order of 47 | # the sqldiff args for some reason barely unknown to us 48 | tempFileIdx="$(getFirstTmpFileIdx "$toDbCandidate1" "$toDbCandidate2")" 49 | #printErr "tempFileIdx $tempFileIdx" 50 | 51 | if [ $tempFileIdx = 0 ]; then 52 | fromDb="$2" 53 | toDb="$5" 54 | elif [ $tempFileIdx = 1 ]; then 55 | fromDb="$toDbCandidate1" 56 | toDb="$1" 57 | elif [ $tempFileIdx = 2 ]; then 58 | fromDb="$toDbCandidate2" 59 | toDb="$1" 60 | else 61 | printErr 'ERROR: tmpDb not set to either $2 or $5' 62 | fi 63 | 64 | sha="$2" 65 | perm="$3" 66 | 67 | #printErr "fromDb $fromDb" 68 | #printErr "$(sqlite3 "$fromDb" ".dump")" 69 | #printErr "toDb $toDb" 70 | #printErr "$(sqlite3 "$toDb" ".dump")" 71 | 72 | #todo #fixme - this echos a newline if there's no diff 73 | diff="$(diffDb "$fromDb" "$toDb")" 74 | if [ -n "$diff" ]; then 75 | 76 | # display a bold diff header 77 | printErr "$(tput bold)sqldiff $toDb $fromDb$(tput sgr0)" 78 | printErr "$(tput bold)index $sha $perm$(tput sgr0)" 79 | echo "$diff" 80 | fi 81 | 82 | #exit 1; 83 | -------------------------------------------------------------------------------- /src/git-sqlite-merge.in: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ## @autogenerated_warning@ 3 | ## @autogenerated_timestamp@ 4 | 5 | prefix="@prefix@" 6 | pkgdatadir="@datarootdir@/@PACKAGE@" # e.g. /usr/local/share/PACKAGE/ 7 | 8 | . "$pkgdatadir/util.sh" 9 | 10 | ancestor="$1" 11 | localDb="$2" 12 | remote="$3" 13 | marker="$4" 14 | placeholder="$5" 15 | 16 | #printErr "ancestor=$ancestor" 17 | #printErr "localDb=$localDb" 18 | #printErr "remote=$remote" 19 | #printErr "marker=$marker" 20 | #printErr "placeholder=$placeholder" 21 | 22 | # create temporary files to store diffs in 23 | localDiffFile=$(mktemp) 24 | remoteDiffFile=$(mktemp) 25 | 26 | # get the diffs from the common ancestor to our states 27 | diffDb "$ancestor" "$localDb" > "$localDiffFile" 28 | diffDb "$ancestor" "$remote" > "$remoteDiffFile" 29 | 30 | # backup the localDb before merging 31 | backupDb="${localDb}.bak" 32 | cp "$localDb" "$backupDb" 33 | 34 | # apply each diff to its counterpart 35 | sqlite3 "$localDb" -init "$remoteDiffFile" ".exit" 36 | sqlite3 "$remote" -init "$localDiffFile" ".exit" 37 | 38 | # delete temporary files 39 | rm "$localDiffFile" 40 | rm "$remoteDiffFile" 41 | 42 | # diff our db's again 43 | local2remote="$(diffDb "$localDb" "$remote" "--no-transaction")" 44 | remote2local="$(diffDb "$remote" "$localDb" "--no-transaction")" 45 | 46 | # get tmp files 47 | local2remoteTmp="$(mktemp)" 48 | remote2localTmp="$(mktemp)" 49 | 50 | # add the contents 51 | echo "$local2remote" > "$local2remoteTmp" 52 | echo "$remote2local" > "$remote2localTmp" 53 | 54 | # diff the tmp files 55 | gitDiff="$(git diff --no-index "$local2remoteTmp" "$remote2localTmp")" 56 | 57 | #printErr "gitDiff = $gitDiff" 58 | 59 | formatGitDiff() 60 | { 61 | # comment out header lines and diff ranges 62 | 63 | awk -v prefix="-- " '{ if( /^diff/ || /^index/ || /^@@/ || /^\+\+\+/ || /^---/ ) { print prefix $0 } else print $0 }' \ 64 | | awk -v localMark="/**/" -v eol="/**/" '{ if ( /^-[^-]/ ) { print localMark substr($0,2) eol } else print $0 }' \ 65 | | awk -v remoteMark="/**/ " -v eol="/**/" '{ if ( /^\+[^+]/ ) { print remoteMark substr($0,2) eol } else print $0 }' \ 66 | | grep -v "^~$" 67 | 68 | } 69 | 70 | # throw a conflict warning if theres a diff still 71 | if [ -n "$gitDiff" ]; then 72 | 73 | # format the diff for sql consumption 74 | fmtGitDiff="$(echo "$gitDiff" | formatGitDiff )" 75 | #printErr "fmtGitDiff = $fmtGitDiff" 76 | 77 | # echo it to an output file for manual editing 78 | conflictFile="${placeholder}-.merge_file.sql" 79 | echo "$fmtGitDiff" > "$conflictFile" 80 | 81 | # restore the backup 82 | mv "$backupDb" "$localDb" 83 | 84 | # exit the script 85 | exit 1 86 | 87 | fi 88 | 89 | # git seems to clean up the backup regardless, 90 | # but if its still here lets get rid of it 91 | if [ -e "$backupDb" ]; then 92 | rm "$backupDb" 93 | fi 94 | 95 | # apply the diff 96 | sqlite3 "$localDb" "$ancestor2remoteDiff" 97 | 98 | -------------------------------------------------------------------------------- /src/git-sqlite.in: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | ## @autogenerated_warning@ 3 | ## @autogenerated_timestamp@ 4 | 5 | prefix="@prefix@" 6 | pkgdatadir="@datarootdir@/@PACKAGE@" # e.g. /usr/local/share/PACKAGE/ 7 | 8 | . "$pkgdatadir/util.sh" 9 | 10 | die() 11 | { 12 | local base="$(basename "$0")" 13 | printErr "$base: error: $@" 14 | exit 1 15 | } 16 | 17 | show_version_and_exit() 18 | { 19 | echo "@PACKAGE_NAME@ - @VERSION@" 20 | echo "License: MIT" 21 | exit 0 22 | } 23 | 24 | show_help_and_exit() 25 | { 26 | local base="$(basename "$1")" 27 | echo "@PACKAGE_NAME@ - @summary@ 28 | 29 | Usage: $BASE [OPTIONS] DATABASE 30 | 31 | COMMAND - one of 'init' or 'attach' 32 | init - initialize the database 33 | attach - attach the config 34 | DATABASE - sqlite3 database 35 | SCHEMA - alternate schema. Only used during 'init'. Sourced from package_dir (typically /usr/local/share/git-sqlite) 36 | 37 | Options: 38 | -h = This help screen. 39 | -V = print version. 40 | 41 | Website: @PACKAGE_URL@ 42 | bug-reports/questions: @PACKAGE_BUGREPORT@ 43 | 44 | " 45 | 46 | exit 47 | } 48 | 49 | prjCheck() 50 | { 51 | local repo="$1" 52 | local db="$2" 53 | 54 | # test if theres a .git directory 55 | if [ ! -d "$repo/.git" ] 56 | then 57 | printErr "'$repo' isn't the parent directory of a git repository" 58 | exit 1 59 | fi 60 | 61 | # test that the db path is relative 62 | if isAbsPath "$db"; then 63 | printErr "please use a relative path to the database" 64 | exit 1 65 | fi 66 | } 67 | 68 | init() 69 | { 70 | local repo="$(pwd)" 71 | local db="$1" 72 | 73 | schema= 74 | if [ -n "$2" ]; then 75 | if [ ! -f "$pkgdatadir/$2" ]; then 76 | die "schema $2 doesn't exist" 77 | else 78 | schema="$2" 79 | fi 80 | else 81 | schema="schema.sql" 82 | fi 83 | 84 | prjCheck "$repo" "$db" 85 | 86 | # test that the db file doesn't exist 87 | if [ -f "$repo/$db" ]; then 88 | printErr "'$db' exists, refusing to create" 89 | exit 1 90 | fi 91 | 92 | sqlite3 "$db" < "$pkgdatadir/$schema" 93 | } 94 | 95 | attach() 96 | { 97 | local repo="$(pwd)" 98 | local db="$1" 99 | 100 | prjCheck "$repo" "$db" 101 | 102 | # test that the db file exists 103 | if [ ! -f "$repo/$db" ]; then 104 | printErr "'$db' doesn't exist" 105 | exit 1 106 | fi 107 | 108 | # test that we've got a sqlite3 database 109 | if ! stringContains "SQLite format 3" "$(head -c 15 < "$repo/$db")"; then 110 | echo "'$db' is not sqlite database" >&2 111 | exit 1 112 | fi 113 | 114 | # add diff section 115 | git config diff.sqlite.binary "true" 116 | git config diff.sqlite.command "git-sqlite-diff" 117 | 118 | # add merge section 119 | git config merge.sqlite.name "sqlite merge" 120 | git config merge.sqlite.driver "git-sqlite-merge %O %A %B %L %P" 121 | 122 | # add git show-sql alias 123 | git config alias.show-sql "show --ext-diff -m" 124 | 125 | # add git apply-sql alias 126 | git config alias.apply-sql "!sqlite3 ${db} < ${db}-.merge_file.sql && rm ${db}-.merge_file.sql && git add ${db}" 127 | 128 | # modify local .gitattributes 129 | attributes="$db diff=sqlite merge=sqlite" 130 | 131 | touch "$repo/.gitattributes" 132 | 133 | if ! stringContains "$attributes" "$(cat "$repo/.gitattributes")"; then 134 | echo "$attributes" >> "$repo/.gitattributes" 135 | fi 136 | } 137 | 138 | # Default values for parameters 139 | show_usage= 140 | show_version= 141 | verbose= 142 | 143 | # Parse parameters 144 | while getopts Vvh param 145 | do 146 | case $param in 147 | h) show_help=1;; 148 | V) show_version=1;; 149 | ?) die "unknown command line option";; 150 | esac 151 | done 152 | shift $(($OPTIND - 1)) 153 | 154 | # Validate parameters 155 | test -n "$show_help" && show_help_and_exit 156 | test -n "$show_version" && show_version_and_exit 157 | test -z "$1" && die "missing command. See -h for help" 158 | test -z "$2" && die "missing database. See -h for help" 159 | 160 | # Set inputs 161 | cmd="$1" 162 | db="$2" 163 | schema="$3" 164 | 165 | # run the command 166 | case $cmd in 167 | "init") init "$db" "$schema";; 168 | "attach") attach "$db";; 169 | *) die "unknown command. See -h for help" 170 | esac 171 | -------------------------------------------------------------------------------- /src/schema.sql.in: -------------------------------------------------------------------------------- 1 | -- @autogenerated_warning@ 2 | -- @autogenerated_timestamp@ 3 | 4 | -- we are using an ad-hoc pseudo uuidv4 5 | CREATE TABLE entity ( 6 | "id" char(36) default (@uuidv4@), 7 | name text, 8 | txt text, -- description 9 | time_added timestamp default current_timestamp, 10 | url text, 11 | is_archived integer, 12 | primary key(id) 13 | ); 14 | 15 | CREATE TABLE tag2entity ( 16 | "id" char(36) default (@uuidv4@), 17 | entity_id char(36), -- id 18 | tag_id char(36), -- id 19 | name text, 20 | txt text, -- description 21 | time_added timestamp default current_timestamp, 22 | url text, 23 | is_archived integer, 24 | primary key(id) 25 | ); 26 | CREATE INDEX tag2entity__entity_id ON tag2entity(entity_id); 27 | CREATE INDEX tag2entity__tag_id ON tag2entity(tag_id); 28 | 29 | CREATE TABLE tag ( 30 | "id" char(36) default (@uuidv4@), 31 | name text, 32 | txt text, -- description 33 | time_added timestamp default current_timestamp, 34 | url text, 35 | is_archived integer, 36 | primary key(id) 37 | ); 38 | 39 | CREATE VIEW entity_tags AS 40 | 41 | SELECT * FROM entity e, tag2entity t2e, tag t 42 | WHERE t2e.entity_id = e.id 43 | AND t2e.tag_id = t.id; 44 | 45 | /* 46 | 47 | some useful tag queries: 48 | 49 | get all the entities that do have (some) tag 50 | 51 | select * 52 | from entity e, 53 | tag2entity t2e 54 | where 55 | t2e.entity_id = e.id 56 | and ; 57 | 58 | 59 | get all the entities that DON'T have any tags: 60 | 61 | select * from entity e 62 | where not exists ( 63 | select * from tag2entity t2e 64 | where t2e.entity_id = e.id 65 | ) 66 | 67 | 68 | adding a tags to an entity: 69 | 70 | insert into tag2entity (tag_id, entity_id) 71 | values ( (select id from tag where name=''), 72 | (select id from entity where name='') ) 73 | 74 | 75 | improving our "UUIDs": 76 | 77 | select replace(julianday(),".",""); 78 | select substr('0000000000000000' || replace(julianday(),".",""), -16, 16); 79 | select substr(replace(julianday(),".","") || '0000000000000000', 1, 16); 80 | select lower(printf('%08X', strftime("%s") || substr(strftime("%f"), 4, 6))); 81 | 82 | */ 83 | -------------------------------------------------------------------------------- /src/util.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | printErr() 4 | { 5 | printf "%s\n" "$*" >&2; 6 | } 7 | 8 | stringContains() 9 | { 10 | [ -z "${2##*$1*}" ] && [ -z "$1" -o -n "$2" ] 11 | } 12 | 13 | isAbsPath() 14 | { 15 | local path="$1" 16 | local pathStart=${path:0:1} 17 | 18 | if [ "$pathStart" = '/' ]; then 19 | return 0 20 | else 21 | return 1 22 | fi 23 | } 24 | 25 | diffDb() 26 | { 27 | # NOTE: sqldiff currently can't perform diffs 28 | # on views or triggers 29 | # see: https://sqlite.org/sqldiff.html#limitations 30 | # HOWEVER there might be some paths forward: 31 | # we might be able to get around this using 32 | # the "--changeset " option 33 | # this seems to detect changes to the sqlite_master tbl 34 | # and can be applied using the 'session' extension 35 | # see: https://sqlite.org/sessionintro.html 36 | local localDb="$1" 37 | local tmpDb="$2" 38 | local noTransaction="$4" 39 | 40 | local transactionStr="" 41 | if [ -z "$noTransaction" ]; then 42 | transactionStr="--transaction" 43 | fi 44 | 45 | # RFM 2018-02-06 adding --primarykey to see if it gets rid of rowid from diff queries 46 | # I need rowid on my tables for the triggers, but I don't want them in the diff 47 | sqldiff --primarykey $transactionStr "$localDb" "$tmpDb" 48 | #sqldiff $transactionStr "$localDb" "$tmpDb" 49 | } 50 | 51 | --------------------------------------------------------------------------------