CLI that renders git tree visualizations as SVG from JSONL input.
Project description
gitsvg
CLI that renders git tree visualizations as SVG from JSONL input.
Installation
pip install gitsvg
Or with uv:
uv tool install gitsvg
Quick start
A .gitsvg.jsonl file is a list of operations, one JSON object per line, applied top-to-bottom to build a diagram. Render it with:
gitsvg render diagram.gitsvg.jsonl -o diagram.svg
Validate without rendering:
gitsvg validate diagram.gitsvg.jsonl
Examples
The examples/ folder ships eight self-contained input files demonstrating the format. Each subsection below shows the rendered output and the source it came from.
Example 1: Linear history
A single branch with a few commits. The minimum viable diagram.
{"op": "branch", "name": "main", "label_side": "left"}
{"op": "commit", "branch": "main", "id": "c1", "msg": "initial commit", "hash": "auto"}
{"op": "commit", "branch": "main", "id": "c2", "msg": "add README", "hash": "auto"}
{"op": "commit", "branch": "main", "id": "c3", "msg": "add tests", "hash": "auto"}
{"op": "commit", "branch": "main", "id": "c4", "msg": "fix typo", "hash": "auto"}
Example 2: Branch and merge
A feature branch forks off main, accumulates a couple of commits, then merges back.
{"op": "branch", "name": "main", "label_side": "left"}
{"op": "commit", "branch": "main", "id": "c1", "msg": "initial commit", "hash": "auto"}
{"op": "commit", "branch": "main", "id": "c2", "msg": "setup config", "hash": "auto"}
{"op": "branch", "name": "feature", "from_branch": "main"}
{"op": "commit", "branch": "feature", "id": "f1", "msg": "add login form", "hash": "auto"}
{"op": "commit", "branch": "feature", "id": "f2", "msg": "wire up auth", "hash": "auto"}
{"op": "merge", "from": "feature", "into": "main", "as": "m1", "msg": "merge feature", "hash": "auto"}
Example 3: Multiple branches with lane reuse
Two concurrent branches share lanes 1 and 2; after both merge, a later feature-b reclaims the now-free lane 1 instead of starting a new one. Lane assignment is automatic and geometry-driven.
{"op": "branch", "name": "main", "label_side": "left"}
{"op": "commit", "branch": "main", "id": "c1", "msg": "initial commit", "hash": "auto"}
{"op": "branch", "name": "feature-a", "from_branch": "main"}
{"op": "commit", "branch": "feature-a", "id": "a1", "msg": "start feature A", "hash": "auto"}
{"op": "branch", "name": "bugfix", "from_branch": "main"}
{"op": "commit", "branch": "bugfix", "id": "x1", "msg": "fix #42", "hash": "auto"}
{"op": "merge", "from": "feature-a", "into": "main", "as": "m1", "msg": "merge feature A", "hash": "auto"}
{"op": "merge", "from": "bugfix", "into": "main", "as": "m2", "msg": "merge bugfix", "hash": "auto"}
{"op": "commit", "branch": "main", "id": "c2", "msg": "release prep", "hash": "auto"}
{"op": "branch", "name": "feature-b", "from_branch": "main"}
{"op": "commit", "branch": "feature-b", "id": "b1", "msg": "feature B", "hash": "auto"}
{"op": "merge", "from": "feature-b", "into": "main", "as": "m3", "msg": "merge feature B", "hash": "auto"}
Example 4: Highlighting a commit
The highlight op marks an existing commit with an enlarged dot and a bold label — useful for drawing attention to a release or a key milestone.
{"op": "branch", "name": "main", "label_side": "left"}
{"op": "commit", "branch": "main", "id": "c1", "msg": "initial commit", "hash": "auto"}
{"op": "commit", "branch": "main", "id": "c2", "msg": "feature work", "hash": "auto"}
{"op": "commit", "branch": "main", "id": "c3", "msg": "more feature work", "hash": "auto"}
{"op": "commit", "branch": "main", "id": "v1", "msg": "release v1.0", "hash": "auto"}
{"op": "commit", "branch": "main", "id": "c4", "msg": "post-release fix", "hash": "auto"}
{"op": "highlight", "commit": "v1"}
Example 5: Remove and rebuild (rebase pattern)
A feature branch is removed and re-declared on top of a more recent main commit, with the same commit IDs as before. This is the rebase-style "move my work onto the new tip" pattern, expressed as primitives.
{"op": "branch", "name": "main", "label_side": "left"}
{"op": "commit", "branch": "main", "id": "c1", "msg": "initial commit", "hash": "auto"}
{"op": "branch", "name": "feature", "from_branch": "main"}
{"op": "commit", "branch": "feature", "id": "f1", "msg": "WIP feature", "hash": "auto"}
{"op": "commit", "branch": "feature", "id": "f2", "msg": "more WIP", "hash": "auto"}
{"op": "commit", "branch": "main", "id": "c2", "msg": "main moves on", "hash": "auto"}
{"op": "commit", "branch": "main", "id": "c3", "msg": "more main work", "hash": "auto"}
{"op": "remove", "branches": ["feature"]}
{"op": "branch", "name": "feature", "from_branch": "main"}
{"op": "commit", "branch": "feature", "id": "f1", "msg": "WIP feature", "hash": "auto"}
{"op": "commit", "branch": "feature", "id": "f2", "msg": "more WIP", "hash": "auto"}
Example 6: Import and squash
The import op replays another file as a prelude — here it picks up the rebased state from Example 5. A single new commit then squashes f1 and f2 into one via replaces:.
{"op": "import", "path": "05_remove_rebuild.gitsvg.jsonl"}
{"op": "commit", "branch": "feature", "replaces": ["f1", "f2"], "id": "f_squash", "msg": "complete feature", "hash": "auto"}
Example 7: Open pull request
The pull_request op declares a pending merge between two branches. Both endpoints live-track the current branch tips: as commits accumulate on either side, the dashed arc advances. The optional title renders as a pill anchored at the source-tip commit. The typical lifecycle closes the PR with remove and then runs a real merge; this example stops before either, so the open PR remains visible in the final state.
{"op": "branch", "name": "main", "label_side": "left"}
{"op": "commit", "branch": "main", "id": "m1", "msg": "release"}
{"op": "branch", "name": "feature", "from_branch": "main"}
{"op": "commit", "branch": "feature", "id": "f1", "msg": "wip"}
{"op": "pull_request", "id": "pr1", "from": "feature", "into": "main", "title": "PR 1: add thing"}
{"op": "commit", "branch": "feature", "id": "f2", "msg": "polish"}
{"op": "commit", "branch": "main", "id": "m2", "msg": "hotfix"}
Example 8: Themed rendering
The theme op patches the diagram's live theme — spacings, sizes, fonts, the branch-colour palette, the SVG background, and more. Each op only overrides the fields it lists; a name selects a built-in theme (today: default) that replaces every field first. Here we import Example 3 unchanged and apply a saturated palette with thicker strokes, larger labels, and a warm background.
{"op": "import", "path": "03_multi_branch.gitsvg.jsonl"}
{"op": "theme", "background_color": "#fff8e7", "branch_line_width": 4, "label_font_size": 14, "branch_label_font_size": 14, "hash_font_size": 11, "commit_radius": 7, "highlight_radius": 9, "colors": {"main": "#d62728", "branch1": "#1f77b4", "branch2": "#2ca02c", "branch3": "#ff7f0e", "branch4": "#9467bd"}}
CLI reference
| Command | Purpose |
|---|---|
gitsvg render <input> -o <output> |
Render a .gitsvg.jsonl file to SVG. Add --small for a more compact SVG (some loss of numeric precision). |
gitsvg validate <input> |
Run the full validation pipeline; report errors with file:line: [code] field: message. Add --json for a structured report. |
gitsvg schema |
Index of all input operations. gitsvg schema <op> prints the JSON Schema for a specific operation; --list-ops prints a bare op list. |
gitsvg errors |
Index of all validation error codes. gitsvg errors <code> prints the long-form catalog entry; --list-codes prints a bare code list. |
gitsvg schema and gitsvg errors are designed for agents and tooling: an LLM-based agent producing input can fetch the schema for a single op and the catalog entry for any error it hits, without reading the rest of the documentation.
License
MIT.
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 gitsvg-0.1.4.tar.gz.
File metadata
- Download URL: gitsvg-0.1.4.tar.gz
- Upload date:
- Size: 64.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
495a6894880945846cfdcb591c7c4468400fe7b89fc51da46b7d28827c33c05b
|
|
| MD5 |
8bd5750988de1400672b756782400e87
|
|
| BLAKE2b-256 |
3f7a6421be5d8666b93a8ba65eac1650f796002d6a208d5edc3205e0f1dafc23
|
Provenance
The following attestation bundles were made for gitsvg-0.1.4.tar.gz:
Publisher:
release_tag.yml on bertpl/gitsvg
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gitsvg-0.1.4.tar.gz -
Subject digest:
495a6894880945846cfdcb591c7c4468400fe7b89fc51da46b7d28827c33c05b - Sigstore transparency entry: 1517594332
- Sigstore integration time:
-
Permalink:
bertpl/gitsvg@c14bf7ebbcfa579c1f92c48e35f7d26005147ffd -
Branch / Tag:
refs/tags/v0.1.4 - Owner: https://github.com/bertpl
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release_tag.yml@c14bf7ebbcfa579c1f92c48e35f7d26005147ffd -
Trigger Event:
push
-
Statement type:
File details
Details for the file gitsvg-0.1.4-py3-none-any.whl.
File metadata
- Download URL: gitsvg-0.1.4-py3-none-any.whl
- Upload date:
- Size: 107.5 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 |
652e8990bc318fbd89219b5c30b3b5c9e5fc0bd9ad1518195900635b2f4b5fdc
|
|
| MD5 |
3cb83f657b85af6f6b0d7a92cd39472d
|
|
| BLAKE2b-256 |
1b4fb2e874f9ff96e577c84376feddf7f1c78b5d8aedc1b49aaa3ef81bf14385
|
Provenance
The following attestation bundles were made for gitsvg-0.1.4-py3-none-any.whl:
Publisher:
release_tag.yml on bertpl/gitsvg
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
gitsvg-0.1.4-py3-none-any.whl -
Subject digest:
652e8990bc318fbd89219b5c30b3b5c9e5fc0bd9ad1518195900635b2f4b5fdc - Sigstore transparency entry: 1517594553
- Sigstore integration time:
-
Permalink:
bertpl/gitsvg@c14bf7ebbcfa579c1f92c48e35f7d26005147ffd -
Branch / Tag:
refs/tags/v0.1.4 - Owner: https://github.com/bertpl
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release_tag.yml@c14bf7ebbcfa579c1f92c48e35f7d26005147ffd -
Trigger Event:
push
-
Statement type: