Skip to main content

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?
┌───────────────────────────────────────────────────────────────────────────────┐
│                    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

┌───────────────────────────────────────────────────────────────────────────────┐
│                    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.       │
│                                                                               │
└───────────────────────────────────────────────────────────────────────────────┘
┌───────────────────────────────────────────────────────────────────────────────┐
│                    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.
┌───────────────────────────────────────────────────────────────────────────────┐
│                    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).
┌───────────────────────────────────────────────────────────────────────────────┐
│                    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

┌───────────────────────────────────────────────────────────────────────────────┐
│                    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

┌───────────────────────────────────────────────────────────────────────────────┐
│                    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

┌───────────────────────────────────────────────────────────────────────────────┐
│                    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

/* 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

┌───────────────────────────────────────────────────────────────────────────────┐
│                    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

/* 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.
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
When two branches merge, their colors should blend - not clash. OKLAB interpolation ensures that the merge line visually represents both parents without becoming muddy or confusing.

Dynamic Generation

Runtime gradient generation with OKLCH/OKLAB