Compare PDFs built from two git commits by running a user-provided build command.
Project description
diff-pdf-commits
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 fromTARGETby replacing.texwith.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 thediff-pdfGUI viewer.no_diff: only build and export both PDFs.keep_worktrees: keep temporary worktrees for debugging.dirty:failorallow.
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-pdfonPATHfor visual comparisonuvif you want to run withuvx
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
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file diff_pdf_commits-0.1.3.tar.gz.
File metadata
- Download URL: diff_pdf_commits-0.1.3.tar.gz
- Upload date:
- Size: 43.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f832daa07b2d636060166c1a189e630d7e2f71dab1355d07dbeff532138cadd5
|
|
| MD5 |
df11298e1aadb7b998479142164a98e8
|
|
| BLAKE2b-256 |
6d9747392dc46e4ce22cf3e63c05fe31af59b9264a295984205c20d6d5b8c8ea
|
Provenance
The following attestation bundles were made for diff_pdf_commits-0.1.3.tar.gz:
Publisher:
publish.yml on ethercod3/diff-pdf-commits
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
diff_pdf_commits-0.1.3.tar.gz -
Subject digest:
f832daa07b2d636060166c1a189e630d7e2f71dab1355d07dbeff532138cadd5 - Sigstore transparency entry: 1668999516
- Sigstore integration time:
-
Permalink:
ethercod3/diff-pdf-commits@f99c13c575630001bc6b73f2059b6da865b519a8 -
Branch / Tag:
refs/tags/v0.1.3 - Owner: https://github.com/ethercod3
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f99c13c575630001bc6b73f2059b6da865b519a8 -
Trigger Event:
release
-
Statement type:
File details
Details for the file diff_pdf_commits-0.1.3-py3-none-any.whl.
File metadata
- Download URL: diff_pdf_commits-0.1.3-py3-none-any.whl
- Upload date:
- Size: 14.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dd6388b853424a3a598202667f27ebd036665799dad504d00a55af34e42ca7f4
|
|
| MD5 |
b4342e51cfd87d65c34d508a2535a1df
|
|
| BLAKE2b-256 |
7f9ee7080cad5b0bb6f7861f0fee2edeb676471fa3930598d52fbfa2b595f04e
|
Provenance
The following attestation bundles were made for diff_pdf_commits-0.1.3-py3-none-any.whl:
Publisher:
publish.yml on ethercod3/diff-pdf-commits
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
diff_pdf_commits-0.1.3-py3-none-any.whl -
Subject digest:
dd6388b853424a3a598202667f27ebd036665799dad504d00a55af34e42ca7f4 - Sigstore transparency entry: 1668999889
- Sigstore integration time:
-
Permalink:
ethercod3/diff-pdf-commits@f99c13c575630001bc6b73f2059b6da865b519a8 -
Branch / Tag:
refs/tags/v0.1.3 - Owner: https://github.com/ethercod3
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@f99c13c575630001bc6b73f2059b6da865b519a8 -
Trigger Event:
release
-
Statement type: