The Merge Line Problem
In a Git graph visualization, branches are represented as colored lines. When two branches merge, what color should the merge line be?Copy
┌───────────────────────────────────────────────────────────────────────────────┐
│ GIT GRAPH VISUALIZATION PROBLEM │
├───────────────────────────────────────────────────────────────────────────────┤
│ │
│ Simple Approach: Use target branch color │
│ ═════════════════════════════════════════ │
│ │
│ main (blue) feature (orange) │
│ │ │ │
│ │ │ │
│ │ merge commit │ │
│ │<────────────────────┘ │
│ │ ^ │
│ │ │ │
│ │ What color? │
│ v │
│ │
│ If we use blue (main's color): │
│ - The merge line looks like a normal main commit │
│ - We lose the visual connection to feature branch │
│ │
│ If we use orange (feature's color): │
│ - Inconsistent with main's visual identity │
│ - Confusing: is this main or feature? │
│ │
├───────────────────────────────────────────────────────────────────────────────┤
│ │
│ Better Approach: Interpolate between both colors │
│ ═════════════════════════════════════════════════ │
│ │
│ main (blue) feature (orange) │
│ │ │ │
│ │ │ │
│ │<───────BLEND────────┘ │
│ │ (50% mix) │
│ │ │
│ │
│ The merge line should visually represent BOTH parents. │
│ Using color interpolation creates this effect. │
│ │
└───────────────────────────────────────────────────────────────────────────────┘
sRGB vs OKLAB for Merge Lines
Copy
┌───────────────────────────────────────────────────────────────────────────────┐
│ sRGB MERGE LINE: MUDDY RESULT │
├───────────────────────────────────────────────────────────────────────────────┤
│ │
│ main: rgb(38, 136, 199) -- Blue (#2688C7) │
│ feature: rgb(199, 136, 38) -- Orange (#C78826) │
│ │
│ sRGB midpoint: │
│ R = (38 + 199) / 2 = 118.5 │
│ G = (136 + 136) / 2 = 136 │
│ B = (199 + 38) / 2 = 118.5 │
│ │
│ Result: rgb(119, 136, 119) -- Grayish-green │
│ │
│ main feature │
│ (vibrant) (vibrant) │
│ │ │ │
│ │ ┌───────────┐ │ │
│ │<───│ MUDDY MIX │───────┘ │
│ │ │ (dull) │ │
│ │ └───────────┘ │
│ v │
│ │
│ The merge line looks "sick" or "faded" compared to vibrant branches. │
│ │
└───────────────────────────────────────────────────────────────────────────────┘
Copy
┌───────────────────────────────────────────────────────────────────────────────┐
│ OKLAB MERGE LINE: CLEAN RESULT │
├───────────────────────────────────────────────────────────────────────────────┤
│ │
│ main: oklch(55% 0.15 230) -- Blue │
│ feature: oklch(55% 0.15 50) -- Orange │
│ │
│ Blue and Orange are OPPOSITE on the color wheel (180 apart). │
│ Their true midpoint IS neutral. This is mathematically correct. │
│ │
│ The DIFFERENCE from sRGB: │
│ - sRGB gray: Muddy, brownish-green, inconsistent lightness │
│ - OKLAB gray: Clean neutral gray, consistent lightness │
│ │
└───────────────────────────────────────────────────────────────────────────────┘
Non-Opposite Colors: Where OKLAB Shines
Most branch combinations are NOT opposite colors, and this is where OKLAB really demonstrates its value.Copy
┌───────────────────────────────────────────────────────────────────────────────┐
│ NON-OPPOSITE COLORS: OKLAB ADVANTAGE │
├───────────────────────────────────────────────────────────────────────────────┤
│ │
│ main: oklch(55% 0.15 230) -- Blue │
│ hotfix: oklch(55% 0.15 25) -- Red │
│ │
│ Hue difference: 230 - 25 = 205 degrees (not opposite!) │
│ │
│ OKLAB interpolation: │
│ main: L=0.55, a=-0.10, b=-0.11 │
│ hotfix: L=0.55, a=0.13, b=0.07 │
│ │
│ Midpoint: │
│ L = 0.55 │
│ a = (-0.10 + 0.13) / 2 = 0.015 │
│ b = (-0.11 + 0.07) / 2 = -0.02 │
│ │
│ Result: A desaturated purple-ish color (not gray!) │
│ The hue is approximately 307deg with low chroma. │
│ │
│ Compare to sRGB: │
│ sRGB midpoint would be muddy brown-gray. │
│ OKLAB midpoint is a recognizable (if muted) purple. │
│ │
│ main (blue) hotfix (red) │
│ │ │ │
│ │ │ │
│ │<───purple-ish───┘ │
│ │ (clean) │
│ v │
│ │
└───────────────────────────────────────────────────────────────────────────────┘
Branch Color Distribution with Golden Angle
For maximum distinction between branches, use the full Golden Angle (137.5 degrees).Copy
┌───────────────────────────────────────────────────────────────────────────────┐
│ BRANCH COLOR DISTRIBUTION │
├───────────────────────────────────────────────────────────────────────────────┤
│ │
│ Using Golden Angle (137.5 degrees) for maximum distinction: │
│ │
│ Branch Index Hue Calculation Result │
│ ────── ───── ─────────────── ────── │
│ main 0 0 + 0*137.5 = 0 0deg (Red) │
│ develop 1 0 + 1*137.5 = 137.5 137.5deg (Yellow-Green) │
│ feature-1 2 0 + 2*137.5 = 275 275deg (Blue-Purple) │
│ feature-2 3 0 + 3*137.5 = 52.5 52.5deg (Yellow-Orange) │
│ hotfix 4 0 + 4*137.5 = 190 190deg (Cyan) │
│ release 5 0 + 5*137.5 = 327.5 327.5deg (Pink-Red) │
│ │
│ No matter how many branches, they never cluster together. │
│ │
├───────────────────────────────────────────────────────────────────────────────┤
│ │
│ Color Wheel with Branch Distribution: │
│ │
│ 0deg (main) │
│ * │
│ / \ │
│ / \ │
│ 5 * * 3 (feature-2) │
│ (release) 52.5deg │
│ / \ │
│ / \ │
│ 270deg ────────┼───────────────────┼──────── 90deg │
│ \ / │
│ \ / │
│ 2 * * 4 (hotfix) │
│ (feature-1) 190deg │
│ 275deg \ / │
│ \ / │
│ \ / │
│ * │
│ 1 (develop) │
│ 137.5deg │
│ │
│ Maximum separation between any two branches. │
│ │
└───────────────────────────────────────────────────────────────────────────────┘
Merge Scenarios
Feature into Main
Copy
┌───────────────────────────────────────────────────────────────────────────────┐
│ SCENARIO: FEATURE -> MAIN │
├───────────────────────────────────────────────────────────────────────────────┤
│ │
│ main: oklch(55% 0.15 0) -- Red (H=0) │
│ feature: oklch(55% 0.15 275) -- Blue-Purple (H=275) │
│ │
│ Hue difference: 275 - 0 = 275 degrees │
│ (Or shorter path: 360 - 275 = 85 degrees) │
│ │
│ OKLAB interpolation will find geometric midpoint: │
│ Result: approximately H=320 (Pink-Magenta area) │
│ │
│ main (red) │
│ * │
│ │ │
│ │<───── merge line (pink-ish) ─────* feature (purple) │
│ │ │
│ v │
│ │
│ The merge line is visually between both colors. │
│ │
└───────────────────────────────────────────────────────────────────────────────┘
Hotfix into Main
Copy
┌───────────────────────────────────────────────────────────────────────────────┐
│ SCENARIO: HOTFIX -> MAIN │
├───────────────────────────────────────────────────────────────────────────────┤
│ │
│ main: oklch(55% 0.15 0) -- Red (H=0) │
│ hotfix: oklch(55% 0.15 190) -- Cyan (H=190) │
│ │
│ Hue difference: 190 degrees (close to opposite!) │
│ │
│ OKLAB interpolation: │
│ Result: Low chroma, approximately neutral │
│ │
│ main (red) │
│ * │
│ │ │
│ │<───── merge line (grayish) ─────* hotfix (cyan) │
│ │ │
│ v │
│ │
│ Near-opposite colors produce near-neutral merge. │
│ This is mathematically correct and perceptually appropriate. │
│ │
└───────────────────────────────────────────────────────────────────────────────┘
Merge Commit vs Merge Line
Copy
┌───────────────────────────────────────────────────────────────────────────────┐
│ MERGE COMMIT vs MERGE LINE │
├───────────────────────────────────────────────────────────────────────────────┤
│ │
│ Distinction: │
│ - Merge LINE: The arrow/line connecting parent to merge commit │
│ - Merge COMMIT: The node representing the merge itself │
│ │
│ parent1 parent2 │
│ * * │
│ \ / │
│ \ <- MERGE LINE -> / │
│ \ (interpolated)/ │
│ \ / │
│ \ / │
│ \ / │
│ ┌────*────┐ │
│ ^ │
│ │ │
│ MERGE COMMIT │
│ (target branch color) │
│ │
│ Color assignments: │
│ - Merge LINE from parent1: color-mix(in oklab, parent1, target 50%) │
│ - Merge LINE from parent2: color-mix(in oklab, parent2, target 50%) │
│ - Merge COMMIT: target branch color (pure) │
│ │
└───────────────────────────────────────────────────────────────────────────────┘
CSS Implementation
Copy
/* Branch Core Colors (OKLCH) */
:root {
--branch-main: oklch(55% 0.15 0);
--branch-develop: oklch(55% 0.15 137.5);
--branch-feature-1: oklch(55% 0.15 275);
--branch-feature-2: oklch(55% 0.15 52.5);
--branch-hotfix: oklch(55% 0.18 190);
--branch-release: oklch(55% 0.15 327.5);
}
/* Merge Line Colors via color-mix (Flow) */
.git-graph .merge-line {
--merge-color: color-mix(
in oklab,
var(--parent-1-color) 50%,
var(--parent-2-color)
);
background: var(--merge-color);
}
/* Specific merge scenarios */
.merge-line[data-from="feature"][data-to="main"] {
--merge-color: color-mix(
in oklab,
var(--branch-main) 50%,
var(--branch-feature-1)
);
}
.merge-line[data-from="hotfix"][data-to="main"] {
--merge-color: color-mix(
in oklab,
var(--branch-main) 50%,
var(--branch-hotfix)
);
}
Hierarchical Coloring for Many Branches
Copy
┌───────────────────────────────────────────────────────────────────────────────┐
│ HIERARCHICAL BRANCH COLORING │
├───────────────────────────────────────────────────────────────────────────────┤
│ │
│ Number of branches Strategy │
│ ────────────────── ──────── │
│ │
│ 2-6 branches Golden angle works perfectly │
│ All colors clearly distinct │
│ │
│ 7-12 branches Golden angle still works │
│ Some colors may feel similar │
│ Consider varying lightness/chroma │
│ │
│ 13-20 branches Colors start to repeat visually │
│ Use groups (same hue, different chroma) │
│ │
│ 20+ branches Color alone is insufficient │
│ Add secondary indicators (patterns, icons) │
│ │
├───────────────────────────────────────────────────────────────────────────────┤
│ │
│ Group by type, vary within groups: │
│ │
│ Tier 1: Branch Type (Hue) │
│ ───────────────────────── │
│ main/master: Red area (0-30) │
│ develop: Green area (100-160) │
│ feature/*: Blue area (200-260) │
│ hotfix/*: Orange area (30-60) │
│ release/*: Purple area (270-330) │
│ │
│ Tier 2: Within Group (Chroma/Lightness) │
│ ─────────────────────────────────────── │
│ feature/auth: oklch(55% 0.15 220) │
│ feature/ui: oklch(55% 0.12 230) <- lower chroma │
│ feature/api: oklch(60% 0.15 240) <- higher lightness │
│ feature/db: oklch(50% 0.15 250) <- lower lightness │
│ │
└───────────────────────────────────────────────────────────────────────────────┘
Branch Status Colors
Copy
/* Branch Status Colors */
.git-branch[data-status="active"] {
/* Active branch (checked out) */
--branch-glow: color-mix(in oklab, var(--branch-color), transparent 70%);
box-shadow: 0 0 8px var(--branch-glow);
}
.git-branch[data-status="stale"] {
/* Stale branch (no recent commits) */
--branch-color-muted: color-mix(in oklab, var(--branch-color), gray 50%);
color: var(--branch-color-muted);
}
.git-branch[data-status="merged"] {
/* Already merged branch */
--branch-color-faded: color-mix(in oklab, var(--branch-color), transparent 60%);
color: var(--branch-color-faded);
text-decoration: line-through;
}
THE CENTER
Merge Lines as Relationship Indicators
In a Git graph, merge lines are the visual representation of code integration. The color of a merge line should communicate “this brings together branch A and branch B.” OKLAB interpolation achieves this by producing a clean, predictable intermediate color.Copy
Connection to Core-Flow:
├── Branch colors are Core (identity via OKLCH)
├── Merge colors are Flow (relationship via OKLAB mixing)
├── Golden Angle ensures maximum branch distinction
└── Clean merge colors = clear visualization of history
Dynamic Generation
Runtime gradient generation with OKLCH/OKLAB