<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>Hodge</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://hodgeli.github.io/</id>
  <link href="https://hodgeli.github.io/" rel="alternate"/>
  <link href="https://hodgeli.github.io/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, Hodge</rights>
  <subtitle>雄关漫道真如铁，而今迈步从头越</subtitle>
  <title>Hodge's Blog</title>
  <updated>2026-09-29T09:16:53.819Z</updated>
  <entry>
    <author>
      <name>Hodge</name>
    </author>
    <category term="开发工具" scheme="https://hodgeli.github.io/categories/%E5%BC%80%E5%8F%91%E5%B7%A5%E5%85%B7/"/>
    <category term="Git" scheme="https://hodgeli.github.io/tags/Git/"/>
    <category term="工作流" scheme="https://hodgeli.github.io/tags/%E5%B7%A5%E4%BD%9C%E6%B5%81/"/>
    <category term="效率工具" scheme="https://hodgeli.github.io/tags/%E6%95%88%E7%8E%87%E5%B7%A5%E5%85%B7/"/>
    <content>
      <![CDATA[<blockquote><p><strong>原文</strong>：<a href="https://barrd.dev/article/parallel-development-without-the-headaches-using-git-worktree/">Parallel development without the headaches using Git worktree</a><br><strong>作者</strong>：Dave（barrd.dev）<br>本文为中文翻译整理，为便于对照，关键段落保留了英文原文引用。</p></blockquote><h2 id="先说结论"><a href="#先说结论" class="headerlink" title="先说结论"></a>先说结论</h2><p><code>git worktree</code> 从 <strong>v2.5</strong> 就有了，距今大约十年，但作者一直没用过。真正上手之后，它彻底改变了他的工作流：<strong>一个任务、一个分支、一个目录</strong>，同时推进多个功能、随时插入线上热修，而 <code>git stash</code> 从日常操作变成了罕见例外。</p><p>要记的命令只有五六个，学习成本很低，换来的却是几乎消失的上下文切换。</p><h2 id="一、worktree-是什么"><a href="#一、worktree-是什么" class="headerlink" title="一、worktree 是什么"></a>一、worktree 是什么</h2><p>作者在折腾一个特别棘手的项目时，发现了 Git 的 <code>worktree</code> 功能：<strong>让你同时在多个分支上工作，每个分支有自己的目录，但共享同一份底层仓库历史。</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">~/Herd/</span><br><span class="line">├── my-project/          # 主 worktree，分支 `main`</span><br><span class="line">│   └── .git/            # 主 git 目录</span><br><span class="line">├── my-project-feature/  # 链接 worktree，分支 `feature/login-form`</span><br><span class="line">└── my-project-hotfix/   # 链接 worktree，分支 `hotfix/payment-bug`</span><br></pre></td></tr></table></figure><p>上面这些目录共享同一份提交历史，都指向同一个 <code>.git</code> 对象数据库，但各自拥有独立的工作区状态。</p><p>每个目录用起来和普通 checkout 没区别 —— 改文件、提交、推送照旧，区别在于你<strong>不用再在同一个工作区里反复横跳切分支</strong>。</p><blockquote><p>Recently whilst tinkering with a particularly tricky project, I came across Git’s <code>worktree</code> feature. A tool that lets you work on multiple branches simultaneously, each in its own directory, all sharing the same underlying repository history.</p></blockquote><blockquote><p>Each directory behaves like a normal checkout, you edit files, commit and push as usual, but you avoid constantly hopping branches in a single working tree.</p></blockquote><h2 id="二、branch-和-worktree-的区别"><a href="#二、branch-和-worktree-的区别" class="headerlink" title="二、branch 和 worktree 的区别"></a>二、branch 和 worktree 的区别</h2><p>传统做法下，同时处理多个分支意味着大量的 <code>git checkout</code> 和 <code>git stash</code> —— 不断地保存现场、切换上下文，然后祈祷没弄丢什么重要的东西。很容易迷失方向，尤其是在一个线上 bug 突然打断你思路的时候。</p><p>有了 <code>git worktree</code>，你可以为任意分支（已存在的或新建的）添加一个新的工作目录，让各条工作流彼此隔离：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># 把一个已存在的分支作为 worktree 加进来</span></span><br><span class="line">git worktree add ../my-project-feature feature-branch</span><br><span class="line"></span><br><span class="line"><span class="comment"># 或者一步到位：新建分支并同时创建 worktree</span></span><br><span class="line">git worktree add -b new-feature ../my-project-new-feature</span><br></pre></td></tr></table></figure><p>这会在主项目同级创建新目录，并检出你指定的分支。之后你可以在每个目录里独立地改文件、提交、推送，完全不碰主工作目录。</p><p>此时你的目录结构大概是这样：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">my-project/              # 主 worktree，分支 `main`</span><br><span class="line">my-project-feature/      # `feature-branch` 的 worktree</span><br><span class="line">my-project-new-feature/  # `new-feature` 的 worktree</span><br></pre></td></tr></table></figure><blockquote><p>Traditionally, working on multiple branches meant a lot of <code>git checkout</code> and <code>git stash</code> constantly saving your place, switching context and hoping you didn’t lose anything important. It’s easy to get lost, especially when a production bug interrupts your flow.</p></blockquote><p><strong>一个重要限制</strong>：同一个分支不能同时被检出到多个 worktree —— 每个 worktree 必须检出一个唯一的分支。实际使用中，这条限制反而促成了 <em>“一个任务、一个分支、一个目录”</em> 的清爽映射，让你在心理上更容易保持方位感。</p><blockquote><p>One important limitation is that the same branch cannot be checked out in more than one worktree at the same time. Each worktree must have a unique branch checked out. In practice, that encourages a tidy mapping of <em>“one task, one branch, one directory”</em>, which makes it easier to stay oriented mentally.</p></blockquote><h2 id="三、实战：一边做新功能，一边救线上故障"><a href="#三、实战：一边做新功能，一边救线上故障" class="headerlink" title="三、实战：一边做新功能，一边救线上故障"></a>三、实战：一边做新功能，一边救线上故障</h2><p>一个很真实的场景：你正在开发结账功能，线上突然炸了。</p><p><strong>初始结构：</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">~/Herd/</span><br><span class="line">└── shop/           # 主 worktree，分支 `main`</span><br><span class="line">    └── .git/</span><br></pre></td></tr></table></figure><p><strong>创建功能 worktree：</strong></p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ~/Herd/shop</span><br><span class="line">git worktree add -b feature/checkout ../shop-checkout</span><br></pre></td></tr></table></figure><p><strong>新结构：</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">~/Herd/</span><br><span class="line">├── shop/           # 主 worktree，分支 `main`</span><br><span class="line">│   └── .git/</span><br><span class="line">└── shop-checkout/  # 链接 worktree，分支 `feature/checkout`</span><br></pre></td></tr></table></figure><p>你可以在 <code>shop-checkout</code> 里安心开发结账功能，同时让 <code>shop</code> 保持在 <code>main</code> 上随时应付 code review。</p><h3 id="线上-bug-来了，创建热修-worktree"><a href="#线上-bug-来了，创建热修-worktree" class="headerlink" title="线上 bug 来了，创建热修 worktree"></a>线上 bug 来了，创建热修 worktree</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ~/Herd/shop</span><br><span class="line">git worktree add -b hotfix/payment-fail ../shop-payment-hotfix</span><br></pre></td></tr></table></figure><p><strong>此时的结构：</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">~/Herd/</span><br><span class="line">├── shop/                 # 主 worktree，分支 `main`</span><br><span class="line">├── shop-checkout/        # 功能 worktree，`feature/checkout`</span><br><span class="line">└── shop-payment-hotfix/  # 热修 worktree，`hotfix/payment-fail`</span><br></pre></td></tr></table></figure><p>到这个地步，你可以同时做三件事：</p><ul><li>在 <code>shop-payment-hotfix</code> 里修复并测试线上 bug</li><li>在 <code>shop-checkout</code> 里继续迭代 <code>feature/checkout</code></li><li>让 <code>shop</code> 保持在 <code>main</code> 上空闲，用于合并和 code review</li></ul><blockquote><p>Here’s a realistic scenario, you’re working on a checkout feature when a production bug <em>appears.</em></p></blockquote><h2 id="四、如何把-worktree-的分支合并回去"><a href="#四、如何把-worktree-的分支合并回去" class="headerlink" title="四、如何把 worktree 的分支合并回去"></a>四、如何把 worktree 的分支合并回去</h2><p>从 worktree 的分支合并改动，和普通的 Git 合并没有任何区别，只是上下文更清晰了 —— 因为每个分支都住在自己的目录里。把功能分支合进 <code>main</code> 的典型流程：</p><ol><li>在功能 worktree 里完成工作并提交</li><li>切到主 worktree 目录：</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">cd</span> ../my-project &amp;&amp; git checkout main</span><br></pre></td></tr></table></figure><ol start="3"><li>合并功能分支：</li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git merge feature-branch</span><br></pre></td></tr></table></figure><ol start="4"><li>解决冲突，然后推送</li></ol><p>因为每个 worktree 只服务于一个分支，<strong>误提交到错误分支、或者被热修打断后丢失现场的概率大大降低</strong>……好吧，理论上如此。😉</p><blockquote><p>Because each worktree is dedicated to a single branch, it’s much harder to accidentally commit to the wrong branch or lose your place when a hotfix interrupts your feature work… anyway, that’s the theory. 😉</p></blockquote><h2 id="五、查看当前所有-worktree"><a href="#五、查看当前所有-worktree" class="headerlink" title="五、查看当前所有 worktree"></a>五、查看当前所有 worktree</h2><p>在开始删除或清理之前，先看看 Git 目前知道哪些 worktree 会很有帮助：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git worktree list</span><br></pre></td></tr></table></figure><p><strong>输出示例：</strong></p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">/Users/barrd/Herd/shop                 66c16256 [main]</span><br><span class="line">/Users/barrd/Herd/shop-checkout        0c8ba118 [feature/checkout]</span><br><span class="line">/Users/barrd/Herd/shop-payment-hotfix  a16e4be2 [hotfix/payment-fail]</span><br></pre></td></tr></table></figure><p>你可以在脑子里把它映射成这样：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[main]                → /home/user/Herd/shop</span><br><span class="line">[feature/checkout]    → /home/user/Herd/shop-checkout</span><br><span class="line">[hotfix/payment-fail] → /home/user/Herd/shop-payment-hotfix</span><br></pre></td></tr></table></figure><p>这样一来，哪些分支被检出、检到了哪里一目了然，也就不会去尝试复用一个已经挂在别的 worktree 上的分支了。</p><h2 id="六、如何移除-worktree"><a href="#六、如何移除-worktree" class="headerlink" title="六、如何移除 worktree"></a>六、如何移除 worktree</h2><p>一个 worktree 用完就该收拾干净。为了安全，先提交或 stash 掉所有改动，然后：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git worktree remove ../my-project-feature</span><br></pre></td></tr></table></figure><p>这条命令只对<strong>干净</strong>的 worktree 生效（没有未提交的改动或未跟踪的文件），除非你加上 <code>--force</code>。另外，它无法移除主 worktree。</p><blockquote><p><strong>Remember</strong><br>Removing a worktree only deletes the working directory, it does not delete the branch itself. Always check with <code>git status</code> in that worktree before removing to avoid losing uncommitted work.</p></blockquote><p><strong>记住</strong>：移除 worktree 只是删掉了工作目录，<strong>并不会删除分支本身</strong>。移除前务必在那个 worktree 里跑一次 <code>git status</code>，以免丢失未提交的工作。</p><h2 id="七、用-prune-清理失效条目"><a href="#七、用-prune-清理失效条目" class="headerlink" title="七、用 prune 清理失效条目"></a>七、用 prune 清理失效条目</h2><p>如果你手动删除了某个 worktree 目录，Git 仍然会在主仓库的 <code>worktrees</code> 目录下保留它的元数据。这种情况下，<code>git worktree list</code> 会把它们标记为 missing。</p><p>用这条命令清理这些失效条目：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git worktree prune</span><br></pre></td></tr></table></figure><p>如果只想清理<strong>闲置了一段时间</strong>的条目，可以加上过期时间：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git worktree prune --expire 7.days.ago</span><br></pre></td></tr></table></figure><p>而 <code>--expire now</code> 会立即移除所有失效的 worktree 元数据 —— 在本地开发环境里，如果你经常手动删掉不再需要的旧目录，这个选项相当顺手。</p><h2 id="八、结语"><a href="#八、结语" class="headerlink" title="八、结语"></a>八、结语</h2><p>这个功能从 <code>v2.5</code> 就存在了，大约十年前，而作者一直没用过……但现在它已经重塑了他的工作流，尤其是在同时应对多个功能和紧急热修的时候。它把各个要素都分隔开来，减少了上下文切换，也让 stash 变成了罕见的例外。</p><p>对于简单的、顺序推进的工作，传统分支方式依然是首选。但如果你曾经希望自己能<strong>同时出现在两个地方</strong>，那就试试 <code>git worktree</code> 吧。</p><blockquote><p>It’s been around since <code>v2.5</code>, which was ~10 years ago and I’d never used it… But it’s now transformed my workflow, especially when juggling parallel features and urgent hotfixes. It keeps all the elements compartmentalised, reduces context switching and means stashing has become a rare exception.</p></blockquote><blockquote><p>For simple, sequential work, traditional branching is still the way to go but if you ever find yourself wishing you could be in two places at once, give <code>git worktree</code> a try.</p></blockquote><blockquote><p>If you’ve any favourite workflow variations you take advantage of <em>please get in touch</em> and let me know.</p></blockquote><h2 id="命令速查"><a href="#命令速查" class="headerlink" title="命令速查"></a>命令速查</h2><table><thead><tr><th>命令</th><th>作用</th></tr></thead><tbody><tr><td><code>git worktree add &lt;路径&gt; &lt;分支&gt;</code></td><td>把已有分支检出到一个新目录</td></tr><tr><td><code>git worktree add -b &lt;新分支&gt; &lt;路径&gt;</code></td><td>新建分支并同时创建 worktree</td></tr><tr><td><code>git worktree list</code></td><td>列出所有 worktree 及其对应分支</td></tr><tr><td><code>git worktree remove &lt;路径&gt;</code></td><td>移除 worktree（仅限干净状态，<code>--force</code> 可强制）</td></tr><tr><td><code>git worktree prune</code></td><td>清理已手动删除目录留下的失效元数据</td></tr><tr><td><code>git worktree prune --expire 7.days.ago</code></td><td>只清理闲置超过指定时间的条目</td></tr></tbody></table><h2 id="关于作者"><a href="#关于作者" class="headerlink" title="关于作者"></a>关于作者</h2><p>Dave 是一位住在布里斯托的苏格兰侨民，拥有 20 多年的 Web 开发经验。喜欢弹吉他、读书、看科幻片，以及折腾各种技术。</p><h2 id="延伸阅读"><a href="#延伸阅读" class="headerlink" title="延伸阅读"></a>延伸阅读</h2><p>原文附带的参考资料与同站文章：</p><ul><li><a href="https://github.blog/open-source/git/gits-database-internals-i-packed-object-store">Git’s Database Internals</a>（github.blog）</li><li><a href="https://git-scm.com/docs/git-worktree">Git Worktree 官方文档</a>（git-scm.com）</li><li><a href="https://barrd.dev/article/git-switch-a-replacement-for-stash/">Git switch – a replacement for stash if on wrong branch</a>（Article）</li><li><a href="https://barrd.dev/article/remove-unused-php-versions-from-laravel-herd/">Remove unused PHP versions from Laravel Herd</a>（Article）</li><li><a href="https://barrd.dev/article/using-laravel-herd-whilst-keeping-valet-and-php-monitor/">Using Laravel Herd whilst keeping Valet and PHP Monitor</a>（Article）</li><li><a href="https://barrd.dev/article/starship-blazing-fast-cross-shell-prompt/">Starship, blazing fast cross shell prompt</a>（Article）</li></ul>]]>
    </content>
    <id>https://hodgeli.github.io/2026/09/29/git-worktree-parallel-development/</id>
    <link href="https://hodgeli.github.io/2026/09/29/git-worktree-parallel-development/"/>
    <published>2026-09-29T09:10:00.000Z</published>
    <summary>翻译整理自 barrd.dev：用 Git worktree 做到「一个任务、一个分支、一个目录」，同时推进多个功能并随时插入线上热修，让 git stash 变成罕见例外。</summary>
    <title>Git worktree：并行开发不再手忙脚乱</title>
    <updated>2026-09-29T09:16:53.819Z</updated>
  </entry>
  <entry>
    <author>
      <name>Hodge</name>
    </author>
    <category term="随笔" scheme="https://hodgeli.github.io/categories/%E9%9A%8F%E7%AC%94/"/>
    <category term="建站" scheme="https://hodgeli.github.io/tags/%E5%BB%BA%E7%AB%99/"/>
    <content>
      <![CDATA[<p>这是新博客的第一篇文章。</p><h2 id="为什么重建"><a href="#为什么重建" class="headerlink" title="为什么重建"></a>为什么重建</h2><p>旧的博客系统基于 Hexo + NexT 5.1.3，最后一次部署停在 2022 年 11 月。<br>这次推倒重来，换了 Butterfly 主题，并把构建完全交给 GitHub Actions ——<br>本地只需要写 Markdown 然后 push，构建和发布都在云端完成。</p><h2 id="写作方式"><a href="#写作方式" class="headerlink" title="写作方式"></a>写作方式</h2><p>在 <code>source/_posts/</code> 下新建 <code>.md</code> 文件，或者在项目根目录执行：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">npm run new -- <span class="string">&quot;文章标题&quot;</span></span><br></pre></td></tr></table></figure><p>写完后提交并推送：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">git add .</span><br><span class="line">git commit -m <span class="string">&quot;新增文章：文章标题&quot;</span></span><br><span class="line">git push</span><br></pre></td></tr></table></figure><p>推送后 GitHub Actions 会自动构建并发布，一两分钟后就能在线上看到。</p><h2 id="代码块效果"><a href="#代码块效果" class="headerlink" title="代码块效果"></a>代码块效果</h2><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">def</span> <span class="title function_">fib</span>(<span class="params">n</span>):</span><br><span class="line">    a, b = <span class="number">0</span>, <span class="number">1</span></span><br><span class="line">    <span class="keyword">for</span> _ <span class="keyword">in</span> <span class="built_in">range</span>(n):</span><br><span class="line">        a, b = b, a + b</span><br><span class="line">    <span class="keyword">return</span> a</span><br></pre></td></tr></table></figure><h2 id="待办"><a href="#待办" class="headerlink" title="待办"></a>待办</h2><ul><li><input disabled="" type="checkbox"> 替换 <code>_config.yml</code> 里的站点标题、副标题、作者等占位符</li><li><input disabled="" type="checkbox"> 配置 <code>_config.butterfly.yml</code> 里的社交链接</li><li><input disabled="" type="checkbox"> 删除这篇示例文章</li></ul>]]>
    </content>
    <id>https://hodgeli.github.io/2026/09/29/hello-world/</id>
    <link href="https://hodgeli.github.io/2026/09/29/hello-world/"/>
    <published>2026-09-29T05:30:00.000Z</published>
    <summary>新博客的第一篇文章</summary>
    <title>Hello World</title>
    <updated>2026-09-29T09:16:53.819Z</updated>
  </entry>
</feed>
