Graphviz visualizations of git repository structure
Project description
visigit
visigit turns any git repository into a live Graphviz diagram. Whether you're learning why git reset --hard wipes your work, exploring a tangled branch topology, or teaching someone how git actually stores files as a tree of objects — visigit shows you what's happening inside the repo.
Contents
- Requirements
- Installation
- Quick Start
- Display Modes
- Monitor Mode — Live View
- All Options
- Development
Requirements
- Python 3.9+
- Graphviz system package (
dotbinary on PATH)
Install Graphviz:
# Ubuntu / Debian / WSL2
sudo apt install graphviz
# macOS
brew install graphviz
Installation
git clone https://github.com/rcronk/visigit.git
cd visigit
pip install -e .
This installs the visigit command globally in your Python environment.
Quick Start
# Snapshot of the current directory's repo
visigit
# Pick a specific repo
visigit --repo-path /path/to/some/repo
# Open a specific mode
visigit --mode branch
visigit --mode verbose
# Watch for changes and re-render automatically
visigit --monitor
By default visigit writes visigit.svg and opens it in an auto-refreshing browser page. Use --no-open to skip opening the viewer, or --output-path to write to a different location.
WSL2 users: The default
--viewer htmlopens a browser page that polls the SVG file every second. This works withoutxdg-open. If you use Windows-side Chrome or Edge, the file path will be something like\\wsl$\Ubuntu\tmp\visigit.html.
Display Modes
Normal mode (the default)
Shows the commit DAG with refs (branches, tags, HEAD) attached to their commits. Long chains of "boring" commits — single parent, single child, no refs — are automatically collapsed into a LAST (N) FIRST summary node so the graph stays readable.
visigit --mode normal
What you see:
HEAD→ current branch → commit chain- Branch and tag labels next to the commits they point to
- Merge commits with edges to both parents
- Collapsed boring chains as summary nodes (e.g.
a1b2c3 (3) f4e5d6) - Special ref nodes:
FETCH_HEAD,ORIG_HEAD,MERGE_HEAD,CHERRY_PICK_HEAD,BISECT_HEAD,stash@{N}— each appears automatically when present in the repo --commit-detailsadds author, message, and date to each commit node
Branch mode
Shows only branch names and their topological relationships — who branched from whom. Each node is a branch tip; edges show ancestry or fork points. Use this to understand the shape of a multi-branch project at a glance.
visigit --mode branch
What you see:
- One node per branch (and tag, if any)
- Direct edge when one branch's tip is a strict ancestor of another's tip
- A
fork / <sha>commit node when two branches have diverged from a shared ancestor (the fork commit itself is shown so you know exactly where they split) HEAD→branchnamelabel on the currently checked-out branch[wt: path]annotation on any branch checked out in a linked worktree (git worktree add)
Verbose mode
Shows the full git object model: commits, trees (directories), blobs (files), and the index (staged/unstaged/untracked files). Use this to understand how git actually stores your project — every git add and git commit becomes visible as a new object in the graph.
visigit --mode verbose
What you see:
- Commit → tree (root directory) → subtrees (subdirectories) → blobs (files)
- Staged Changes box: files in the index not yet committed, each with their blob SHA
- Unstaged Changes box: modified tracked files not yet staged
- Untracked box: files git doesn't know about yet
gitlinknodes for git submodule entries (mode-160000 tree entries pointing into a submodule's history)- New nodes added since the last render are highlighted in gold (useful in monitor mode)
Mermaid output
To export a Mermaid flowchart instead of a Graphviz image, use --output-format mermaid. The output is a .md file you can paste directly into GitHub, GitLab, or Notion:
visigit --output-format mermaid --output-path diagram.md
All three display modes work with Mermaid output. The file is a fenced ```mermaid ``` block — open it in any Mermaid-aware renderer.
Monitor Mode — Live View
Add --monitor to any mode and visigit watches the repository for filesystem changes. Every time you run a git command in another terminal, the graph re-renders automatically. New nodes since the last render are highlighted in gold.
visigit --monitor --viewer html
Open a second terminal window alongside the browser. Run git commands there; watch the diagram update.
Walkthrough 1: Learning git commands
This walkthrough covers the git commands that confuse people most — branch, merge, reset, and rebase — and lets you watch exactly what happens to the commit graph with each one.
Terminal A — start visigit:
mkdir /tmp/git-lab && cd /tmp/git-lab
git init -b main
git config user.email "you@example.com"
git config user.name "Your Name"
visigit --monitor --viewer html --repo-path /tmp/git-lab
Terminal B — run commands and watch the graph:
cd /tmp/git-lab
# ── Commits ──────────────────────────────────────────────────────────────────
echo "base" > base.txt && git add -A && git commit -m "base commit"
# Graph: HEAD → main → first commit node
echo "second" > second.txt && git add -A && git commit -m "second commit"
# Graph: HEAD → main → second → base (parent chain grows)
# ── Branching ────────────────────────────────────────────────────────────────
git checkout -b feature
# Graph: 'feature' label appears on the same commit as main
echo "feat" > feat.txt && git add -A && git commit -m "add feature"
# Graph: feature moves ahead; main stays behind — you can see them diverge
git checkout main
echo "hotfix" > fix.txt && git add -A && git commit -m "hotfix"
# Graph: now main and feature have diverged from the same parent
# ── Merge: no-fast-forward ────────────────────────────────────────────────────
git merge feature --no-ff -m "Merge feature into main"
# Graph: a merge commit appears with TWO parent edges — one to each diverged tip
# ── Reset ────────────────────────────────────────────────────────────────────
git reset --soft HEAD~1
# --soft: branch pointer moves back one commit; the merge commit disappears.
# Working tree and index are unchanged.
git reset --mixed HEAD~1
# --mixed (the default): branch pointer moves back one more; staged changes clear.
# Working tree files are unchanged; you'd need to re-add them.
git reset --hard HEAD~1
# --hard: branch pointer moves back; index AND working tree are wiped to match.
# The commits are still in the object store but no longer reachable.
# ── Rebase ───────────────────────────────────────────────────────────────────
git checkout feature
git rebase main
# Graph: feature's commits are REPLAYED on top of main's current tip.
# Notice: the old feature commit nodes disappear and NEW nodes appear with
# different SHAs — rebase creates new commit objects, it doesn't move old ones.
Walkthrough 2: Exploring git internals
This walkthrough uses verbose mode to reveal git's object model — how every file you stage and commit becomes a blob, tree, and commit object with a content-addressable SHA.
Terminal A — start visigit in verbose mode:
mkdir /tmp/learn-git && cd /tmp/learn-git
git init -b main
git config user.email "you@example.com"
git config user.name "Your Name"
visigit --mode verbose --monitor --viewer html --repo-path /tmp/learn-git
Terminal B — run commands and watch the object graph:
cd /tmp/learn-git
# ── Staging ───────────────────────────────────────────────────────────────────
echo "# My Project" > README.md
git add README.md
# Graph: a 'Staged Changes' box appears containing README.md with its blob SHA.
# The blob object exists in git's object store — but no commit or tree yet.
# ── Committing ────────────────────────────────────────────────────────────────
git commit -m "Initial commit"
# Graph: a commit node appears, pointing to a root tree node, which points
# to the README.md blob. The 'Staged Changes' box disappears.
# This is what git commit does: wraps the index into a tree, wraps the tree
# into a commit, and moves the branch pointer to the new commit.
# ── Adding another file ───────────────────────────────────────────────────────
echo "print('hello')" > app.py
git add app.py
# Graph: 'Staged Changes' reappears with app.py and its new blob SHA.
# README.md is NOT in staged changes — only the new/changed file.
git commit -m "Add app.py"
# Graph: a second commit node appears pointing to a NEW tree node.
# The new tree points to TWO blobs: README.md and app.py.
# Notice: the README.md blob SHA is the SAME as before — git deduplicates
# unchanged file content automatically (content-addressable storage).
# ── Modifying a file ──────────────────────────────────────────────────────────
echo "print('world')" >> app.py
# Graph: 'Unstaged Changes' box appears showing app.py with its new SHA.
# The working tree has diverged from the index.
git add app.py
# Graph: 'Unstaged Changes' disappears; 'Staged Changes' appears with app.py.
# The staged blob SHA is different from the committed one — new content, new SHA.
git commit -m "Update app.py"
# Graph: third commit → new tree → new blob for app.py; README.md blob unchanged.
# You can see git reuses the same README.md blob object across all three commits.
# ── Subdirectories ────────────────────────────────────────────────────────────
mkdir src && echo "class Core: pass" > src/core.py
git add -A && git commit -m "Add src/core.py"
# Graph: the root tree now has a CHILD tree node for 'src/', which points to
# core.py's blob. Each directory level becomes its own tree object.
All Options
| Option | Default | Description |
|---|---|---|
--repo-path PATH |
. |
Path to the git repository |
--mode {normal,verbose,branch} |
normal |
Display mode (see above) |
--output-format FORMAT |
svg |
Graphviz format (svg, pdf, png, …) or mermaid (writes a Mermaid .md file) |
--output-path PATH |
visigit.svg (or visigit.md for mermaid) |
Where to write the output file |
--rank-direction {RL,LR,TB,BT} |
RL (normal/verbose), LR (branch) |
Graph layout direction |
--max-commit-depth N |
unlimited | Limit BFS traversal depth per ref |
--exclude-remotes |
off | Omit remote-tracking refs from the graph |
--commit-details |
off | Add author, message, and date to commit nodes |
--monitor |
off | Watch repo for changes and re-render automatically |
--viewer {html,auto,none} |
html |
html: auto-refreshing browser page; auto: xdg-open/open/start; none: write file only |
--no-open |
off | Write file but do not open any viewer |
--verbose-log |
off | Enable verbose logging |
Development
# Install with dev dependencies
pip install -e ".[dev]"
# Run tests
make test # or: pytest tests/ -v
# Lint and format
make lint # ruff check
make format # ruff format
Tests create temporary git repositories and verify DOT graph structure for all three modes and all major corner cases (merge commits, detached HEAD, boring-chain collapse, fork nodes, same-commit branches, verbose tree/blob edges, and more).
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 visigit-0.3.1.tar.gz.
File metadata
- Download URL: visigit-0.3.1.tar.gz
- Upload date:
- Size: 206.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
57864f3e6fac9c514f6d365cb567deeb726a300e161a15065477693c9bae96ce
|
|
| MD5 |
46e9d123d3db7126c2659b4148da5334
|
|
| BLAKE2b-256 |
5fa0b40680f616b3653b75eab9c4386182cb890307b1155719a66b4dacd85fb9
|
File details
Details for the file visigit-0.3.1-py3-none-any.whl.
File metadata
- Download URL: visigit-0.3.1-py3-none-any.whl
- Upload date:
- Size: 54.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3c1d9d32615f87930d2a9b9c7b69d3e77ed48e5b17a4740c8d8f0580cd0e5d59
|
|
| MD5 |
76db64ff969e1161a2e3fb40728dc31e
|
|
| BLAKE2b-256 |
af7eefd61ccf29aecd980f2534002128dad34327dc4293a202500ac16f9a402d
|