aditazzz

Videos Merge Conflict

Merge Conflict

Two hearts on the same line, at the very same time. 💔 A breakup told as a git merge conflict: HEAD (her) versus the incoming branch (him), one file, line 42.

Watch on YouTube · 3:30 · video by Claude Fable 5.1 ·

The code behind it

Every frame of this video is drawn by a Python program. This is the heart of it, from scenes.py, line 347.

songs/merge-conflict/scenes.py
def sec_chorus(c, t, A, key):
    T = CH[key]
    t0 = {'ch1': 75.1, 'ch2': 127.2}[key]; t1 = {'ch1': 91.9, 'ch2': 144.6}[key]
    a_sec = sec_alpha(t, t0, t1, 0.02, 0.3)
    layer(c, a_sec)
    pulse = 1 + 0.02 * A['kick']
    vise = ease_io5(ramp(t, T[6], T[7] + 0.6))
    gap = lerp(1.0, 0.45, vise)
    # faces
    fy = CY - 10
    her(c, 470 + 160 * vise, fy, 0.62 * pulse, 1 - 0.3 * vise, look=0.5, glow=1 + A['kick'])
    him(c, 1450 - 160 * vise, fy, 0.62 * pulse, 1 - 0.3 * vise, look=-0.5, glow=1 + A['kick'])
    # title
    ta = window(t, T[0] - 0.05, T[1] + 0.2, 0.08, 0.3)
    if ta > 0:
        draw_text(c, 'MERGE CONFLICT', CX, 140, TF_MONO4, 72, IVORY, ta, tracking=24,
                  glow=1.4 * max(0, 1 - (t - T[0]) / 0.5) + 0.6 + A['kick'])
    # your version or mine: two code lines alternate on beats
    va = window(t, T[1] - 0.05, T[2] + 0.1, 0.1, 0.3)
    if va > 0:
        on = int((t - T[1]) / BEAT) % 2
        draw_text(c, 'def get_user(id):', CX, CY - 40, TF_MONO, 34, HER, va * (1 if on == 0 else 0.25), glow=0.8 * (on == 0))
        draw_text(c, 'async def fetch_user(id):', CX, CY + 40, TF_MONO, 34, HIM, va * (1 if on == 1 else 0.25),
                  glow=0.8 * (on == 1))
    # two hearts on the same line, same time
    ha = window(t, T[2] - 0.05, T[4] + 0.1, 0.1, 0.3)
    if ha > 0:
        hy = CY + 40
        c.drawPath(line(CX - 360, hy + 30, CX + 360, hy + 30), stroke_paint(SILVER, ha * 0.6, 1.4))
        mono_label(c, '42', CX - 400, hy + 36, 16, ha * 0.5, align='right')
        u = ease_in(ramp(t, T[2], T[3] + 0.1))
        for s, colr in ((-1, HER), (1, HIM)):
            x = CX + s * lerp(300, 46, u)
            draw_icon(c, HEART, x, hy - 20, 0.42, ha, colr, 2.0, glow=0.8)
        if t > T[3] + 0.1:
            k = max(0, 1 - (t - T[3] - 0.1) / 0.6)
            ripple(c, CX, hy - 20, t, T[3] + 0.1, 0.7, 10, 160, IVORY, 0.9)
            draw_icon(c, CROSS, CX, hy - 110, 1.0, ha * ease_out(ramp(t, T[3] + 0.1, T[3] + 0.3)), IVORY, 2.6, glow=1 + k)
    # rebase refusals
    ra = window(t, T[4] - 0.05, T[6] + 0.1, 0.1, 0.3)
    if ra > 0:
        for i, (s, colr, x) in enumerate((('$ git rebase feature/async', HER, CX), ('$ git rebase main', HIM, CX))):
            ti = T[4 + i]
            if t < ti:
                continue
            y = CY - 40 + i * 90
            k = ease_out(ramp(t, ti, ti + 0.3))
            draw_text(c, s, x, y, TF_MONO, 30, colr, ra * k)
            draw_text(c, 'refused', x, y + 34, TF_MONO, 16, SILVER, ra * 0.6 * ease_out(ramp(t, ti + 0.6, ti + 0.9)),
                      tracking=4)
    # stuck between the markers: vise
    if vise > 0 or t > T[6]:
        ma = window(t, T[6] - 0.05, t1 + 0.4, 0.15, 0.4)
        top = lerp(80, CY - 230, vise)
        bot = lerp(H - 140, CY + 230, vise)
        draw_text(c, '<' * 7 + ' HEAD', CX, top, TF_MONO, 54, HER, ma, tracking=8, glow=0.8)
    ...

Read all 634 lines on GitHub. If you use it, credit aditazzz and link the video.

What you see

Fine white lines on black. Her face on the left is HEAD; his on the right is the incoming branch. Between them sits main.py, and both of them keep rewriting line 42: she renames the function and leaves a note, he makes it async and clean, and on the branch graph his feature branch lives for three whole weeks without a single pull. The pre-chorus draws the conflict markers between the two faces, seven arrows left, a line of equals, seven arrows right, and nothing in the middle but the screen.

In the chorus the two versions of the line alternate on the beat, two hearts land on the same line at the same time, each rebase is refused, and the markers close like a vise. Verse two is the evidence: her green tests, his thread where the lead said yes, a force-push forgiven, commits squashed, "works on my machine" on both laptops. The bridge is a code lens over the review notes (get_user (better), if user is None: return (saved me)), and the breakdown runs through the editor's three buttons: accept current, accept incoming, accept both. Build failed. The final chorus resolves the file line by line, merges on the graph, pushes straight to main, and the marker glyphs drift away. The outro: merge successful. Two new conflicts in utils.py.

Files

FileLinesWhat it draws
scenes.py634Every section of the video: the two faces, the code editor, the branch graph, the conflict markers, the chorus, the evidence, the code lens, the breakdown, the resolution and the outro, plus the HUD for both aspect ratios.

By the numbers

  • 3:30 long, 12,570 frames rendered (16:9 and 9:16, 30 fps), 120 BPM
  • 61 lyric lines and 338 words synced to the vocals (the word timings came from a local Whisper pass and are written into scenes.py)
  • 5 Shorts and Reels cut from it

Lyrics

Words and music by aditazzz.

Intro

Auto-merging main.py
Conflict
Automatic merge failed

Verse

I was here first on line forty-two
I renamed the function, I left you a note
You lived on a branch for three whole weeks
Never pulled once, never wrote
I rewrote that line the very same day
I made it async, I made it clean
You never told me you were touching it
You never told me anything

Pre-chorus

Seven arrows pointing left (that's you)
A line of equals in between (that's us)
Seven arrows pointing right (that's me)
And nothing in the middle but the screen

Chorus

It's a merge conflict, baby
Your version or mine
Two hearts on the same line
At the very same time
I won't rebase for you
You won't rebase for me
So we're stuck between the markers
Of what we used to be

Verse

My tests all pass, I've got a green check
I've got a thread where the lead said yes
You force-pushed once and I forgave you
You squashed my commits and I'm still a mess
It works on my machine
It works on mine
Then why won't it work
On this one line

Pre-chorus

Seven arrows pointing left (that's you)
A line of equals in between (that's us)
Seven arrows pointing right (that's me)
And nothing in the middle but the screen

Chorus

It's a merge conflict, baby
Your version or mine
Two hearts on the same line
At the very same time
I won't rebase for you
You won't rebase for me
So we're stuck between the markers
Of what we used to be

Break

Accept current change
Accept incoming change
Accept both changes
Build failed

Bridge

Maybe your function name was better
Maybe your null check saved my life
Maybe we were never enemies
Just two people and one file

Final chorus

So I'll take your version, baby
And you'll keep a piece of mine
We'll delete the markers
Line by line
Commit it together
Push it straight to main
No more arrows
No more pain

Outro

Merge successful
Two new conflicts in utils.py