PageSourceSearch

https://aymuos15.github.io/microblogs/worktree-vs-branches.js

js aymuos15.github.io collected 2026-10-03 08:40:59 UTC 6,106 bytes, 155 lines download raw bytes

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.