Skip to content

Commit e080443

Browse files
authored
Merge pull request #13 from TheTrueSCU/release/prepare-v0.2.0
release: v0.2.0
2 parents d96ae40 + 0726b31 commit e080443

6 files changed

Lines changed: 169 additions & 10 deletions

File tree

Justfile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,5 @@ generate-examples:
110110
uv run git-graphable examples/repos/repo-pristine --engine mermaid -o examples/assets/pristine.mmd --highlight-critical --critical-branch main --highlight-authors --bare
111111
uv run git-graphable examples/repos/repo-messy --engine mermaid -o examples/assets/messy.mmd --highlight-wip --highlight-direct-pushes --highlight-stale --bare
112112
uv run git-graphable examples/repos/repo-features --engine mermaid -o examples/assets/features.mmd --highlight-orphans --highlight-diverging-from main --bare
113+
uv run git-graphable examples/repos/repo-risk-silo --engine mermaid -o examples/assets/silo.mmd --highlight-silos --silo-threshold 20 --bare
114+
uv run git-graphable examples/repos/repo-complex-hygiene --engine mermaid -o examples/assets/complex.mmd --highlight-back-merges --bare

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ git graphable .
1414
- **Automatic Visualization**: Generates and opens an image (SVG/PNG) automatically if no output is specified.
1515
- **Advanced Highlighting**: Visualize author patterns, topological distance, and specific merge paths.
1616
- **GitHub Integration**: Highlight commits based on pull request status (Merged, Open, Closed, Draft) using the `gh` CLI.
17-
- **Hygiene Analysis**: Automatically detect WIP commits, direct pushes to protected branches, and squashed PRs.
17+
- **Hygiene Analysis**: Automatically detect WIP commits, direct pushes to protected branches, squashed PRs, back-merges, and contributor silos.
1818
- **Health Scoring**: Get a numeric "Hygiene Score" (0-100%) with a color-coded grade and detailed breakdown of workflow anti-patterns.
1919
- **CI Gating**: Use the `--check` flag to return a non-zero exit code if the hygiene score falls below a threshold (configurable via `--min-score`).
2020
- **Flexible Input**: Works with local repository paths or remote Git URLs.

examples/EXAMPLES.md

Lines changed: 105 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
This page demonstrates the visual output and hygiene analysis of `git-graphable` using generated example repositories.
44

55
## 1. Pristine Repository (Score: 100%)
6-
Demonstrates a clean, PR-based workflow with author highlighting and critical branch marking.
6+
Demonstrates a clean, PR-based workflow with multi-author highlighting and critical branch marking.
77

88
**Command:**
99
```bash
@@ -45,8 +45,8 @@ git-graphable repo-messy --highlight-wip --highlight-direct-pushes --highlight-s
4545

4646
**Hygiene Report:**
4747
- **Overall Score**: 76% (C)
48-
- **Direct Pushes**: -15% (Non-merge commits on `main`)
49-
- **WIP Commits**: -9% (3 commits with `WIP:` in message)
48+
- **Direct Pushes**: -15%
49+
- **WIP Commits**: -9%
5050

5151
**Output:**
5252
```mermaid
@@ -73,8 +73,107 @@ f534dfb429831e547f418960a9c1091af158664d --> 147f97d5dd2c89f8078e0cc67aab5d49548
7373

7474
---
7575

76-
## 3. Special Features (Score: 93%)
77-
Demonstrates topological analysis features like orphan/dangling commits and divergence (behind base).
76+
## 3. Risk Analysis (Bus Factor)
77+
Highlights branches with many commits but only one contributor. This indicates a "Review Risk" where large amounts of code are being written in isolation.
78+
79+
**Command:**
80+
```bash
81+
git-graphable repo-risk-silo --highlight-silos --silo-threshold 20
82+
```
83+
84+
**Output:**
85+
```mermaid
86+
flowchart TD
87+
3ea61173cf4a6c69db17b4c6501039d33a6982b0["3ea6117 - main - Demo User - 20260305105901"]
88+
5efcb8d1f1ebb2795a738df951c5e06203f262b5["5efcb8d - Alice - 20260305105901"]
89+
9195465c812ad54e5665012678f294b2f22d7184["9195465 - Alice - 20260305105901"]
90+
d3a2ea8a3c8ed7409403d836f4280e7df24fe0a3["d3a2ea8 - Alice - 20260305105901"]
91+
cd27397b8f88e090e5269311b26b77b10a61f954["cd27397 - Alice - 20260305105901"]
92+
43458ccb4b4d435f1e726a71c36f4d74dfef3d88["43458cc - Alice - 20260305105901"]
93+
5781a1dcd158780172ef530c7d3c4a5bbfddbb9b["5781a1d - Alice - 20260305105901"]
94+
192391841cd43546840f9a73ca82d590a596f3d1["1923918 - Alice - 20260305105901"]
95+
1123939f9dc7e8ac88c44560cea2854b25b8633a["1123939 - Alice - 20260305105901"]
96+
3bb33732ee23b3c90eb56131d7c18461e635efab["3bb3373 - Alice - 20260305105901"]
97+
92d7b93cd7f52406236dc1a771c18d3101097ac0["92d7b93 - Alice - 20260305105901"]
98+
edc7e0989161e639f69a2e918315070a9b650257["edc7e09 - Alice - 20260305105901"]
99+
aaa8545d80ce1c7f93f0ed635a642d52e537d418["aaa8545 - Alice - 20260305105901"]
100+
44f32db29d6b3a917fe1f0493a78a563d164eccb["44f32db - Alice - 20260305105901"]
101+
fcb262b2e3dce5b6d005cf5a2ee1e9d51a923053["fcb262b - Alice - 20260305105901"]
102+
588cfa14d70f6679bb53588b4bcb8fa49adedb90["588cfa1 - Alice - 20260305105901"]
103+
fc5736cf0a21cba3426fd0853c24f20592b2c925["fc5736c - Alice - 20260305105901"]
104+
a4f8461065731a429ad9ae8c044827329d3083d5["a4f8461 - Alice - 20260305105901"]
105+
543b5e4de434310b1f90817fd89ac19f735adaa8["543b5e4 - Alice - 20260305105901"]
106+
b1fdd9163e15af3eb69105e1337bbe75813f61f7["b1fdd91 - Alice - 20260305105901"]
107+
b1bba43af1237077c8d101b88d5a2e7aafdd3806["b1bba43 - Alice - 20260305105901"]
108+
807f19736e0a1903dc83ec62cdf810bc5c043a1a["807f197 - Alice - 20260305105901"]
109+
30c28e9ac75e9ca65360d6c000e3dd62b0ff48f7["30c28e9 - Alice - 20260305105901"]
110+
f012b1d4971e5d6e9619396f9adbb32d311e0c80["f012b1d - Alice - 20260305105901"]
111+
76310c4489cb4667e1f31e540b40b42c30b70190["76310c4 - Alice - 20260305105901"]
112+
0007580446cab2af471bc90a29dd094175ef5617["0007580 [SILO] - feature/huge-silo - Alice - 20260305105901"]
113+
style 0007580446cab2af471bc90a29dd094175ef5617 stroke:blue,stroke-width:6px
114+
3ea61173cf4a6c69db17b4c6501039d33a6982b0 --> 5efcb8d1f1ebb2795a738df951c5e06203f262b5
115+
5efcb8d1f1ebb2795a738df951c5e06203f262b5 --> 9195465c812ad54e5665012678f294b2f22d7184
116+
9195465c812ad54e5665012678f294b2f22d7184 --> d3a2ea8a3c8ed7409403d836f4280e7df24fe0a3
117+
d3a2ea8a3c8ed7409403d836f4280e7df24fe0a3 --> cd27397b8f88e090e5269311b26b77b10a61f954
118+
cd27397b8f88e090e5269311b26b77b10a61f954 --> 43458ccb4b4d435f1e726a71c36f4d74dfef3d88
119+
43458ccb4b4d435f1e726a71c36f4d74dfef3d88 --> 5781a1dcd158780172ef530c7d3c4a5bbfddbb9b
120+
5781a1dcd158780172ef530c7d3c4a5bbfddbb9b --> 192391841cd43546840f9a73ca82d590a596f3d1
121+
192391841cd43546840f9a73ca82d590a596f3d1 --> 1123939f9dc7e8ac88c44560cea2854b25b8633a
122+
1123939f9dc7e8ac88c44560cea2854b25b8633a --> 3bb33732ee23b3c90eb56131d7c18461e635efab
123+
3bb33732ee23b3c90eb56131d7c18461e635efab --> 92d7b93cd7f52406236dc1a771c18d3101097ac0
124+
92d7b93cd7f52406236dc1a771c18d3101097ac0 --> edc7e0989161e639f69a2e918315070a9b650257
125+
edc7e0989161e639f69a2e918315070a9b650257 --> aaa8545d80ce1c7f93f0ed635a642d52e537d418
126+
aaa8545d80ce1c7f93f0ed635a642d52e537d418 --> 44f32db29d6b3a917fe1f0493a78a563d164eccb
127+
44f32db29d6b3a917fe1f0493a78a563d164eccb --> fcb262b2e3dce5b6d005cf5a2ee1e9d51a923053
128+
fcb262b2e3dce5b6d005cf5a2ee1e9d51a923053 --> 588cfa14d70f6679bb53588b4bcb8fa49adedb90
129+
588cfa14d70f6679bb53588b4bcb8fa49adedb90 --> fc5736cf0a21cba3426fd0853c24f20592b2c925
130+
fc5736cf0a21cba3426fd0853c24f20592b2c925 --> a4f8461065731a429ad9ae8c044827329d3083d5
131+
a4f8461065731a429ad9ae8c044827329d3083d5 --> 543b5e4de434310b1f90817fd89ac19f735adaa8
132+
543b5e4de434310b1f90817fd89ac19f735adaa8 --> b1fdd9163e15af3eb69105e1337bbe75813f61f7
133+
b1fdd9163e15af3eb69105e1337bbe75813f61f7 --> b1bba43af1237077c8d101b88d5a2e7aafdd3806
134+
b1bba43af1237077c8d101b88d5a2e7aafdd3806 --> 807f19736e0a1903dc83ec62cdf810bc5c043a1a
135+
807f19736e0a1903dc83ec62cdf810bc5c043a1a --> 30c28e9ac75e9ca65360d6c000e3dd62b0ff48f7
136+
30c28e9ac75e9ca65360d6c000e3dd62b0ff48f7 --> f012b1d4971e5d6e9619396f9adbb32d311e0c80
137+
f012b1d4971e5d6e9619396f9adbb32d311e0c80 --> 76310c4489cb4667e1f31e540b40b42c30b70190
138+
76310c4489cb4667e1f31e540b40b42c30b70190 --> 0007580446cab2af471bc90a29dd094175ef5617
139+
```
140+
141+
---
142+
143+
## 4. Redundant History
144+
Highlights redundant back-merges (merging `main` into a feature branch). This helps identify where a rebase strategy might have been cleaner.
145+
146+
**Command:**
147+
```bash
148+
git-graphable repo-complex-hygiene --highlight-back-merges
149+
```
150+
151+
**Output:**
152+
```mermaid
153+
flowchart TD
154+
366874227b985955d27323453b9e075f53065692["3668742 - Demo User - 20260305105901"]
155+
89c693c037b2eab4256beab9ead6572e9c9d0f58["89c693c - Demo User - 20260305105901"]
156+
71589446a700af13cb14ee4fea04c4ab1ad0a1e1["7158944 - Demo User - 20260305105901"]
157+
11f210a834080631aeb343dcec09abde01f15e44["11f210a - Demo User - 20260305105901"]
158+
62d326c80963476bf06537d224f66db9f48f30b4["62d326c [BACK-MERGE] - feature/noisy-history - Demo User - 20260305105901"]
159+
style 62d326c80963476bf06537d224f66db9f48f30b4 stroke:orange,stroke-width:4px,stroke-dasharray: 2 2
160+
96f27dee0ae8c3eb5abb9f9b04b4ead750a729ba["96f27de - main - Demo User - 20260305105901"]
161+
99d822031a58c60594158beecfb254695af84db9["99d8220 - Demo User - 20260305105901"]
162+
594597456b51ab193d76035dc5119f70b4cdaa7a["5945974 - feature/to-be-squashed - Demo User - 20260305105901"]
163+
366874227b985955d27323453b9e075f53065692 --> 89c693c037b2eab4256beab9ead6572e9c9d0f58
164+
366874227b985955d27323453b9e075f53065692 --> 71589446a700af13cb14ee4fea04c4ab1ad0a1e1
165+
89c693c037b2eab4256beab9ead6572e9c9d0f58 --> 62d326c80963476bf06537d224f66db9f48f30b4
166+
71589446a700af13cb14ee4fea04c4ab1ad0a1e1 --> 62d326c80963476bf06537d224f66db9f48f30b4
167+
71589446a700af13cb14ee4fea04c4ab1ad0a1e1 --> 96f27dee0ae8c3eb5abb9f9b04b4ead750a729ba
168+
71589446a700af13cb14ee4fea04c4ab1ad0a1e1 --> 11f210a834080631aeb343dcec09abde01f15e44
169+
11f210a834080631aeb343dcec09abde01f15e44 --> 99d822031a58c60594158beecfb254695af84db9
170+
99d822031a58c60594158beecfb254695af84db9 --> 594597456b51ab193d76035dc5119f70b4cdaa7a
171+
```
172+
173+
---
174+
175+
## 5. Topological Analysis
176+
Demonstrates features like orphan/dangling commits and divergence (behind base).
78177

79178
**Command:**
80179
```bash
@@ -96,7 +195,7 @@ style ebeaa6afb7b85a2d84d8aa5279ca3ad50f54a987 stroke:orange,stroke-width:2px,st
96195

97196
---
98197

99-
## 4. CI Mode (Gating)
198+
## 6. CI Mode (Gating)
100199
Demonstrates how to use `git-graphable` as a CI gate. The tool returns a non-zero exit code if the hygiene score is below the threshold.
101200

102201
**Command (Fails):**

examples/generate_demos.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,13 +129,67 @@ def generate_features():
129129
run_git(["branch", "-D", "detached-work"], path)
130130

131131

132+
def generate_risk_silo():
133+
print("Generating repo-risk-silo...")
134+
path = create_base_repo("repo-risk-silo")
135+
136+
# Create a long-running branch with only one author (Alice)
137+
run_git(["checkout", "-b", "feature/huge-silo"], path)
138+
run_git(["config", "user.name", "Alice"], path)
139+
run_git(["config", "user.email", "[email protected]"], path)
140+
141+
for i in range(25):
142+
(path / f"work_{i}.txt").write_text(f"work {i}")
143+
run_git(["add", f"work_{i}.txt"], path)
144+
run_git(["commit", "-m", f"chore: alice working hard {i}"], path)
145+
146+
run_git(["checkout", "main"], path)
147+
148+
149+
def generate_squash_and_backmerge():
150+
print("Generating repo-complex-hygiene...")
151+
path = create_base_repo("repo-complex-hygiene")
152+
153+
# 1. A branch that was back-merged (main into feature)
154+
run_git(["checkout", "-b", "feature/noisy-history"], path)
155+
(path / "feat.txt").write_text("feat")
156+
run_git(["add", "feat.txt"], path)
157+
run_git(["commit", "-m", "feat: start working"], path)
158+
159+
run_git(["checkout", "main"], path)
160+
(path / "main_work.txt").write_text("main")
161+
run_git(["add", "main_work.txt"], path)
162+
run_git(["commit", "-m", "chore: some main work"], path)
163+
164+
run_git(["checkout", "feature/noisy-history"], path)
165+
run_git(
166+
["merge", "main", "-m", "Merge branch 'main' into feature/noisy-history"], path
167+
)
168+
169+
# 2. A branch intended for squashing (manual simulation)
170+
run_git(["checkout", "main"], path)
171+
run_git(["checkout", "-b", "feature/to-be-squashed"], path)
172+
for i in range(3):
173+
(path / f"part_{i}.txt").write_text(f"part {i}")
174+
run_git(["add", f"part_{i}.txt"], path)
175+
run_git(["commit", "-m", f"feat: part {i} of squashed work"], path)
176+
177+
# Simulate the squash commit on main (we won't link it here, highlighter does it via PR OIDs)
178+
run_git(["checkout", "main"], path)
179+
(path / "squashed_result.txt").write_text("all parts")
180+
run_git(["add", "squashed_result.txt"], path)
181+
run_git(["commit", "-m", "feat: implementing all parts (#123)"], path)
182+
183+
132184
def main():
133185
REPOS_DIR.mkdir(exist_ok=True)
134186
ASSETS_DIR.mkdir(exist_ok=True)
135187

136188
generate_pristine()
137189
generate_messy()
138190
generate_features()
191+
generate_risk_silo()
192+
generate_squash_and_backmerge()
139193

140194
print("\nDone! Demo repositories created in examples/repos/")
141195

pyproject.toml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,21 +5,25 @@ authors = [
55
dependencies = [
66
"graphable>=0.6.0",
77
]
8-
description = "A powerful tool to convert Git commit history into beautiful flowcharts."
8+
description = "A powerful Git history visualizer and hygiene linter with CI gating."
99
keywords = [
1010
"analysis",
11+
"ci",
1112
"d2",
1213
"git",
14+
"git-flow",
15+
"github",
1316
"graph",
1417
"hygiene",
18+
"lint",
1519
"mermaid",
1620
"topology",
1721
"visualization",
1822
]
1923
name = "git-graphable"
2024
readme = "README.md"
2125
requires-python = ">=3.13"
22-
version = "0.1.0"
26+
version = "0.2.0"
2327

2428
[project.optional-dependencies]
2529
cli = [

uv.lock

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)