<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Git on Krishnatejaswi S</title>
    <link>https://KTS-o7.github.io/bear/tags/git/</link>
    <description>Recent content in Git on Krishnatejaswi S</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <managingEditor>shentharkrishnatejaswi@gmail.com (Krishnatejaswi S)</managingEditor>
    <webMaster>shentharkrishnatejaswi@gmail.com (Krishnatejaswi S)</webMaster>
    <copyright>Krishnatejaswi S</copyright>
    <lastBuildDate>Thu, 19 Feb 2026 00:00:00 +0530</lastBuildDate>
    <atom:link href="https://KTS-o7.github.io/bear/tags/git/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Many Small Tasks, One Deadline: Running Parallel AI Agents with Git Worktrees</title>
      <link>https://KTS-o7.github.io/bear/notes/codex_worktrees_adventure/</link>
      <pubDate>Thu, 19 Feb 2026 00:00:00 +0530</pubDate><author>shentharkrishnatejaswi@gmail.com (Krishnatejaswi S)</author>
      <guid>https://KTS-o7.github.io/bear/notes/codex_worktrees_adventure/</guid>
      <description>&lt;p&gt;I thought this would be an easy day.&lt;/p&gt;&#xA;&lt;p&gt;The tasks were small. The backlog was not. This is the worst possible combo for a normal workflow because the fixed overhead dominates: branch setup, dependency sync, commits, reviewable diffs, and PR management. Doing it serially feels safe, but it is slow in a way that doesn&amp;rsquo;t show up in estimates.&lt;/p&gt;&#xA;&lt;p&gt;So I tried the obvious cheat: run multiple AI agents in parallel.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<p>I thought this would be an easy day.</p>
<p>The tasks were small. The backlog was not. This is the worst possible combo for a normal workflow because the fixed overhead dominates: branch setup, dependency sync, commits, reviewable diffs, and PR management. Doing it serially feels safe, but it is slow in a way that doesn&rsquo;t show up in estimates.</p>
<p>So I tried the obvious cheat: run multiple AI agents in parallel.</p>
<p>It worked, but only after I tripped over three problems that are easy to reproduce if you try this without thinking through git state, shells, and sandbox boundaries.</p>
<h2 id="what-the-system-looked-like-so-you-dont-think-this-is-a-demo-problem">What the system looked like (so you don&rsquo;t think this is a demo problem)</h2>
<p>I ended up writing a small orchestration script with three phases:</p>
<ol>
<li>Create (or reuse) one worktree per task.</li>
<li>Install dependencies in parallel.</li>
<li>Run <code>codex exec</code> in batched parallel, then push branches and open draft PRs.</li>
</ol>
<p>The key detail is that batching wasn&rsquo;t “run everything at once”. It was “parallel within a batch, sequential across batches”, grouped by expected file overlap.</p>
<p>Here is the redacted shape of the script (this is not pseudocode; it&rsquo;s a sanitized skeleton of what I ran):</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-zsh" data-lang="zsh"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="cp">#!/usr/bin/env zsh
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="nb">set</span> -euo pipefail
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="nv">WORKTREE_DIR</span><span class="o">=</span><span class="s2">&#34;.worktrees&#34;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="nv">BASE_BRANCH</span><span class="o">=</span><span class="s2">&#34;&lt;base-branch&gt;&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="nv">LOG_DIR</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">WORKTREE_DIR</span><span class="si">}</span><span class="s2">/_logs&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">mkdir -p <span class="s2">&#34;</span><span class="si">${</span><span class="nv">WORKTREE_DIR</span><span class="si">}</span><span class="s2">&#34;</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">LOG_DIR</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"># Phase 1: worktrees + deps (parallel installs)</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">hdr <span class="s2">&#34;Phase 1: Setting up worktrees&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">git worktree add -b <span class="s2">&#34;&lt;feature-branch&gt;&#34;</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">WORKTREE_DIR</span><span class="si">}</span><span class="s2">/&lt;lane&gt;&#34;</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">BASE_BRANCH</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="o">(</span><span class="nb">cd</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">WORKTREE_DIR</span><span class="si">}</span><span class="s2">/&lt;lane&gt;/frontend&#34;</span> <span class="o">&amp;&amp;</span> bun install --frozen-lockfile<span class="o">)</span> <span class="p">&amp;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="o">(</span><span class="nb">cd</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">WORKTREE_DIR</span><span class="si">}</span><span class="s2">/&lt;lane&gt;/backend&#34;</span>  <span class="o">&amp;&amp;</span> uv sync<span class="o">)</span> <span class="p">&amp;</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl"><span class="nb">wait</span>
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="c1"># Phase 2: batched parallel codex exec (one log per lane)</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">hdr <span class="s2">&#34;Phase 2: Running Codex&#34;</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">codex <span class="nb">exec</span> --dangerously-bypass-approvals-and-sandbox -C <span class="s2">&#34;</span><span class="si">${</span><span class="nv">WORKTREE_DIR</span><span class="si">}</span><span class="s2">/&lt;lane&gt;&#34;</span> -m <span class="s2">&#34;</span><span class="si">${</span><span class="nv">CODEX_MODEL</span><span class="si">}</span><span class="s2">&#34;</span> <span class="s2">&#34;&lt;prompt&gt;&#34;</span> &gt; <span class="s2">&#34;</span><span class="si">${</span><span class="nv">LOG_DIR</span><span class="si">}</span><span class="s2">/&lt;lane&gt;.log&#34;</span> 2&gt;<span class="p">&amp;</span><span class="m">1</span> <span class="p">&amp;</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl"><span class="nb">wait</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">
</span></span><span class="line"><span class="ln">22</span><span class="cl"><span class="c1"># Phase 3: push + PRs</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">hdr <span class="s2">&#34;Phase 3: PRs to </span><span class="si">${</span><span class="nv">BASE_BRANCH</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">24</span><span class="cl">git -C <span class="s2">&#34;</span><span class="si">${</span><span class="nv">WORKTREE_DIR</span><span class="si">}</span><span class="s2">/&lt;lane&gt;&#34;</span> push -u origin <span class="s2">&#34;&lt;feature-branch&gt;&#34;</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">gh pr create --base <span class="s2">&#34;</span><span class="si">${</span><span class="nv">BASE_BRANCH</span><span class="si">}</span><span class="s2">&#34;</span> --head <span class="s2">&#34;&lt;feature-branch&gt;&#34;</span> --draft --body <span class="s2">&#34;&lt;templated body&gt;&#34;</span></span></span></code></pre></div><p>Notice what this gives you immediately: one directory per lane, one log file per lane, and a clean boundary between “make changes” and “publish changes”.</p>
<p>Now for the parts that went wrong.</p>
<h2 id="failure-1-the-shell-lied-about-what-bash-means">Failure #1: The shell lied about what “Bash” means</h2>
<p>The first failure happened before any parallelism even started. The orchestration was written with associative arrays, and the system shell rejected it with:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">declare: -A: invalid option</span></span></code></pre></div><p>This is the kind of bug that looks embarrassing until you realize it is inevitable. macOS ships an older Bash; other environments may default to <code>sh</code>; CI runners may use different interpreters. If your control-plane script can&rsquo;t build the lane-to-branch mapping reliably, your entire run becomes a dice roll.</p>
<p>The fix was not “make it work on my machine”. The fix was pinning the interpreter and failing fast (<code>set -euo pipefail</code>). Once the script ran under the interpreter it was written for, this class of failure disappeared.</p>
<h2 id="failure-2-the-sandbox-was-fine-until-it-touched-git">Failure #2: The sandbox was fine until it touched <code>.git</code></h2>
<p>The second failure was more instructive: everything looked successful until commit/push time, and then git failed when trying to write worktree metadata:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">fatal: Unable to create &#39;.git/worktrees/&lt;lane&gt;/index.lock&#39;: Operation not permitted</span></span></code></pre></div><p>The important mental model is: “can edit files” is not equivalent to “can finish delivery”. Git history mutation needs to create locks and update metadata under <code>.git/</code>. Sandboxed agents often allow workspace file edits while denying <code>.git</code> writes by design.</p>
<p>The fix is to treat permissions as architecture. In my runbook now, implementation and version-control mutation are distinct phases. I keep guardrails on while generating and editing code, and only elevate privileges for <code>commit</code>, <code>rebase</code>, <code>push</code>, and PR creation. That sounds procedural, but it is the difference between parallelism and chaos.</p>
<h2 id="failure-3-the-pr-diff-was-computed-against-the-wrong-reality">Failure #3: The PR diff was computed against the wrong reality</h2>
<p>The third failure was the “ghost diff” class: the PR contained changes that “weren&rsquo;t part of the task” even though the worktree looked clean locally. This is not a GitHub bug. It is a merge-base bug.</p>
<p>PR diff is computed from:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">merge_base(feature, base) .. feature</span></span></code></pre></div><p>If your base ref is stale when the feature branch is compared, <code>merge_base</code> resolves behind your intended base, and commits that should be “already in base” appear as if they were introduced by the feature.</p>
<p>The only reliable approach is to verify ancestry before review and rebase if needed:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git merge-base --is-ancestor origin/&lt;base-branch&gt; HEAD <span class="o">||</span> <span class="nb">echo</span> REBASE_REQUIRED
</span></span><span class="line"><span class="ln">2</span><span class="cl">git diff --name-only origin/&lt;base-branch&gt;...HEAD</span></span></code></pre></div><p>This takes seconds and saves you from burning reviewer attention on diff noise.</p>
<h2 id="what-changed-once-i-actually-read-the-codex-cli-docs">What changed once I actually read the Codex CLI docs</h2>
<p>My first attempt treated Codex like a generic shell command that prints code. The docs made the control surface explicit, and that changed how I designed the run.</p>
<p>Approval and sandbox mode became part of the plan instead of an afterthought. Configuration precedence became something I could reason about when a lane behaved differently. Non-interactive <code>codex exec</code> became the default because it is scriptable and produces logs you can archive. And built-in review flows (like <code>/review</code>) became a lane-local quality gate before humans ever see the PR.</p>
<p>I also stopped mixing two different kinds of parallelism. Worktrees are for isolating tasks across lanes. Multi-agent mode is for decomposing one task inside a lane. When you treat them as separate tools, your system stays debuggable.</p>
<h2 id="the-boring-checklist">The boring checklist</h2>
<p>At this point the process is intentionally boring, which is exactly what you want near a deadline. My checklist is short:</p>
<ul>
<li>If the lane can&rsquo;t commit/push, it doesn&rsquo;t “count” as done. Fix the permission boundary first.</li>
<li>If the PR diff scope isn&rsquo;t what you expect, stop and fix ancestry before asking for review.</li>
<li>If a lane doesn&rsquo;t have a log file, assume it didn&rsquo;t run deterministically.</li>
</ul>
<h2 id="appendix-redacted-script-skeleton">Appendix: Redacted Script Skeleton</h2>
<p>Below is a condensed, anonymized skeleton of the script I used. It preserves the mechanics (worktrees, batching, logs, PR creation) but removes identity details.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-zsh" data-lang="zsh"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="cp">#!/usr/bin/env zsh
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="nb">set</span> -euo pipefail
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="nv">BASE_BRANCH</span><span class="o">=</span><span class="s2">&#34;&lt;base-branch&gt;&#34;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="nv">WORKTREE_DIR</span><span class="o">=</span><span class="s2">&#34;.worktrees&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="nv">LOG_DIR</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">WORKTREE_DIR</span><span class="si">}</span><span class="s2">/_logs&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">mkdir -p <span class="s2">&#34;</span><span class="si">${</span><span class="nv">WORKTREE_DIR</span><span class="si">}</span><span class="s2">&#34;</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">LOG_DIR</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="nb">typeset</span> -A TASK_BRANCH TASK_TITLE TASK_PLAN TASK_LABEL
</span></span><span class="line"><span class="ln">11</span><span class="cl">TASK_BRANCH<span class="o">[</span>001<span class="o">]=</span><span class="s2">&#34;feature/lane-001&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">TASK_TITLE<span class="o">[</span>001<span class="o">]=</span><span class="s2">&#34;Lane 001: &lt;title&gt;&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">TASK_PLAN<span class="o">[</span>001<span class="o">]=</span><span class="s2">&#34;docs/plans/&lt;plan&gt;.md&#34;</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl">TASK_LABEL<span class="o">[</span>001<span class="o">]=</span><span class="s2">&#34;&lt;label&gt;&#34;</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="nv">BATCH_1</span><span class="o">=(</span><span class="m">001</span> 002<span class="o">)</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="nv">BATCH_2</span><span class="o">=(</span>003<span class="o">)</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">
</span></span><span class="line"><span class="ln">19</span><span class="cl">setup_lane<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="ln">20</span><span class="cl">  <span class="nb">local</span> <span class="nv">id</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$1</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">21</span><span class="cl">  <span class="nb">local</span> <span class="nv">branch</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">TASK_BRANCH</span><span class="p">[</span><span class="nv">$id</span><span class="p">]</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">22</span><span class="cl">  <span class="nb">local</span> <span class="nv">worktree</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">WORKTREE_DIR</span><span class="si">}</span><span class="s2">/lane-</span><span class="si">${</span><span class="nv">id</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">23</span><span class="cl">
</span></span><span class="line"><span class="ln">24</span><span class="cl">  <span class="k">if</span> <span class="o">[[</span> -d <span class="s2">&#34;</span><span class="si">${</span><span class="nv">worktree</span><span class="si">}</span><span class="s2">&#34;</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">25</span><span class="cl">    <span class="nb">echo</span> <span class="s2">&#34;Reusing </span><span class="si">${</span><span class="nv">worktree</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">26</span><span class="cl">  <span class="k">else</span>
</span></span><span class="line"><span class="ln">27</span><span class="cl">    git worktree add -b <span class="s2">&#34;</span><span class="si">${</span><span class="nv">branch</span><span class="si">}</span><span class="s2">&#34;</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">worktree</span><span class="si">}</span><span class="s2">&#34;</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">BASE_BRANCH</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">28</span><span class="cl">  <span class="k">fi</span>
</span></span><span class="line"><span class="ln">29</span><span class="cl">
</span></span><span class="line"><span class="ln">30</span><span class="cl">  <span class="o">(</span><span class="nb">cd</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">worktree</span><span class="si">}</span><span class="s2">/frontend&#34;</span> <span class="o">&amp;&amp;</span> bun install --frozen-lockfile<span class="o">)</span> <span class="p">&amp;</span>
</span></span><span class="line"><span class="ln">31</span><span class="cl">  <span class="o">(</span><span class="nb">cd</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">worktree</span><span class="si">}</span><span class="s2">/backend&#34;</span>  <span class="o">&amp;&amp;</span> uv sync<span class="o">)</span> <span class="p">&amp;</span>
</span></span><span class="line"><span class="ln">32</span><span class="cl">  <span class="nb">wait</span>
</span></span><span class="line"><span class="ln">33</span><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="ln">34</span><span class="cl">
</span></span><span class="line"><span class="ln">35</span><span class="cl">run_lane<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="ln">36</span><span class="cl">  <span class="nb">local</span> <span class="nv">id</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$1</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">37</span><span class="cl">  <span class="nb">local</span> <span class="nv">worktree</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">WORKTREE_DIR</span><span class="si">}</span><span class="s2">/lane-</span><span class="si">${</span><span class="nv">id</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">38</span><span class="cl">  <span class="nb">local</span> <span class="nv">log</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">LOG_DIR</span><span class="si">}</span><span class="s2">/lane-</span><span class="si">${</span><span class="nv">id</span><span class="si">}</span><span class="s2">.log&#34;</span>
</span></span><span class="line"><span class="ln">39</span><span class="cl">  <span class="nb">local</span> <span class="nv">prompt</span><span class="o">=</span><span class="s2">&#34;&lt;redacted prompt built from plan + conventions&gt;&#34;</span>
</span></span><span class="line"><span class="ln">40</span><span class="cl">
</span></span><span class="line"><span class="ln">41</span><span class="cl">  codex <span class="nb">exec</span> --dangerously-bypass-approvals-and-sandbox -C <span class="s2">&#34;</span><span class="si">${</span><span class="nv">worktree</span><span class="si">}</span><span class="s2">&#34;</span> <span class="s2">&#34;</span><span class="si">${</span><span class="nv">prompt</span><span class="si">}</span><span class="s2">&#34;</span> &gt; <span class="s2">&#34;</span><span class="si">${</span><span class="nv">log</span><span class="si">}</span><span class="s2">&#34;</span> 2&gt;<span class="p">&amp;</span><span class="m">1</span>
</span></span><span class="line"><span class="ln">42</span><span class="cl"><span class="o">}</span>
</span></span><span class="line"><span class="ln">43</span><span class="cl">
</span></span><span class="line"><span class="ln">44</span><span class="cl">create_pr<span class="o">()</span> <span class="o">{</span>
</span></span><span class="line"><span class="ln">45</span><span class="cl">  <span class="nb">local</span> <span class="nv">id</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$1</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">46</span><span class="cl">  <span class="nb">local</span> <span class="nv">branch</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">TASK_BRANCH</span><span class="p">[</span><span class="nv">$id</span><span class="p">]</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">47</span><span class="cl">  <span class="nb">local</span> <span class="nv">title</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">TASK_TITLE</span><span class="p">[</span><span class="nv">$id</span><span class="p">]</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">48</span><span class="cl">  <span class="nb">local</span> <span class="nv">worktree</span><span class="o">=</span><span class="s2">&#34;</span><span class="si">${</span><span class="nv">WORKTREE_DIR</span><span class="si">}</span><span class="s2">/lane-</span><span class="si">${</span><span class="nv">id</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">49</span><span class="cl">
</span></span><span class="line"><span class="ln">50</span><span class="cl">  git -C <span class="s2">&#34;</span><span class="si">${</span><span class="nv">worktree</span><span class="si">}</span><span class="s2">&#34;</span> push -u origin <span class="s2">&#34;</span><span class="si">${</span><span class="nv">branch</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">51</span><span class="cl">  gh pr create --base <span class="s2">&#34;</span><span class="si">${</span><span class="nv">BASE_BRANCH</span><span class="si">}</span><span class="s2">&#34;</span> --head <span class="s2">&#34;</span><span class="si">${</span><span class="nv">branch</span><span class="si">}</span><span class="s2">&#34;</span> --draft --title <span class="s2">&#34;</span><span class="si">${</span><span class="nv">title</span><span class="si">}</span><span class="s2">&#34;</span> --body <span class="s2">&#34;&lt;templated body&gt;&#34;</span>
</span></span><span class="line"><span class="ln">52</span><span class="cl"><span class="o">}</span></span></span></code></pre></div><h2 id="references">References</h2>
<ul>
<li>Codex docs hub: <a href="https://developers.openai.com/codex">https://developers.openai.com/codex</a></li>
<li>Codex CLI overview: <a href="https://developers.openai.com/codex/cli">https://developers.openai.com/codex/cli</a></li>
<li>Codex CLI features: <a href="https://developers.openai.com/codex/cli/features">https://developers.openai.com/codex/cli/features</a></li>
<li>Codex multi-agent docs: <a href="https://developers.openai.com/codex/multi-agent">https://developers.openai.com/codex/multi-agent</a></li>
<li>Codex security/sandbox docs: <a href="https://developers.openai.com/codex/security">https://developers.openai.com/codex/security</a></li>
<li>Codex config basics: <a href="https://developers.openai.com/codex/config-basic">https://developers.openai.com/codex/config-basic</a></li>
<li>Codex config reference: <a href="https://developers.openai.com/codex/config-reference">https://developers.openai.com/codex/config-reference</a></li>
<li>Codex CLI GitHub README: <a href="https://github.com/openai/codex/blob/main/README.md">https://github.com/openai/codex/blob/main/README.md</a></li>
<li>Ralph loop agent (Vercel Labs): <a href="https://github.com/vercel-labs/ralph-loop-agent">https://github.com/vercel-labs/ralph-loop-agent</a></li>
<li>Ralph from first principles (Geoffrey Huntley): <a href="https://www.youtube.com/watch?v=4Nna09dG_c0">https://www.youtube.com/watch?v=4Nna09dG_c0</a></li>
<li>Git worktree docs: <a href="https://git-scm.com/docs/git-worktree">https://git-scm.com/docs/git-worktree</a></li>
</ul>
]]></content:encoded>
    </item>
    <item>
      <title>Git</title>
      <link>https://KTS-o7.github.io/bear/notes/git/</link>
      <pubDate>Thu, 04 Dec 2025 00:00:00 +0530</pubDate><author>shentharkrishnatejaswi@gmail.com (Krishnatejaswi S)</author>
      <guid>https://KTS-o7.github.io/bear/notes/git/</guid>
      <description>&lt;h2 id=&#34;git&#34;&gt;Git&lt;/h2&gt;&#xA;&lt;p&gt;Before we start, here&amp;rsquo;s a link to one of the best free books on Git: &lt;a href=&#34;https://git-scm.com/book/en/v2&#34;&gt;Pro Git Book&lt;/a&gt;&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h3 id=&#34;what-is-version-control&#34;&gt;What is Version Control?&lt;/h3&gt;&#xA;&lt;p&gt;When working on a project, we often need to keep track of changes made to the code. Version control systems help us track and reconcile changes across different versions of our codebase.&lt;/p&gt;&#xA;&lt;p&gt;Think of your codebase as a tree. Each change you make can create a new branch in the tree. It&amp;rsquo;s up to you to decide if your changes are good enough to become part of the main branch. But why a tree? Because we have a single source of truth (the &lt;code&gt;main&lt;/code&gt; branch) based on which we can reconcile all changes.&lt;/p&gt;</description>
      <content:encoded><![CDATA[<h2 id="git">Git</h2>
<p>Before we start, here&rsquo;s a link to one of the best free books on Git: <a href="https://git-scm.com/book/en/v2">Pro Git Book</a></p>
<hr>
<h3 id="what-is-version-control">What is Version Control?</h3>
<p>When working on a project, we often need to keep track of changes made to the code. Version control systems help us track and reconcile changes across different versions of our codebase.</p>
<p>Think of your codebase as a tree. Each change you make can create a new branch in the tree. It&rsquo;s up to you to decide if your changes are good enough to become part of the main branch. But why a tree? Because we have a single source of truth (the <code>main</code> branch) based on which we can reconcile all changes.</p>
<p>Imagine the source of truth is a single branch called <code>main</code>. When you want to work on a new feature, you create a branch from <code>main</code>, make your changes in that branch, and once you&rsquo;re done, you can merge the branch back into <code>main</code>.</p>
<p>This approach allows us to:</p>
<ol>
<li>Work on multiple features in parallel</li>
<li>Enable multiple people to work on the same codebase simultaneously</li>
<li>Revert to previous stable states if something goes wrong</li>
</ol>
<p><a href="https://mermaid.live/edit#pako:eNp1klFvgjAQx78Kub2ia7GINovJBH3zbU8TH6pchQQoqWWZE7_7KjAjyexT737__92lvQscVILA4ahFlTofUVw69rxvNyIrd85otGj2WpSHtHGW2zUKU2uku140wOEf9nq8bHGCX5irqnGiu_1tr18XB1UUmTn12nCoXd1r_aONWm2B-oiNs-4G7chqQLrcyZxztKPKLM_5C1LpS_lI1k_JsidSSob0kYRPSfSUrAYEXPvgWQLc6BpdsCMX4hbC5eaJwaRYYAzcXhOUos5NDHF5tbZKlJ9KFX9OrepjClyK_GSjukqEwSgT9jeLe1ZjmaAOVV0a4JSwtgjwC3wD9xgbU0KCKQ1oQGaUBC6cgU-mbEymJGABmwXEY97VhZ-2LRmziT-n1GfE8zx_TnwXMMmM0ptukdp9uv4C9ee5ZA"><img src="https://mermaid.ink/img/pako:eNp1klFvgjAQx78Kub2ia7GINovJBH3zbU8TH6pchQQoqWWZE7_7KjAjyexT737__92lvQscVILA4ahFlTofUVw69rxvNyIrd85otGj2WpSHtHGW2zUKU2uku140wOEf9nq8bHGCX5irqnGiu_1tr18XB1UUmTn12nCoXd1r_aONWm2B-oiNs-4G7chqQLrcyZxztKPKLM_5C1LpS_lI1k_JsidSSob0kYRPSfSUrAYEXPvgWQLc6BpdsCMX4hbC5eaJwaRYYAzcXhOUos5NDHF5tbZKlJ9KFX9OrepjClyK_GSjukqEwSgT9jeLe1ZjmaAOVV0a4JSwtgjwC3wD9xgbU0KCKQ1oQGaUBC6cgU-mbEymJGABmwXEY97VhZ-2LRmziT-n1GfE8zx_TnwXMMmM0ptukdp9uv4C9ee5ZA?type=png" alt=""></a></p>
<h3 id="getting-started">Getting Started</h3>
<p>First, download Git from <a href="https://git-scm.com/downloads">here</a> and install it.</p>
<p>In this guide, we&rsquo;ll cover:</p>
<ol>
<li>Setting up Git credentials</li>
<li>Creating a new repository</li>
<li>Understanding the staging area and making commits</li>
<li>Working with branches</li>
<li>Merging branches</li>
<li>Working with remote repositories</li>
<li>Common Git commands and workflows</li>
</ol>
<h4 id="1-setting-up-git-credentials">1. Setting Up Git Credentials</h4>
<p>Before you start using Git, configure your name and email. These will be associated with all your commits.</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git config --global user.name <span class="s2">&#34;Your Name&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">git config --global user.email <span class="s2">&#34;your.email@example.com&#34;</span></span></span></code></pre></div><p>You can verify your configuration with:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git config --list</span></span></code></pre></div><h4 id="2-creating-a-new-repository">2. Creating a New Repository</h4>
<p>Navigate to the directory where you want to create the repository. You can either:</p>
<ul>
<li>Initialize an existing directory as a Git repository</li>
<li>Create a new directory and then initialize it</li>
</ul>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># Option 1: Initialize current directory</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">git init
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># Option 2: Create new directory and initialize</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">mkdir my-project
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="nb">cd</span> my-project
</span></span><span class="line"><span class="ln">7</span><span class="cl">git init</span></span></code></pre></div><h4 id="3-understanding-the-staging-area-and-making-commits">3. Understanding the Staging Area and Making Commits</h4>
<p>Git uses a three-stage workflow:</p>
<ol>
<li><strong>Working Directory</strong>: Your files as they exist on disk</li>
<li><strong>Staging Area</strong>: Files you&rsquo;ve marked to be included in the next commit</li>
<li><strong>Repository</strong>: Committed snapshots of your project</li>
</ol>
<p>Let&rsquo;s create a file and commit it:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># Create a new file</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;Hello, World!&#34;</span> &gt; hello.txt
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># Stage the file (add it to the staging area)</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">git add hello.txt
</span></span><span class="line"><span class="ln">6</span><span class="cl">
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="c1"># Commit the changes with a descriptive message</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">git commit -m <span class="s2">&#34;Add hello.txt file&#34;</span></span></span></code></pre></div><p><strong>Key Commands:</strong></p>
<ul>
<li><code>git status</code> - See which files are modified, staged, or untracked</li>
<li><code>git add &lt;file&gt;</code> - Stage a specific file</li>
<li><code>git add .</code> - Stage all changes in the current directory</li>
<li><code>git commit -m &quot;message&quot;</code> - Commit staged changes with a message</li>
</ul>
<h4 id="4-working-with-branches">4. Working with Branches</h4>
<p>Branches allow you to work on features, experiments, or fixes without affecting the main codebase.</p>
<p><strong>Create and switch to a new branch:</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git checkout -b feature1</span></span></code></pre></div><p>This is equivalent to:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git branch feature1      <span class="c1"># Create the branch</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">git checkout feature1    <span class="c1"># Switch to the branch</span></span></span></code></pre></div><p><strong>Modern alternative (Git 2.23+):</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git switch -c feature1   <span class="c1"># Create and switch</span></span></span></code></pre></div><p><strong>Make changes in the new branch:</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">echo</span> <span class="s2">&#34;Hello, World! in feature1&#34;</span> &gt; hello.txt</span></span></code></pre></div><p><strong>View all branches:</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git branch                <span class="c1"># List local branches</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">git branch -a            <span class="c1"># List all branches (local and remote)</span></span></span></code></pre></div><h4 id="5-committing-changes-to-a-branch">5. Committing Changes to a Branch</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git add hello.txt
</span></span><span class="line"><span class="ln">2</span><span class="cl">git commit -m <span class="s2">&#34;Update hello.txt in feature1 branch&#34;</span></span></span></code></pre></div><h4 id="6-merging-branches">6. Merging Branches</h4>
<p>Once your feature is complete, merge it back into <code>main</code>:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># Switch back to main branch</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">git checkout main
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># Merge feature1 into main</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">git merge feature1</span></span></code></pre></div><p><strong>Note:</strong> If there are no conflicts, Git will automatically create a merge commit. If conflicts occur, you&rsquo;ll need to resolve them manually.</p>
<h4 id="7-working-with-remote-repositories">7. Working with Remote Repositories</h4>
<p>Remote repositories allow you to collaborate with others and back up your code.</p>
<p><strong>Add a remote repository:</strong></p>
<p>First, create a new repository on a platform like GitHub, GitLab, or Bitbucket. Then copy the repository URL and add it as a remote:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git remote add origin &lt;remote-repository-URL&gt;</span></span></code></pre></div><p><strong>View remote repositories:</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git remote -v              <span class="c1"># List all remotes with URLs</span></span></span></code></pre></div><p><strong>Update remote URL (if needed):</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git remote set-url origin &lt;new-URL&gt;</span></span></code></pre></div><h4 id="8-pushing-changes-to-remote">8. Pushing Changes to Remote</h4>
<p>Push your local commits to the remote repository:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git push -u origin main</span></span></code></pre></div><p>The <code>-u</code> flag sets up tracking, so future pushes can be done with just <code>git push</code>.</p>
<p><strong>Push to a specific branch:</strong></p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git push origin feature1</span></span></code></pre></div><h4 id="9-pulling-changes-from-remote">9. Pulling Changes from Remote</h4>
<p><code>git pull</code> fetches changes from the remote and merges them into your current branch:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git pull origin main</span></span></code></pre></div><p><strong>Note:</strong> <code>git pull</code> is equivalent to <code>git fetch</code> followed by <code>git merge</code>.</p>
<h4 id="10-fetching-changes-from-remote">10. Fetching Changes from Remote</h4>
<p><code>git fetch</code> downloads changes from the remote without merging them:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git fetch origin</span></span></code></pre></div><p>This is useful when you want to see what changes exist on the remote before merging them. After fetching, you can review changes with:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git log origin/main..main    <span class="c1"># See commits on remote</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">git diff origin/main          <span class="c1"># See differences</span></span></span></code></pre></div><hr>
<h3 id="additional-useful-commands">Additional Useful Commands</h3>
<h4 id="viewing-history-and-changes">Viewing History and Changes</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git log                      <span class="c1"># View commit history</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">git log --oneline            <span class="c1"># Compact one-line view</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">git log --graph --oneline    <span class="c1"># Visual branch history</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">git diff                     <span class="c1"># See unstaged changes</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">git diff --staged            <span class="c1"># See staged changes</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">git show &lt;commit-hash&gt;       <span class="c1"># Show details of a specific commit</span></span></span></code></pre></div><h4 id="undoing-changes">Undoing Changes</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git restore &lt;file&gt;           <span class="c1"># Discard changes in working directory</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">git restore --staged &lt;file&gt;  <span class="c1"># Unstage a file</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">git reset HEAD~1             <span class="c1"># Undo last commit (keeps changes)</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">git reset --hard HEAD~1      <span class="c1"># Undo last commit (discards changes) - use with caution!</span></span></span></code></pre></div><h4 id="working-with-gitignore">Working with .gitignore</h4>
<p>Create a <code>.gitignore</code> file to exclude files from version control:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># Example .gitignore</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">node_modules/
</span></span><span class="line"><span class="ln">3</span><span class="cl">*.log
</span></span><span class="line"><span class="ln">4</span><span class="cl">.env
</span></span><span class="line"><span class="ln">5</span><span class="cl">.DS_Store</span></span></code></pre></div><h4 id="cloning-a-repository">Cloning a Repository</h4>
<p>To get a copy of an existing repository:</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git clone &lt;repository-URL&gt;</span></span></code></pre></div><p>This creates a new directory with the repository name and downloads all files and history.</p>
<hr>
<h3 id="common-workflows">Common Workflows</h3>
<p><strong>Typical workflow:</strong></p>
<ol>
<li><code>git pull</code> - Get latest changes</li>
<li><code>git checkout -b feature-name</code> - Create feature branch</li>
<li>Make changes and <code>git add</code> files</li>
<li><code>git commit -m &quot;message&quot;</code> - Commit changes</li>
<li><code>git push origin feature-name</code> - Push to remote</li>
<li>Create pull/merge request on platform</li>
<li>After review, merge to main</li>
<li><code>git checkout main &amp;&amp; git pull</code> - Update local main</li>
</ol>
<hr>
<h3 id="tips-and-best-practices">Tips and Best Practices</h3>
<ol>
<li><strong>Write clear commit messages</strong>: Describe what and why, not how</li>
<li><strong>Commit often</strong>: Small, logical commits are easier to review and revert</li>
<li><strong>Pull before push</strong>: Always pull latest changes before pushing</li>
<li><strong>Use branches</strong>: Keep main stable, work on features in branches</li>
<li><strong>Review before merging</strong>: Check your changes with <code>git diff</code> and <code>git status</code></li>
</ol>
]]></content:encoded>
    </item>
  </channel>
</rss>
