Skip to main content

Pipe and diff files: execute shell pipelines against multiple inputs, diff/compare/join results.

Project description

dffs

Pipe and diff files: execute shell pipelines, diff/compare/join results.

dffs on PyPI

Apply a transform to both sides of a comparison, then diff the results — like Haskell's on:

a ─→ [f] ─→ f(a) ─┐
                    ├─→ [cmp] ─→ result
b ─→ [f] ─→ f(b) ─┘

Three CLIs apply this pattern with different comparators:

CLI cmp Description
git-diff-x diff Diff a Git-tracked file at two commits, through a pipeline
diff-x diff Diff two files through a pipeline
comm-x comm Set operations on two files through a pipeline

Install

pip install dffs

CLIs

git-diff-x

Diff a Git-tracked file at two commits (or one commit vs. the worktree), after piping both versions through a command pipeline.

Examples

JSON: readable diffs of compact files

A config file is stored as compact JSON (one line, no whitespace). In commit 38856a0, a few fields were updated, but git diff is unreadable:

-{"name":"myapp","version":"1.2.3","settings":{"debug":false,"logLevel":"info","maxRetries":3,...}}
+{"name":"myapp","version":"1.3.0","settings":{"debug":false,"logLevel":"warn","maxRetries":3,...}}

git diff-x with jq pretty-prints both sides before diffing, so you see exactly what changed:

git diff-x -R 38856a0 'jq .' example/config.json
# 3c3
# <   "version": "1.2.3",
# ---
# >   "version": "1.3.0",
# 6c6
# <     "logLevel": "info",
# ---
# >     "logLevel": "warn",
# 11c11
# <       "analytics": false
# ---
# >       "analytics": true

This also normalizes out any whitespace or key-ordering differences — only actual value changes appear.

CSV: ignoring row order

A CSV's rows were reordered in commit 7f0c468:

git diff --stat 7f0c468^..7f0c468 -- example/data.csv
# example/data.csv | 4 ++--
# 1 file changed, 2 insertions(+), 2 deletions(-)

git diff shows a noisy patch, but sorting first reveals the data is unchanged:

git diff-x -R 7f0c468 sort example/data.csv
# (no output — the sorted contents are identical)
CSV: comparing column names

In commit 0bdec95, the city column was replaced with role. Extract and compare just the header:

git diff-x -R 0bdec95 "head -1 | tr , '\n'" example/data.csv
# 3c3
# < city
# ---
# > role
Comparing line counts

Compare line-count (wc -l) of this README, before and after commit 8b7a761:

git-diff-x -R 8b7a761 'wc -l' README.md
# 1c1
# < 16
# ---
# > 206
More examples
# Compare the number of lines (`wc -l`) in file `foo` at the previous vs. current commit
# (`-R HEAD` is equivalent to `-r HEAD^..HEAD`).
git diff-x -R HEAD wc -l foo

# Colorized (`-c`) diff of `md5sum`s of `foo`, at HEAD (last committed value) vs. the current
# worktree content.
git diff-x -c md5sum foo

# Use `-` to separate pipeline commands from paths (when more than one path is to be diffed),
# e.g. this compares the largest 10 numbers in `file{1,2}` (HEAD vs. worktree):
git diff-x 'sort -rn' head - file1 file2

Usage

git-diff-x
# Usage: git-diff-x [OPTIONS] [exec_cmd...] [<path> | - [paths...]]
#
#   Diff files at two commits, or one commit and the current worktree, after
#   applying an optional command pipeline.
#
#   Examples:
#
#   # Compare the number of lines (`wc -l`) in file `foo` at the previous vs.
#   current commit (`-r HEAD^..HEAD`):
#
#   git diff-x -r HEAD^..HEAD wc -l foo
#
#   # Colorized (`-c`) diff of `md5sum`s of `foo`, at HEAD (last committed
#   value) vs. the current worktree content:
#
#   git diff-x -c md5sum foo
#
#   # Use `-` to separate pipeline commands from paths (when more than one path
#   is to be diffed), e.g. this compares the largest 10 numbers in `file{1,2}`
#   (HEAD vs. worktree):
#
#   git diff-x 'sort -rn' head - file1 file2
#
# Options:
#   -c, --color / --no-color     Colorize the output (default: auto, based on
#                                TTY)
#   -r, --refspec TEXT           <commit 1>..<commit 2> (compare two commits) or
#                                <commit> (compare <commit> to the worktree)
#   -R, --ref TEXT               Diff a specific commit; alias for `-r
#                                <ref>^..<ref>`
#   -t, --staged                 Compare HEAD vs. staged changes (index)
#   -P, --pipefail               Check all pipeline commands for errors (like
#                                bash's `set -o pipefail`); default only checks
#                                last command
#   -s, --shell-executable TEXT  Shell to use for executing commands; defaults
#                                to $SHELL
#   -S, --no-shell               Don't pass `shell=True` to Python
#                                `subprocess`es
#   -U, --unified INTEGER        Number of lines of context to show (passes
#                                through to `diff`)
#   -V, --version                Show version and exit
#   -v, --verbose                Log intermediate commands to stderr
#   -w, --ignore-whitespace      Ignore whitespace differences (pass `-w` to
#                                `diff`)
#   -x, --exec-cmd TEXT          Command(s) to execute before invoking `comm`;
#                                alternate syntax to passing commands as
#                                positional arguments
#   --help                       Show this message and exit.

diff-x

The underlying building block — same concept, but for two arbitrary files (not Git commits).

Examples

Given two similar JSON objects, where one is compact and the other is pretty-printed:

echo '{"a":1,"b":2}' > 1.json
echo '{"a":1,"b":3}' | jq > 2.json

diff {1,2}.json outputs the entirety of both objects:

1c1,4
< {"a":1,"b":2}
---
> {
>   "a": 1,
>   "b": 3
> }

diff-x 'jq .' {1,2}.json pretty-prints each side before diffing:

3c3
<   "b": 2
---
>   "b": 3

Usage

diff-x
# Usage: diff-x [OPTIONS] [exec_cmd...] <path1> <path2>
#
#   Diff two files after running them through a pipeline of other commands.
#
# Options:
#   -c, --color / --no-color     Colorize the output (default: auto, based on
#                                TTY)
#   -P, --pipefail               Check all pipeline commands for errors (like
#                                bash's `set -o pipefail`); default only checks
#                                last command
#   -s, --shell-executable TEXT  Shell to use for executing commands; defaults
#                                to $SHELL
#   -S, --no-shell               Don't pass `shell=True` to Python
#                                `subprocess`es
#   -U, --unified INTEGER        Number of lines of context to show (passes
#                                through to `diff`)
#   -V, --version                Show version and exit
#   -v, --verbose                Log intermediate commands to stderr
#   -w, --ignore-whitespace      Ignore whitespace differences (pass `-w` to
#                                `diff`)
#   -x, --exec-cmd TEXT          Command(s) to execute before invoking `comm`;
#                                alternate syntax to passing commands as
#                                positional arguments
#   --help                       Show this message and exit.

comm-x

comm performs set intersection/difference; comm-x lets you run a pipeline on each input first.

Examples

Given two similar lists of numbers, but in different orders:

seq 10 > 1.txt
seq 10 -2 0 > 2.txt

comm outputs gibberish, because the files aren't in sorted order:

comm 1.txt 2.txt
# 1
# 	10
# 2
# 3
# 4
# 5
# 6
# 7
# 		8
# comm: file 2 is not in sorted order
# 	6
# 	4
# 	2
# 	0
# 9
# comm: file 1 is not in sorted order
# 10
# comm: input is not in sorted order

comm-x sort sorts each file first:

comm-x sort 1.txt 2.txt
# 	0
# 1
# 		10
# 		2
# 3
# 		4
# 5
# 		6
# 7
# 		8
# 9

Shell Integration

Add convenient aliases to your shell by adding this to your ~/.bashrc or ~/.zshrc:

eval "$(dffs-shell-integration bash)"

This provides aliases with the following suffix conventions:

  • c = color, n = no-color, w = ignore-whitespace
  • r = ref (-R, compare commit to parent), s = refspec (-r), t = staged (--staged)

Examples

Alias Expands to
dx diff-x
dxc diff-x --color
cx comm-x
gdx git diff-x
gdxc git diff-x --color
gdxr git diff-x -R (compare commit to parent)
gdxs git diff-x -r (explicit refspec)
gdxt git diff-x --staged
gdxcr git diff-x --color -R
gdxtw git diff-x --staged -w

To see all available aliases:

dffs-shell-integration bash

To load only aliases for a specific command:

eval "$(dffs-shell-integration bash git-diff-x)"

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

dffs-0.1.6.tar.gz (36.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

dffs-0.1.6-py3-none-any.whl (15.8 kB view details)

Uploaded Python 3

File details

Details for the file dffs-0.1.6.tar.gz.

File metadata

  • Download URL: dffs-0.1.6.tar.gz
  • Upload date:
  • Size: 36.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dffs-0.1.6.tar.gz
Algorithm Hash digest
SHA256 2f7e3a95caeec68661a607f15f6f4dde085ab3e5c67c7bcff598392287da9018
MD5 d56ba94ebdb3ae7c618a36dfc23a0829
BLAKE2b-256 2addfc16635b1d9a2ea277ccf0d7eea14225f0ddc9a7ced6ceb4949c1c962bd0

See more details on using hashes here.

Provenance

The following attestation bundles were made for dffs-0.1.6.tar.gz:

Publisher: ci.yml on runsascoded/dffs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file dffs-0.1.6-py3-none-any.whl.

File metadata

  • Download URL: dffs-0.1.6-py3-none-any.whl
  • Upload date:
  • Size: 15.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for dffs-0.1.6-py3-none-any.whl
Algorithm Hash digest
SHA256 2b5c22c507a21d0774af2afcaf850e00be086e03a702ebfb0d1342d43a4988ed
MD5 fb1c3642c57afaaba4dfc403db99248c
BLAKE2b-256 68e3b2d67e28171cf3f650ffe68a6003dcaa24243f67f158db5c032d3818edba

See more details on using hashes here.

Provenance

The following attestation bundles were made for dffs-0.1.6-py3-none-any.whl:

Publisher: ci.yml on runsascoded/dffs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page