Git integration
Git calls any file over 512 MiB binary and prints no diff. rift git-diff gives git a real diff for those files.
rift git-diff ships in 0.3.0.
On a 640 MiB pair of generated SQL dumps, git prints this:
$ git diff --no-index a.sql b.sql diff --git a/a.sql b/b.sql index 86d4681..61a1efd 100644 Binary files a/a.sql and b/b.sql differ
With Rift as the external diff, the same command prints git's headers and a unified diff:
$ git -c diff.external='rift git-diff' diff --no-index a.sql b.sql > out.diff $ head -n 12 out.diff | cut -c1-100 diff --git a/a.sql b/b.sql index 86d4681..61a1efd 100644 --- a/a.sql +++ b/b.sql @@ -380,7 +380,6 @@ INSERT INTO public.orders (id, customer_id, status, amount, note) VALUES (380, 514366, 'shipped', 5 381 178722 cancelled 2930.54 wmojdqnzik INSERT INTO public.orders (id, customer_id, status, amount, note) VALUES (382, 679322, 'cancelled', -383 668107 shipped 5325.74 zu INSERT INTO public.orders (id, customer_id, status, amount, note) VALUES (384, 442363, 'new', 6149. 385 359182 cancelled 475.15 ztbyhdlmxk INSERT INTO public.orders (id, customer_id, status, amount, note) VALUES (386, 967299, 'shipped', 4
Set it up for large files only
Name the large files in .gitattributes and define the driver, so everything else keeps git's own diff:
echo '*.sql diff=rift' >> .gitattributes
echo '*.csv diff=rift' >> .gitattributes
git config diff.rift.command 'rift git-diff --mem 1G'
Git runs the command through the shell, so options go inside the quotes.
rift git-diff takes the seven arguments git passes: path old-file old-hex old-mode new-file new-hex new-mode, and for a rename or copy also the new path and git's rename lines. It prints git's headers (diff --git, mode lines, index, --- a/path, +++ b/path, and /dev/null for an added or deleted file) and the unified diff from Rift.
Exit status
The command exits 0 whether or not the files differ, because git treats any other status as a failure and stops with status 128. The status of git diff is git's own: 0, or 1 with --exit-code when there are differences. Rift exits 2 on an error.
What differs from git's output
- Hunk headers carry no function name.
- The hash of a work tree file is written as
0000000, because git does not pass one. - Hashes are always 7 characters.
LFS pointers
If a side is a Git LFS pointer, Rift reads the object from .git/lfs/objects of the common git directory and reads it in place. A missing object stops the run and names its oid: fetch it with git lfs fetch. If the object's size differs from the pointer's, Rift stops. Rift does not check the hash and ignores lfs.storage.
The cost without LFS
Git writes every blob that is not in the work tree to a temporary file before it runs the command. For a file that is not stored with LFS, that is a full copy: on a 10 GB file, 10 GB of disk and the time to write it. Comparing a work tree file with the index makes one copy. Comparing two commits makes two.
The terminal view
git difftool opens the terminal view. It passes the two files as $LOCAL and $REMOTE and does not resolve LFS pointers:
git config difftool.rift.cmd 'rift -i "$LOCAL" "$REMOTE"'
git config difftool.prompt false
git difftool -t rift