Skip to main content

diff-pdf-commits

CI PyPI Python License: MIT Run with uvx

Build a PDF from two Git revisions and compare the results.

diff-pdf-commits creates detached git worktree checkouts for two refs, runs your build command in each checkout, saves both generated PDFs, and optionally runs diff-pdf to create or open a visual diff.

It does not assume LaTeX, Typst, Make, Docker, or any project layout. A project supplies its own build command and PDF path, either on the command line or through diff_config.toml.

Install

Run without installing:

uvx diff-pdf-commits HEAD~1 HEAD --config diff_config.toml

Or install it:

pipx install diff-pdf-commits
python -m pip install diff-pdf-commits

Quick Start

For repeated use in a repository, add diff_config.toml:

[diff_pdf]
build = "make pdf"
pdf = "build/report.pdf"
view = true

Then compare two refs:

diff-pdf-commits HEAD~1 HEAD --config diff_config.toml

Generated artifacts are written to .pdf-diff/<left>__<right>/ by default.

Config File

--config is the canonical way to store project-specific behavior: build command, PDF path, copied local files, and environment variables.

[diff_pdf]
build = "docker compose --profile latex run --build --rm latex"
env_file = ".env"
pdf_from_target = true
view = true

[diff_pdf.env]
PYTHONIOENCODING = "utf-8"
PYTHONUTF8 = "1"
TARGET = { from_env = "TARGET" }
VAULT_PATH = { from_env = "VAULT_PATH" }
VAULT_OS_PATH = { from_env = "VAULT_OS_PATH", resolve = true }

[diff_pdf.copy]
paths = [
  ".env",
  "docker-compose.yaml",
  "docker/latex.dockerfile",
]

Supported [diff_pdf] keys:

  • build: shell command run in each temporary worktree.
  • pdf: PDF path relative to the worktree root. It can also be { from_env = "TARGET", replace_suffix = ".pdf" }.
  • pdf_from_target: derive the PDF path from TARGET by replacing .tex with .pdf.
  • env_file: .env-style file used while expanding config values.
  • out: output directory, default .pdf-diff.
  • diff_output: explicit visual diff PDF path.
  • view: open the diff-pdf GUI viewer.
  • no_diff: only build and export both PDFs.
  • keep_worktrees: keep temporary worktrees for debugging.
  • dirty: fail or allow.

Supported [diff_pdf.env] values:

STATIC_VALUE = "value"
FROM_ENV = { from_env = "SOURCE_NAME" }
WITH_DEFAULT = { from_env = "OPTIONAL_NAME", default = "fallback" }
ABSOLUTE_PATH = { from_env = "RELATIVE_OR_ABSOLUTE_PATH", resolve = true }

Command-line options override config values. Repeated --env options override matching [diff_pdf.env] keys. Repeated --copy options are appended to configured copy paths.

One-Shot Usage

You can also pass everything on the command line:

diff-pdf-commits HEAD~1 HEAD \
  --build "latexmk -pdf main.tex" \
  --pdf main.pdf

Only build both revisions and export the PDFs:

diff-pdf-commits v1.0.0 HEAD \
  --build "typst compile main.typ main.pdf" \
  --pdf main.pdf \
  --no-diff

Save a visual diff PDF to a specific path:

diff-pdf-commits HEAD~1 HEAD \
  --build "task pdf" \
  --pdf dist/report.pdf \
  --diff-output review/report-diff.pdf

Pass local build inputs into both temporary worktrees:

diff-pdf-commits HEAD~1 HEAD \
  --build "task pdf" \
  --pdf report.pdf \
  --env SOURCE_DATE_EPOCH=0 \
  --copy .env \
  --copy config/local.json

Output Layout

By default, each run writes to .pdf-diff/<left>__<right>/:

.pdf-diff/
  HEAD_1__HEAD/
    logs/
      build-left.log
      build-right.log
    pdfs/
      left-HEAD_1-report.pdf
      right-HEAD-report.pdf
    worktrees/
      left/
      right/

Temporary worktrees are removed after the run unless --keep-worktrees is set. Logs and copied PDFs are kept.

Requirements

Required:

  • Python 3.10+
  • Git
  • The tools needed by your build command

Optional:

  • diff-pdf on PATH for visual comparison
  • uv if you want to run with uvx

diff-pdf is not needed when --no-diff is set.

Command Reference

Usage: diff-pdf-commits [OPTIONS] LEFT_REF RIGHT_REF

Options:
  --build TEXT          Shell command that builds the PDF in each worktree.
  --pdf PATH            PDF path relative to repo root.
  --repo PATH           Path inside the git repository.
  --out PATH            Output directory.
  --diff-output PATH    Write visual diff PDF to this path.
  --config PATH         Load options from TOML.
  --view / --no-view    Open diff-pdf GUI viewer.
  --no-diff             Only build and export both PDFs; do not run diff-pdf.
  --keep-worktrees      Keep temporary git worktrees for debugging.
  --dirty [fail|allow]
  --env KEY=VALUE       Environment variable passed to the build command.
  --copy PATH           Copy a local file or directory into each worktree.
  -h, --help            Show help.

diff-pdf-commits is the canonical command. pdf-commit-diff is kept as a compatibility alias.

Security

--build is executed with shell=True in each temporary worktree. This is intentional so projects can use commands such as make pdf, task pdf, latexmk, typst, or docker compose.

Do not pass untrusted build strings.

Development

uv sync --extra dev
uv run black --check --diff src tests
uv run pytest
uv build

Docker-based integration tests are opt-in:

DIFF_PDF_COMMITS_RUN_DOCKER_TESTS=1 uv run pytest

Run the local checkout through uvx:

uvx --refresh --from . diff-pdf-commits HEAD~1 HEAD --config diff_config.toml

Metadata

Release files for diff-pdf-commits 0.1.3

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for diff-pdf-commits 0.1.3
File Size Uploaded
diff_pdf_commits-0.1.3.tar.gz 43.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for diff-pdf-commits 0.1.3
File Interpreter ABI Platform
diff_pdf_commits-0.1.3-py3-none-any.whl Python 3 none any Details

Total release size: 57.3 kB

Release files / diff_pdf_commits-0.1.3.tar.gz

Download URL diff_pdf_commits-0.1.3.tar.gz
Size 43.2 kB
Tags Source
SHA-256 checksum
How to use checksums
f832daa07b2d636060166c1a189e630d7e2f71dab1355d07dbeff532138cadd5
BLAKE2b-256 checksum
How to use checksums
6d9747392dc46e4ce22cf3e63c05fe31af59b9264a295984205c20d6d5b8c8ea
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 29, 2026.

Transparency log

Release files / diff_pdf_commits-0.1.3-py3-none-any.whl

Download URL diff_pdf_commits-0.1.3-py3-none-any.whl
Size 14.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dd6388b853424a3a598202667f27ebd036665799dad504d00a55af34e42ca7f4
BLAKE2b-256 checksum
How to use checksums
7f9ee7080cad5b0bb6f7861f0fee2edeb676471fa3930598d52fbfa2b595f04e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on May 29, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.3 This release

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page