1// ââ Worktree vs Branches Diagram âââââââââââââââââââââââââââââââââââââââââââââ 2microblogEntries.push({ 3 content: `<p>A <strong>branch</strong> is just a pointer to a commit. Switching branches swaps files in your single working directory. Which forces one on stashing uncommitted work. A <strong>worktree</strong> (<code>git worktree add</code>) gives each branch its own directory, all backed by the same <code>.git</code> object store. Thus, no stashing required, a personal ick only tbh.</p> 4<p>The agentic advantage: worktrees let you run coding agents in parallel. Each agent gets its own isolated checkout while sharing the same repo. <a href="https://github.com/jj-vcs/jj" target="_blank">Jujutsu (jj)</a> is an open-source alternative that bakes this kind of parallel workflow into the VCS itself. Find a better deep dive into other alternatives <a href="https://blog.ezyang.com/2026/03/parallel-agents-heart-sapling/" target="_blank">here</a>.</p>`, 5 date: "Mar. '26", 6 diagram: "worktree", 7 id: "(Git) worktrees-vs-branches", 8 links: [], 9 tags: ["git", "workflow"], 10 title: "(Git) Worktrees vs Branches", 11}); 12 13function buildWorktreeDiagram() { 14 const container = document.getElementById("microblog-diagram-worktree"); 15 if (!container) { 16 return; 17 } 18 19 let mode = "branch"; 20 21 // Shared geometry â larger viewBox so SVG text renders at readable sizes 22 const W = 440, 23 H = 220; 24 const gitX = W / 2, 25 gitY = 32, 26 gitRx = 44, 27 gitRy = 18; 28 29 const branchLayout = { 30 boxes: [{ x: W / 2, y: 130 }], 31 connectors: [[gitX, gitY + gitRy, W / 2, 130 - 22]], 32 footnote: "stash \u2192 checkout \u2192 switch", 33 labels: [ 34 { dim: true, text: "main", x: 62, y: 130 }, 35 { dim: false, text: "feat-A", x: W / 2, y: 190 }, 36 { dim: true, text: "fix-B", x: 378, y: 130 }, 37 ], 38 }; 39 40 const worktreeLayout = { 41 boxes: [ 42 { x: W / 2 - 95, y: 130 }, 43 { x: W / 2 + 95, y: 130 }, 44 ], 45 connectors: [ 46 [gitX - 16, gitY + gitRy, W / 2 - 95, 130 - 22], 47 [gitX + 16, gitY + gitRy, W / 2 + 95, 130 - 22], 48 ], 49 footnote: "parallel \u2014 no stashing needed", 50 labels: [], 51 }; 52 53 function buildSvg(layout) { 54 const bw = 130, 55 bh = 44; 56 let s = `<svg viewBox="0 0 ${W} ${H}" class="wt-svg" xmlns="http://www.w3.org/2000/svg">`; 57 58 // .git ellipse 59 s += `<ellipse cx="${gitX}" cy="${gitY}" rx="${gitRx}" ry="${gitRy}" 60 fill="none" stroke="var(--text-secondary)" stroke-width="1.2" stroke-dasharray="4 3" opacity="0.55"/>`; 61 s += `<text x="${gitX}" y="${gitY + 5}" text-anchor="middle" 62 font-family="var(--font-mono)" font-size="13" fill="var(--text-secondary)">.git</text>`; 63 64 // Connectors (dashed lines from .git to boxes) 65 for (const [x1, y1, x2, y2] of layout.connectors) { 66 s += `<line x1="${x1}" y1="${y1}" x2="${x2}" y2="${y2}" 67 stroke="var(--text-secondary)" stroke-width="0.9" stroke-dasharray="4 3" opacity="0.45"/>`; 68 } 69 70 // Boxes 71 const single = layout.boxes.length === 1; 72 for (const [i, b] of layout.boxes.entries()) { 73 const col = !single && i === 0 ? "var(--link)" : "var(--text)"; 74 s += `<rect x="${b.x - bw / 2}" y="${b.y - bh / 2}" width="${bw}" height="${bh}" 75 rx="4" fill="none" stroke="${col}" stroke-width="1.2"/>`; 76 let inner = "working dir"; 77 if (!single) { 78 inner = i === 0 ? "feat-A/" : "fix-B/"; 79 } 80 s += `<text x="${b.x}" y="${b.y + 5}" text-anchor="middle" 81 font-family="var(--font-mono)" font-size="12" fill="${col}">${inner}</text>`; 82 } 83 84 // Branch labels (only in branch mode) 85 for (const l of layout.labels) { 86 const col = l.dim ? "var(--text-secondary)" : "var(--link)"; 87 const op = l.dim ? "0.4" : "1"; 88 s += `<text x="${l.x}" y="${l.y + 5}" text-anchor="middle" 89 font-family="var(--font-mono)" font-size="11" fill="${col}" opacity="${op}">${l.text}</text>`; 90 if (!l.dim && layout.boxes.length === 1) { 91 const bx = layout.boxes[0].x; 92 s += `<line x1="${l.x}" y1="${l.y - 5}" x2="${bx}" y2="${layout.boxes[0].y + bh / 2}" 93 stroke="var(--link)" stroke-width="0.7" stroke-dasharray="3 2" opacity="0.45"/>`; 94 } 95 } 96 97 // Footnote 98 s += `<text x="${W / 2}" y="${H - 6}" text-anchor="middle" 99 font-family="var(--font-mono)" font-size="10" fill="var(--text-secondary)" opacity="0.5">${layout.footnote}</text>`; 100 101 s += "</svg>"; 102 return s; 103 } 104 105 function render() { 106 const layout = mode === "branch" ? branchLayout : worktreeLayout; 107 container.querySelector(".wt-diagram-area").innerHTML = buildSvg(layout); 108 } 109 110 // Toggle buttons (reuse dcn-toggle / dcn-btn styles) 111 const toggle = document.createElement("div"); 112 toggle.className = "dcn-toggle"; 113 114 const btnBr = document.createElement("button"); 115 btnBr.className = "dcn-btn active"; 116 btnBr.textContent = "Branches"; 117 118 const btnWt = document.createElement("button"); 119 btnWt.className = "dcn-btn"; 120 btnWt.textContent = "Worktrees"; 121 122 function setMode(m) { 123 if (m === mode) { 124 return; 125 } 126 mode = m; 127 btnBr.classList.toggle("active", mode === "branch"); 128 btnWt.classList.toggle("active", mode === "worktree"); 129 const area = container.querySelector(".wt-diagram-area"); 130 area.classList.add("wt-fading"); 131 setTimeout(() => { 132 render(); 133 area.classList.remove("wt-fading"); 134 }, 200); 135 } 136 137 btnBr.addEventListener("click", () => setMode("branch")); 138 btnWt.addEventListener("click", () => setMode("worktree")); 139 140 toggle.appendChild(btnBr); 141 toggle.appendChild(btnWt); 142 143 const area = document.createElement("div"); 144 area.className = "wt-diagram-area"; 145 146 const caption = document.createElement("p"); 147 caption.className = "dcn-caption"; 148 caption.textContent = 149 "Click to compare single-directory branching with parallel worktrees."; 150 151 container.appendChild(toggle); 152 container.appendChild(area); 153 container.appendChild(caption); 154 render(); 155}
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.