<?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>Copilot on Mixinet BlogOps</title>
    <link>https://blogops.mixinet.net/tags/copilot/</link>
    <description>Recent content in Copilot on Mixinet BlogOps</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en</language>
    <copyright>&amp;copy; 2022-2025 Sergio Talens-Oliag.
</copyright>
    <lastBuildDate>Thu, 23 Apr 2026 19:40:00 +0200</lastBuildDate><atom:link href="https://blogops.mixinet.net/tags/copilot/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Developing a Git Worktree Helper with Copilot</title>
      <link>https://blogops.mixinet.net/posts/developing_a_git_worktree_helper_with_copilot/</link>
      <pubDate>Thu, 23 Apr 2026 19:40:00 +0200</pubDate>
      
      <guid>https://blogops.mixinet.net/posts/developing_a_git_worktree_helper_with_copilot/</guid>
      <description>&lt;section id=&#34;preamble&#34; aria-label=&#34;Preamble&#34;&gt;&lt;p&gt;Over the past few weeks I’ve been developing and using a personal command-line
tool called &lt;code&gt;gwt&lt;/code&gt; (&lt;em&gt;Git Worktree&lt;/em&gt;) to manage Git repositories using worktrees.
This article explains what the tool does, how it evolved, and how I used
&lt;a href=&#34;https://github.com/features/copilot/cli/&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;GitHub Copilot CLI&lt;/a&gt; to develop it (in
fact the idea of building the script was also to test the tool).&lt;/p&gt;&lt;/section&gt;
&lt;section class=&#34;doc-section level-1&#34;&gt;&lt;h2 id=&#34;_the_problem_managing_multiple_branches&#34;&gt;The Problem: Managing Multiple Branches&lt;/h2&gt;&lt;p&gt;I was working on a project with multiple active branches, including orphans; the
regular branches are for fixes or features, while the orphans are used to keep
copies of remote documents or store processed versions of those documents.&lt;/p&gt;
&lt;p&gt;The project also uses a special orphan branch that contains the scripts and the
CI/CD configuration to store and process the external documents (it is on a
separate branch to avoid mixing its operation with the main project code).&lt;/p&gt;
&lt;p&gt;The plan is trigger a pipeline against the special branch from remote projects
to create or update the doc branch for it in our git repository, retrieving
artifacts from the remote projects to get the files and put them on an orphan
branch (initially I added new commits after each update, but I changed the
system to use force pushes and keep only one commit, as the history is not
really needed).&lt;/p&gt;
&lt;p&gt;The original documents have to be changed, so, after ingesting them, we run a
script that modifies them and adds or updates another branch with the processed
version; the contents of that branch are used by the &lt;code&gt;main&lt;/code&gt; branch build process
(there we use &lt;code&gt;git fetch&lt;/code&gt; and &lt;code&gt;git archive&lt;/code&gt; to retrieve its contents).&lt;/p&gt;
&lt;p&gt;When working on the scripts to manage the orphan branches I discovered the
&lt;a href=&#34;https://git-scm.com/docs/git-worktree&#34; target=&#34;_blank&#34; rel=&#34;noopener&#34;&gt;worktree&lt;/a&gt; feature of &lt;code&gt;git&lt;/code&gt;, a
functionality that allows me to keep multiple branches checked out in parallel
using a single &lt;code&gt;.git&lt;/code&gt; folder, removing the need to use &lt;code&gt;git switch&lt;/code&gt; and &lt;code&gt;git
stash&lt;/code&gt; when changing between branches (until now I’ve been a heavy user of those
commands).&lt;/p&gt;
&lt;p&gt;Reading about it I found that a lot of people use worktrees with the help of a
wrapper script to simplify the management. After looking at one or two posts
and the related scripts I decided to create my own using a specific directory
structure to simplify things.&lt;/p&gt;
&lt;p&gt;That’s how I started to work on the &lt;code&gt;gwt&lt;/code&gt; script; as I also wanted to test
&lt;code&gt;copilot&lt;/code&gt; I decided to build it using its help (I have a pro license at work and
wanted to play with the cli version instead of integrated into an editor, as I
didn’t want to learn a lot of new keyboard shortcuts).&lt;/p&gt;&lt;/section&gt;
&lt;section class=&#34;doc-section level-1&#34;&gt;&lt;h2 id=&#34;_the_gwt_philosophy_opinionated_and_transparent&#34;&gt;The gwt Philosophy: Opinionated and Transparent&lt;/h2&gt;&lt;p&gt;&lt;code&gt;gwt&lt;/code&gt; enforces a simple, filesystem-visible model:&lt;/p&gt;
&lt;div class=&#34;ulist&#34;&gt;&lt;ul&gt;&lt;li&gt;&lt;strong&gt;Exactly one bare repository&lt;/strong&gt; named &lt;code&gt;bare.git&lt;/code&gt; (treated as an implementation
detail)&lt;/li&gt;&lt;li&gt;&lt;strong&gt;One worktree directory per branch&lt;/strong&gt; where the directory name matches the
branch name&lt;/li&gt;&lt;li&gt;&lt;strong&gt;Single responsibility&lt;/strong&gt;: &lt;code&gt;gwt&lt;/code&gt; doesn’t try to be a general &lt;code&gt;git&lt;/code&gt; wrapper; it
only handles operations that map cleanly to this layout&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;</description>
      <content:encoded><![CDATA[<section id="preamble" aria-label="Preamble"><p>Over the past few weeks I’ve been developing and using a personal command-line
tool called <code>gwt</code> (<em>Git Worktree</em>) to manage Git repositories using worktrees.
This article explains what the tool does, how it evolved, and how I used
<a href="https://github.com/features/copilot/cli/" target="_blank" rel="noopener">GitHub Copilot CLI</a> to develop it (in
fact the idea of building the script was also to test the tool).</p></section>
<section class="doc-section level-1"><h2 id="_the_problem_managing_multiple_branches">The Problem: Managing Multiple Branches</h2><p>I was working on a project with multiple active branches, including orphans; the
regular branches are for fixes or features, while the orphans are used to keep
copies of remote documents or store processed versions of those documents.</p>
<p>The project also uses a special orphan branch that contains the scripts and the
CI/CD configuration to store and process the external documents (it is on a
separate branch to avoid mixing its operation with the main project code).</p>
<p>The plan is trigger a pipeline against the special branch from remote projects
to create or update the doc branch for it in our git repository, retrieving
artifacts from the remote projects to get the files and put them on an orphan
branch (initially I added new commits after each update, but I changed the
system to use force pushes and keep only one commit, as the history is not
really needed).</p>
<p>The original documents have to be changed, so, after ingesting them, we run a
script that modifies them and adds or updates another branch with the processed
version; the contents of that branch are used by the <code>main</code> branch build process
(there we use <code>git fetch</code> and <code>git archive</code> to retrieve its contents).</p>
<p>When working on the scripts to manage the orphan branches I discovered the
<a href="https://git-scm.com/docs/git-worktree" target="_blank" rel="noopener">worktree</a> feature of <code>git</code>, a
functionality that allows me to keep multiple branches checked out in parallel
using a single <code>.git</code> folder, removing the need to use <code>git switch</code> and <code>git
stash</code> when changing between branches (until now I’ve been a heavy user of those
commands).</p>
<p>Reading about it I found that a lot of people use worktrees with the help of a
wrapper script to simplify the management. After looking at one or two posts
and the related scripts I decided to create my own using a specific directory
structure to simplify things.</p>
<p>That’s how I started to work on the <code>gwt</code> script; as I also wanted to test
<code>copilot</code> I decided to build it using its help (I have a pro license at work and
wanted to play with the cli version instead of integrated into an editor, as I
didn’t want to learn a lot of new keyboard shortcuts).</p></section>
<section class="doc-section level-1"><h2 id="_the_gwt_philosophy_opinionated_and_transparent">The gwt Philosophy: Opinionated and Transparent</h2><p><code>gwt</code> enforces a simple, filesystem-visible model:</p>
<div class="ulist"><ul><li><strong>Exactly one bare repository</strong> named <code>bare.git</code> (treated as an implementation
detail)</li><li><strong>One worktree directory per branch</strong> where the directory name matches the
branch name</li><li><strong>Single responsibility</strong>: <code>gwt</code> doesn’t try to be a general <code>git</code> wrapper; it
only handles operations that map cleanly to this layout</li></ul></div>
<p>The repository structure looks like this:</p>
<div class="listing-block"><pre class="highlight"><code>my-repo/
+-- bare.git/           # the Git repository (internal)
+-- main/               # worktree for branch &#34;main&#34;
+-- feature/api/        # worktree for branch &#34;feature/api&#34;
+-- fix/docs/           # worktree for branch &#34;fix/docs&#34;
+-- orphan-history/     # worktree for the &#34;orphan-history&#34; branch</code></pre></div>
<p>The tool follows five core design principles:</p>
<div class="olist arabic"><ol class="arabic"><li><strong>Explicit over clever</strong>: Git commands are not hidden or reinterpreted</li><li><strong>Transparent execution</strong>: Every operation is printed before it happens</li><li><strong>Safe, preview-first operations</strong>: Destructive commands default to preview,
confirmation, then apply</li><li><strong>Shell-agnostic core</strong>: The script never changes the caller’s working
directory (shell wrappers handle that)</li><li><strong>Opinionated but minimal</strong>: Only commands that fit the layout model are
included</li></ol></div></section>
<section class="doc-section level-1"><h2 id="_core_commands">Core Commands</h2><p>The script provides these essential commands:</p>
<div class="ulist"><ul><li><code>gwt init &lt;url&gt;</code> — Clone a repository and set up the <code>gwt</code> layout</li><li><code>gwt convert &lt;dir&gt;</code> — Convert an existing Git checkout to the <code>gwt</code> layout</li><li><code>gwt add [--orphan] &lt;branch&gt; [&lt;base&gt;]</code> — Create a new worktree (optionally
orphaned)</li><li><code>gwt remove &lt;branch&gt;</code> — Remove a worktree and unregister it (asks the user to
remove the local branch too, useful when removing already merged branches)</li><li><code>gwt rename &lt;old&gt; &lt;new&gt;</code> — Rename a branch AND its worktree directory</li><li><code>gwt list</code> — List all worktrees</li><li><code>gwt default [&lt;branch&gt;]</code> — Get or set the default branch</li><li><code>gwt current</code> — Print the current worktree or branch name</li></ul></div>
<p>Except <code>init</code> and <code>convert</code> all of the commands work inside a directory
structure that follows the <code>gwt</code> layout, which looks for the <code>bare.git</code> folder to
find the root folder of the structure.</p>
<p>As I don’t want to hide which commands are really used by the wrapper, all <code>git</code>
and filesystem operations pass through a single <code>run</code> shell function that prints
each command before executing it. This gives complete visibility into what the
tool is doing.</p>
<p>Also, destructive operations (<code>remove</code>, <code>rename</code>) default to preview mode:</p>
<div class="listing-block"><pre class="highlight"><code class="language-shell" data-lang="shell">$ gwt remove feature-old --dry-run

+ git -C bare.git branch -d feature-old
+ git -C bare.git worktree remove feature-old/

Apply these changes? [y/N]:</code></pre></div>
<p>The user sees exactly what will happen, can verify it’s correct, and only then
confirm execution.</p></section>
<section class="doc-section level-1"><h2 id="_incremental_development_with_copilot">Incremental Development with Copilot</h2><p>The <code>gwt</code> script has grown from 597 lines in its original version (<code>git-wt</code>) to
1,111 lines when writing the first draft of this post.</p>
<p>This growth happened through incremental, test-driven development, with each
feature being refined based on real usage patterns.</p>
<p>What follows is a little history of the script evolution written with the help
of <code>git log</code>.</p>
<section class="doc-section level-2"><h3 id="_initial_version">Initial version</h3><p>First I wrote a design document and asked <code>copilot</code> to create the initial
version of the <code>git-wt</code> script with the original core commands.</p>
<p>I started to use the tool with a remote repostory (I made copies of the branches
in some cases to avoid missing work) and fixed bugs (trivial ones with <code>neovim</code>,
larger ones asking <code>copilot</code> to fix the issues for me, so I had less typing to
do).</p>
<aside class="admonition-block note" role="note"><h6 class="block-title label-only"><span class="title-label">Note: </span></h6><p>As I used <code>copilot</code> I noticed that when you make manual changes it is important
to tell the tool about them, otherwise it gets confused and sometimes tries to
remove manual changes.</p></aside></section>
<section class="doc-section level-2"><h3 id="_first_command_update">First command update</h3><p>One of the first commands I had to enhance was <code>rename</code>:</p>
<div class="ulist"><ul><li>as I normally use branches with <code>/</code> on their name and my tool checks out the
<em>worktrees</em> using the branch name as the path inside the <code>gwt</code> root folder
(i.e. a <code>fix/rename</code> branch creates the <code>fix</code> directory and checks the branch
inside the <code>fix/rename</code> folder) the <code>rename</code> command had to clean up the empty
parent directories</li><li>when renaming a worktree we move the folders and fix the references using the
<code>worktree repair</code> command to make things work locally, but the rename also
affects the remote branch reference, to avoid surprises the command unsets the
remote branch reference so it can be pushed again using the new name (of
course, the user is responsible of managing the old remote branch, as the
<code>gwt</code> can’t guess what it should do with it).</li></ul></div></section>
<section class="doc-section level-2"><h3 id="_integration_with_the_shell">Integration with the shell</h3><p>As I use <code>zsh</code> with the <a href="https://github.com/romkatv/powerlevel10k" target="_blank" rel="noopener">Powerlevel10k
theme</a> I asked <code>copilot</code> to help me add visual elements to the prompt when
working with <code>gwt</code> folders, something that I would have never tried without
help, as it would have required a lot of digging on my part on how to do it, as
I never looked into it.</p>
<p>The initial version of the code was on an independent file that I sourced from
my <code>.zshrc</code> file and it prints <code><i class="fa fa-tags"></i></code> on the right part of the prompt
when we are inside a <code>gwt</code> folder (note that if the folder is a worktree we see
the existing git integration text right before it, so we have the previous
behavior and we see that it is a <code>gwt</code> friendly repo) and if we are on the root
folder or the <code>bare.git</code> folder we see <code><i class="fa fa-tags"></i> gwt</code> or <code><i class="fa fa-tags"></i> bare</code>
(I added the text because there are no git promts on those folders).</p>
<p>I also asked <code>copilot</code> to create <code>zsh</code> autocompletion functions (I only use
<code>zsh</code>, so I didn’t add autocompletion for other shells). The good thing here is
that I wouldn’t have done that manually, as it would have required some reading
to get it right, but the output of <code>copilot</code> worked and I can update things
using it or manually if I need to.</p>
<p>One thing I was missing from the script was the possibility of changing the
working directory easily, so I wrote a <code>gwt</code> wrapper function for <code>zsh</code> that
intercepts commands that require shell cooperation (changing the working
directory) and delegates everything else to the core script.</p>
<p>Currently the function supports the following enhanced commands:</p>
<div class="ulist"><ul><li><code>cd [&lt;branch&gt;]</code>: change into a worktree or the default one if missing</li><li><code>convert &lt;dir&gt;</code>: convert a checkout, then cd into the initial worktree</li><li><code>add [--orphan] &lt;branch&gt; [&lt;base&gt;]</code>: create a worktree, then cd into it on success</li><li><code>rename &lt;old&gt; &lt;new&gt;</code>: rename a worktree, then cd into it if we were inside it</li></ul></div>
<p>Note that the <code>cd</code> command will not work on other shells or if the user does not
load my wrapper, but the rest will still work without the working directory
changes.</p></section>
<section class="doc-section level-2"><h3 id="_renaming_the_command">Renaming the command</h3><p>As I felt that <code>git-wt</code> was a long name I renamed the tool to <code>gwt</code>, I could
have done it by hand, but using <code>copilot</code> I didn’t have to review all files by
myself and it did it right (note that I have it configured to always ask me
before doing changes, as it sometimes tries to do something I don’t want and I
like to check its changes …​ as I have the files in git repos, I manually add
the files when I like the status and if the cli output is not clear I allow it
to apply it and check the effects with <code>git diff</code> so I can validate or revert
what was done).</p></section>
<section class="doc-section level-2"><h3 id="_the_convert_command">The <code>convert</code> command</h3><p>After playing with one repo I added the <code>convert</code> subcommand for migrating
existing checkouts, it seemed a simple task at first, but it took multiple
iterations to get it right, as I found multiple issues while testing (in fact I
did copies of the existing checkouts to be able to re-test each update, as some
of the iterations broke them).</p>
<p>The version of the function when this post was first edited had the following
comment explaining what it does:</p>
<div class="listing-block"><pre class="highlight"><code class="language-shell" data-lang="shell"># ---------------------------------------------------------------------------
# convert - convert an existing checkout into the gwt layout
# ---------------------------------------------------------------------------
#
# Must be run from the parent directory of &lt;dir&gt;.
#
# Steps:
#   1. Read branch from the checkout&#39;s HEAD
#   2. Rename &lt;dir&gt; to &lt;dir&gt;.wt.tmp (sibling, same filesystem)
#   3. Create &lt;dir&gt;/ as the new gwt root
#   4. Move &lt;dir&gt;.wt.tmp/.git to &lt;dir&gt;/bare.git; set core.bare = true
#   5. Fix fetch refspec (bare clone default maps refs directly, no remotes/)
#   6. Add a --no-checkout worktree so git wires up the metadata and
#      creates &lt;dir&gt;/&lt;branch&gt;/.git (the only file in that dir)
#   7. Move that .git file into the real working tree (&lt;dir&gt;.wt.tmp)
#   8. Remove the now-empty placeholder directory
#   9. Move the real working tree into place as &lt;dir&gt;/&lt;branch&gt;
#  10. Reset the index to HEAD so git status is clean
#      (--no-checkout leaves the index empty)
#  11. Create &lt;dir&gt;/.git -&gt; bare.git symlink so plain git commands work
#      from the root without --git-dir
#
# The .git file ends up at the same absolute path git recorded in step 5,
# so no worktree repair is needed. Working tree files are never modified.</code></pre></div>
<p>The <code>.git</code> link was added when I noticed that I could run commands that don’t
need the checked out files on the root of the <code>gwt</code> structure, which is handy
sometimes (i.e. a <code>git fetch</code> or a <code>git log</code>, that shows the log of the branch
marked as <code>default</code>).</p>
<p>After playing with commands that used the <code>bare.git</code> folder I updated the <code>init</code>
and <code>convert</code> commands to keep the origin refs, ensuring that the remote
tracking works correctly.</p></section>
<section class="doc-section level-2"><h3 id="_improving_the_add_command">Improving the <code>add</code> command</h3><p>While playing with the tool on more repos I noticed that I also had to enhance
the <code>add</code> command to better handle worktree creation, depending on my needs.</p>
<p>Right now the tool supports the following use cases:</p>
<div class="ulist"><ul><li>if the <code>branch</code> exists locally or on origin, it just checks it out.</li><li>if the <code>branch</code> does not exist, we create it using the given base branch or,
if no base is given, the current <em>worktree</em> (if we are in the root folder or
 <code>bare.git</code> the command fails).</li><li>as I needed it for my project, I added a <code>--orphan</code> option to be able to
create orphan branches directly.</li></ul></div></section>
<section class="doc-section level-2"><h3 id="_moving_to_a_single_file">Moving to a single file</h3><p>Eventually I decided to make the tool self contained; I removed the design
document (I moved the content to comments on the top of the script and details
to comments on each function definition) and added a pair of commands to print
the code to source for the <code>p10k</code> and <code>zsh</code> integration (autocompletion &amp;
functions), leaving everything in a single file.</p>
<p>Now my <code>.zshrc</code> file adds the following to source both things:</p>
<div class="listing-block"><pre class="highlight"><code class="language-shell" data-lang="shell"># After loading the p10k configuration
if type gwt &gt;/dev/null 2&gt;&amp;1; then
  source &lt;(gwt p10k)
fi
[...]
# After loading autocompletion
if type gwt &gt;/dev/null 2&gt;&amp;1; then
  source &lt;(gwt zsh)
fi</code></pre></div></section>
<section class="doc-section level-2"><h3 id="_versioning">Versioning</h3><p>As I modified the script I found interesting to use CalVer-based versioning (the
version variable has the format <code>YYYY.mm.dd-r#</code>) so I added a subcommand to show
its value or bump it using the current date and computing the right revision
number.</p></section>
<section class="doc-section level-2"><h3 id="_about_the_use_of_copilot">About the use of <code>copilot</code></h3><p>Although I’ve never been a fan of AI tools I have to admit that the <code>copilot</code>
CLI has been very useful for building the tool:</p>
<div class="ulist"><ul><li><strong>Rapid prototyping</strong>: Each commit represented a small feature or fix that I
could implement, test immediately in my actual workflow, and iterate on based
on the result</li><li><strong>Edge case handling</strong>: Rather than trying to anticipate every scenario
upfront, I could ask Copilot how to handle edge cases as they appeared in real
usage</li><li><strong>Script refinement</strong>: Questions like &#34;how do I clean up empty directories
after a rename&#34; or &#34;how do I detect if I’m inside a specific worktree&#34; were
quickly answered with working code</li><li><strong>Shell integration</strong>: The Zsh wrapper and completion system grew from simple
prototypes to sophisticated features, with each iteration informed by how I
actually used the tool</li></ul></div>
<p>For example, the <code>convert</code> command started as a simple rename operation, but
evolved to also create a <code>.git</code> symlink and intelligently handle various
migration scenarios—all because I used it repeatedly and refined the
implementation each time.</p></section></section>
<section class="doc-section level-1"><h2 id="_self_contained_and_opinionated">Self-Contained and Opinionated</h2><p><code>gwt</code> is deliberately opinionated:</p>
<div class="ulist"><ul><li><strong>Zsh &amp; Powerlevel10k Integration</strong>: The tool includes built-in Zsh shell
integration, accessed via <code>source &lt;(gwt zsh)</code> and supports adding a prompt
segment when using <code>p10k</code>, as described earlier.</li><li><strong>Directory Structure</strong>: The <code>bare.git</code> directory name is non-negotiable. This
is how <code>gwt</code> discovers the repository root from any subdirectory, and how the
tool knows whether a directory is a gwt repository. The simplicity of this
marker means the discovery mechanism is foolproof and requires no
configuration.</li><li><strong>No Configuration Files</strong>: <code>gwt</code> deliberately has no configuration. There are
no <code>.gwtrc</code> files or config directories. This makes it portable; the tool
works the same way everywhere, and repositories can be shared across systems
without synchronizing configuration.</li></ul></div></section>
<section class="doc-section level-1"><h2 id="_from_script_to_system">From Script to System</h2><p>What started as a small helper script for managing worktrees has become a
complete system:</p>
<div class="olist arabic"><ol class="arabic"><li><strong>Core script</strong> (<code>gwt</code>): 1,111 lines of pure shell, no external dependencies</li><li><strong>Shell integration</strong>: Zsh functions and completions</li><li><strong>Prompt integration</strong>: Powerlevel10k segment</li><li><strong>Documentation</strong>: Built-in help and design philosophy documentation</li></ol></div>
<p>The script is self-contained, everything needed for the tool to work is in a
single file.</p>
<p>This makes it trivial to update (just replace the script) or audit
(no hidden dependencies).</p></section>
<section class="doc-section level-1"><h2 id="_development_with_ai_support">Development with AI support</h2><p>Developing <code>gwt</code> with <code>copilot</code> taught me some things:</p>
<div class="ulist"><ul><li><strong>Incremental refinement works well for small tools</strong>: Each iteration informed
the next, resulting in a tool that handles real use cases elegantly</li><li><strong>Transparency is a feature</strong>: Making operations visible builds confidence and
is easier to debug</li><li><strong>Opinionated tools can be powerful</strong>: By constraining the problem space (one
bare repo, one worktree per branch), the solution becomes simpler and more
robust</li><li><strong>Shell integration matters</strong>: The same core commands are easier to use when
they can automatically change directories and provide completions</li><li><strong>Real-world testing is essential</strong>: I wouldn’t have discovered the need for
automatic directory cleanup or context-aware <code>cd</code> behavior without actually
using the tool daily</li></ul></div></section>
<section class="doc-section level-1"><h2 id="_what_was_next">What was next?</h2><p>The tool is stable and handles my daily workflow well, so my guess is that I
would keep using it and fixing issues if or when I found them, but I do not plan
to include additional features unless I find a use case that justifies it (i.e.
I never added support for some of the <code>worktree</code> subcommands, as it is easier to
use the <code>git</code> versions if I ever needed them).</p></section>
<section class="doc-section level-1"><h2 id="_what_really_happened">What really happened</h2><p>While editing this post I discovered that I needed to add another command to it
and fixed a bug (see below).</p>
<p>With those changes and the inclusion of a license and copyright notice (just in
case I distribute it at some point) now the script is 1,217 lines long instead
of the 1,111 it had when I started to write this entry.</p>
<section class="doc-section level-2"><h3 id="_submodule_support">Submodule Support</h3><p>When I converted this blog repository to the <code>gwt</code> format and tried to preview
the post using <code>docker compose</code>, it failed because the worktree I was on didn’t
have the Git submodule initialized.</p>
<p>My blog theme is included on the repository as a submodule, and when I used
<code>gwt</code> to check out different branches in worktrees, the submodule was not
initialized in the new worktrees.</p>
<p>This led me to add new internal function and a <code>gwt submodule</code> command to
handle submodule initialization; the internal function is called from <code>convert</code>
and <code>add</code> (when converting a repo or adding a worktree) and the public command
is useful to update the submodules on existing branches.</p></section>
<section class="doc-section level-2"><h3 id="_path_handling_with_branch_names_containing_slashes">Path Handling with Branch Names Containing Slashes</h3><p>The second discovery was a bug in how the tool handled branch names containing
slashes (e.g., <code>feature/new-api</code>, <code>docs/user-guide</code>), the worktree directories
are created with the branch name as the path, so a branch like <code>feature/new-api</code>
would create two nested folders (<code>feature</code> and <code>new-api</code> inside it).</p>
<p>However, there was a mismatch in how the <code>zsh</code> wrapper function resolved
worktree paths (initially it used shell parameter expansion, i.e.
<code>rel=&#34;${cwd#&#34;$REPO_ROOT&#34;/}&#34;</code>), versus how the core script calculated them,
causing the <code>cd</code> command to fail or navigate to the wrong location when branch
names contained slashes.</p>
<p>The fix involved ensuring consistent path resolution throughout the script and
wrapper (now it uses a function that processes the <code>git worktree list</code> output),
so that <code>gwt cd feature/new-api</code> correctly navigates to the worktree directory
regardless of path depth.</p></section></section>
<section class="doc-section level-1"><h2 id="_conclusion">Conclusion</h2><p><code>gwt</code> is a tool that solves a real problem: managing multiple Git branches
simultaneously without context-switching overhead.</p>
<p>I’m sure I’m going to keep using it for my projects, as it simplifies some
workflows, although I’ll also use <code>switch</code> and <code>stash</code> in some cases, but I like
the use of multiple worktrees in parallel.</p>
<p>In fact I converted this blog repository checkout to the <code>gwt</code> format to work on
a separate branch as it felt the right approach even if I’m the only one using
the repo now, and it helped me improve the tool, as explained before.</p>
<p>Also, it was a good example of how to use AI tools like <code>copilot</code> to develop a
simple tool and keep it evolving while using it.</p>
<p>In any case, although I find the <code>copilot</code> useful and has saved me time, I don’t
trust it to work without supervision, it worked well, but got stuck some times
and didn’t do the things as I wanted in multiple occasions.</p>
<p>I also have an additional problem now …​ I’ve been reading about it, but I
don’t really know which models to use or how the premium requests are computed
(I’ve only been playing with it since last month and I ran out of requests the
last day of the month on purpose, just to see what happened …​ it stops working
…​ ;).</p>
<p>On my work machine I’ve been using a specific user account with a <em>GitHub
Copilot Business</em> subscription and I only used the <code>Anthropic Claude Sonnet 4.6</code>
model and with my personal account I configured the <code>Anthropic Claude Haiku 4.5</code>
model, but I’ve only used that to create the initial draft of this post (I ended
up rewriting most of it manually anyway) and to review the final version (I’m
not a native speaker and it was useful for finding typos and improving the style
in some parts).</p>
<p>I guess I’ll try other models with <code>copilot</code> in the future and check other
command line tools like <a href="https://aider.chat/" target="_blank" rel="noopener">aider</a> or
<a href="https://claude.com/product/claude-code" target="_blank" rel="noopener">claude-code</a>, but probably only using
free accounts unless I get a payed account at work, as I have with <em>GitHub
Copilot</em>.</p>
<p>To be fair, what I will love to be able to do is to use local models (<code>aider</code> can
do it), but the machines I have are not powerful enough. I tried to run a simple
test and it felt really slow, but when I have the time or the need I’ll try
again, just in case.</p></section>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
