<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shunsuke Kitada</title>
    <description>The latest articles on DEV Community by Shunsuke Kitada (@shunk031).</description>
    <link>https://dev.to/shunk031</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3548138%2F0849812b-5b8a-4de9-86ef-ac720b4e5afb.jpg</url>
      <title>DEV Community: Shunsuke Kitada</title>
      <link>https://dev.to/shunk031</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shunk031"/>
    <language>en</language>
    <item>
      <title>A Coding-Agent-Friendly Environment Is Friendly to Humans Too: ghq x gwq x fzf</title>
      <dc:creator>Shunsuke Kitada</dc:creator>
      <pubDate>Fri, 16 Jan 2026 15:00:00 +0000</pubDate>
      <link>https://dev.to/shunk031/a-coding-agent-friendly-environment-is-friendly-to-humans-too-ghq-gwq-fzf-2km0</link>
      <guid>https://dev.to/shunk031/a-coding-agent-friendly-environment-is-friendly-to-humans-too-ghq-gwq-fzf-2km0</guid>
      <description>&lt;p&gt;As your number of repositories grows through &lt;code&gt;git clone&lt;/code&gt;, for both work and personal projects, it becomes harder to remember &lt;strong&gt;where&lt;/strong&gt; you cloned things and &lt;strong&gt;which directory&lt;/strong&gt; you’re currently working in. You end up wasting time on &lt;code&gt;cd&lt;/code&gt; and shell completion. On top of that, once you start creating branches for development or checking out other branches to review Pull Requests, the overhead of switching branches and managing stashes just keeps increasing. I often mess up branch switches, run into conflicts, or almost lose my changes.&lt;/p&gt;

&lt;p&gt;These problems become even more visible once you start using coding agents like &lt;strong&gt;Claude Code&lt;/strong&gt; or &lt;strong&gt;Codex&lt;/strong&gt;. The more tasks you run in parallel, the more likely things are to collide if you only have a single working directory. And of course, you want to unleash your coding agents as much as possible 😄.&lt;/p&gt;

&lt;p&gt;In this article, I’ll show how combining the following three tools can significantly improve your daily development workflow. And yes—please do use coding agents.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;a href="https://github.com/x-motemen/ghq" rel="noopener noreferrer"&gt;&lt;code&gt;ghq&lt;/code&gt;&lt;/a&gt; to standardize where repositories are cloned (so things don’t fall apart as they grow)&lt;/li&gt;
&lt;li&gt;Use &lt;a href="https://github.com/d-kuro/gwq" rel="noopener noreferrer"&gt;&lt;code&gt;gwq&lt;/code&gt;&lt;/a&gt; to make git worktree operations painless (parallel work becomes the default)&lt;/li&gt;
&lt;li&gt;Use &lt;a href="https://github.com/junegunn/fzf" rel="noopener noreferrer"&gt;&lt;code&gt;fzf&lt;/code&gt;&lt;/a&gt; to minimize directory hopping (list → fuzzy search → instant jump)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Why git worktree Works So Well with Coding Agents
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://git-scm.com/docs/git-worktree" rel="noopener noreferrer"&gt;git worktree&lt;/a&gt; allows you to have multiple working directories (worktrees) for a single repository. The official Git documentation clearly explains the distinction between the &lt;em&gt;main worktree&lt;/em&gt; and &lt;em&gt;linked worktrees&lt;/em&gt;, and recommends cleaning up unused linked worktrees with &lt;code&gt;git worktree remove&lt;/code&gt;. &lt;sup id="fnref1"&gt;1&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;The reason this works so well with coding agents is simple: &lt;strong&gt;your workspaces are isolated&lt;/strong&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Task A progresses in worktree A&lt;/li&gt;
&lt;li&gt;Task B progresses in worktree B&lt;/li&gt;
&lt;li&gt;Even if you run agents for both, they’re not fighting over the same repository&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Anthropic’s best practices also introduce workflows where multiple Claude sessions are run simultaneously using worktrees. &lt;sup id="fnref2"&gt;2&lt;/sup&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Tooling Stack Used in This Article
&lt;/h2&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;ghq&lt;/code&gt;: Standardize Where You Clone Repositories
&lt;/h3&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/x-motemen" rel="noopener noreferrer"&gt;
        x-motemen
      &lt;/a&gt; / &lt;a href="https://github.com/x-motemen/ghq" rel="noopener noreferrer"&gt;
        ghq
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Remote repository management made easy
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="adoc"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;ghq(1) &lt;span&gt;&lt;a href="https://github.com/x-motemen/ghq/actions?workflow=test" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/x-motemen/ghq/workflows/test/badge.svg?branch=master" alt="Build Status"&gt;&lt;/a&gt;&lt;/span&gt; &lt;span&gt;&lt;a href="https://codecov.io/gh/x-motemen/ghq" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4bef4d8ee84c100cf12cc18951c2981bbc4e3444008348f95c34f072988c7511/68747470733a2f2f636f6465636f762e696f2f67682f782d6d6f74656d656e2f6768712f6272616e63682f6d61737465722f67726170682f62616467652e737667" alt="Coverage"&gt;&lt;/a&gt;&lt;/span&gt;
&lt;/h1&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 id="user-content-name" class="heading-element"&gt;NAME&lt;/h2&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p&gt;ghq - Manage remote repository clones&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 id="user-content-description" class="heading-element"&gt;DESCRIPTION&lt;/h2&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;p&gt;'ghq' provides a way to organize remote repository clones, like go get does. When you clone a remote repository by ghq get, ghq makes a directory under a specific root directory (by default ~/ghq) using the remote repository URL’s host and path.&lt;/p&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre&gt;$ ghq get https://github.com/x-motemen/ghq
# Runs `git clone https://github.com/x-motemen/ghq ~/ghq/github.com/x-motemen/ghq`&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;You can also list local repositories (ghq list).&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 id="user-content-synopsis" class="heading-element"&gt;SYNOPSIS&lt;/h2&gt;

&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;pre&gt;ghq get [-u] [-p] [--shallow] [--vcs &amp;lt;vcs&amp;gt;] [--look] [--silent] [--branch] [--no-recursive] [--bare] [--partial blobless|treeless] &amp;lt;repository URL&amp;gt;|&amp;lt;host&amp;gt;/&amp;lt;user&amp;gt;/&amp;lt;project&amp;gt;|&amp;lt;user&amp;gt;/&amp;lt;project&amp;gt;|&amp;lt;project&amp;gt;
ghq list [-p] [-e] [&amp;lt;query&amp;gt;]
ghq create [--vcs &amp;lt;vcs&amp;gt;] &amp;lt;repository URL&amp;gt;|&amp;lt;host&amp;gt;/&amp;lt;user&amp;gt;/&amp;lt;project&amp;gt;|&amp;lt;user&amp;gt;/&amp;lt;project&amp;gt;|&amp;lt;project&amp;gt;
ghq rm [--dry-run] &amp;lt;repository URL&amp;gt;|&amp;lt;host&amp;gt;/&amp;lt;user&amp;gt;/&amp;lt;project&amp;gt;|&amp;lt;user&amp;gt;/&amp;lt;project&amp;gt;|&amp;lt;project&amp;gt;
ghq migrate [-y] [--dry-run] &amp;lt;local repository path&amp;gt;
ghq root [--all]&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 id="user-content-commands" class="heading-element"&gt;COMMANDS&lt;/h2&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;dl&gt;
&lt;dt&gt;get&lt;/dt&gt;
&lt;dd&gt;
&lt;p&gt;Clone a remote repository under ghq root directory (see
&lt;a href="https://github.com/x-motemen/ghq#directory-structures" rel="noopener noreferrer"&gt;DIRECTORY STRUCTURES&lt;/a&gt; below). &lt;code&gt;ghq clone&lt;/code&gt; is an alias for this command
If the repository is
already cloned to local, nothing will happen unless '-u' ('--update')
flag is…&lt;/p&gt;
&lt;/dd&gt;
&lt;/dl&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/x-motemen/ghq" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;




&lt;p&gt;&lt;code&gt;ghq&lt;/code&gt; is a CLI tool for organizing cloned repositories. Its philosophy is to place them under a common root using a structure like &lt;code&gt;host/owner/repo&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;With the &lt;code&gt;ghq list&lt;/code&gt; command, you can see all repositories you’ve cloned locally. When combined with &lt;code&gt;fzf&lt;/code&gt; (covered later), this becomes a powerful UI for jumping between repositories. The &lt;code&gt;ghq list --full-path&lt;/code&gt; command outputs full paths and is also featured in the official ghq handbook as a common pattern to pair with &lt;code&gt;fzf&lt;/code&gt;. &lt;sup id="fnref3"&gt;3&lt;/sup&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;fzf&lt;/code&gt;: Turn Any List into a “Selectable UI”
&lt;/h3&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://junegunn.github.io/fzf/" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjunegunn.github.io%2Ffzf%2Fimages%2Ffzf-color.png" height="auto" class="m-0"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://junegunn.github.io/fzf/" rel="noopener noreferrer" class="c-link"&gt;
            fzf | junegunn.choi.

          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            fzf is a general-purpose command-line fuzzy finder.
It’s an interactive filter program for any kind of list; files, command history, processes, hostnames, bookmarks, git commits, etc. With its novel “fuzzy” matching algorithm, you can quickly type in patterns with omitted characters and still get the results you want.
Is it any good? # Yes, it is. Some say it’s the next best thing since sliced internet (whatever that is). If you spend a lot of time on the terminal, fzf can really change the way you work and make you much more productive.
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjunegunn.github.io%2Ffavicon.ico"&gt;
          junegunn.github.io
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;




&lt;p&gt;&lt;code&gt;fzf&lt;/code&gt; is a fast, interactive fuzzy finder that runs in the terminal. It takes input from stdin, filters it in real time, and lets you select items interactively.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjunegunn.github.io%2Ffzf%2Fimages%2Ffzf.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fjunegunn.github.io%2Ffzf%2Fimages%2Ffzf.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;gwq&lt;/code&gt;: Manage Worktrees “the ghq Way”
&lt;/h3&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/d-kuro" rel="noopener noreferrer"&gt;
        d-kuro
      &lt;/a&gt; / &lt;a href="https://github.com/d-kuro/gwq" rel="noopener noreferrer"&gt;
        gwq
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      🌳 Git worktree manager with fuzzy finder - Work on multiple branches simultaneously, perfect for parallel AI coding workflows 🍋
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;gwq - Git Worktree Manager&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;gwq&lt;/code&gt; is a CLI tool for efficiently managing Git worktrees. Like how &lt;code&gt;ghq&lt;/code&gt; manages repository clones, &lt;code&gt;gwq&lt;/code&gt; provides intuitive operations for creating, switching, and deleting worktrees using a fuzzy finder interface.&lt;/p&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/d-kuro/gwq/./docs/assets/usage.gif"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fd-kuro%2Fgwq%2F.%2Fdocs%2Fassets%2Fusage.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Why gwq?&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Git worktrees allow you to check out multiple branches from the same repository into separate directories. This is particularly powerful when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Working on multiple features simultaneously&lt;/li&gt;
&lt;li&gt;Running parallel AI coding agents on different tasks&lt;/li&gt;
&lt;li&gt;Reviewing code while developing new features&lt;/li&gt;
&lt;li&gt;Testing changes without disrupting your main workspace&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;AI Coding Agent Workflows&lt;/h3&gt;
&lt;/div&gt;
&lt;p&gt;One of the most powerful applications of &lt;code&gt;gwq&lt;/code&gt; is enabling parallel AI coding workflows. Instead of having a single AI agent work sequentially through tasks, you can leverage multiple worktrees to have multiple AI agents work on different parts of your project simultaneously:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c"&gt;&lt;span class="pl-c"&gt;#&lt;/span&gt; Create worktrees for parallel development&lt;/span&gt;
gwq add -b feature/authentication
gwq add -b feature/data-visualization
gwq add -b bugfix/login-issue
&lt;/pre&gt;…
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/d-kuro/gwq" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;




&lt;p&gt;&lt;code&gt;gwq&lt;/code&gt; is a CLI tool for efficiently managing git worktrees. Its README describes it as:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;“Just like ghq manages clones, gwq manages worktrees.”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s designed around fuzzy-finder-driven workflows, making it easy to create, switch, and delete worktrees.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj7udreyfb897r0awsqgk.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj7udreyfb897r0awsqgk.gif"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Unifying &lt;code&gt;clone&lt;/code&gt; and &lt;code&gt;worktree&lt;/code&gt; Under the Same Root
&lt;/h2&gt;

&lt;p&gt;The key idea of this article is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;By placing both original repositories and git worktree directories under the same root (e.g. &lt;code&gt;~/ghq&lt;/code&gt;), you can target a single location with &lt;code&gt;fzf&lt;/code&gt;, making navigation lightning-fast.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Below is a concrete setup.&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup: Point Both &lt;code&gt;ghq&lt;/code&gt; and &lt;code&gt;gwq&lt;/code&gt; to &lt;code&gt;~/ghq&lt;/code&gt;
&lt;/h3&gt;

&lt;h4&gt;
  
  
  &lt;code&gt;ghq&lt;/code&gt;: Fix the Root to &lt;code&gt;~/ghq&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;Configure ghq to use &lt;code&gt;~/ghq&lt;/code&gt; as its root. ghq reads this from git config.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ghq]
  root = ~/ghq
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With this setup, running &lt;code&gt;ghq get github.com/owner/repo&lt;/code&gt; results in the following structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/ghq/
  github.com/
    owner/
      repo/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  &lt;code&gt;gwq&lt;/code&gt;: Place Worktrees Under &lt;code&gt;~/ghq&lt;/code&gt;
&lt;/h4&gt;

&lt;p&gt;gwq is configured via &lt;code&gt;~/.config/gwq/config.toml&lt;/code&gt;, where you can set &lt;code&gt;worktree.basedir&lt;/code&gt; and &lt;code&gt;naming.template&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[naming]
template = '{{.Host}}/{{.Owner}}/{{.Repository}}={{.Branch}}'

[worktree]
basedir = '~/ghq'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;gwq supports template variables such as &lt;code&gt;Host&lt;/code&gt;, &lt;code&gt;Owner&lt;/code&gt;, &lt;code&gt;Repository&lt;/code&gt;, and &lt;code&gt;Branch&lt;/code&gt;, and even allows branch name sanitization. This is clearly documented in its README.&lt;/p&gt;

&lt;p&gt;I personally use the format:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;'{{.Host}}/{{.Owner}}/{{.Repository}}={{.Branch}}'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you instead follow the gwq default and separate directories by &lt;code&gt;{{.Branch}}&lt;/code&gt;, worktrees end up nested &lt;em&gt;inside&lt;/em&gt; the ghq-cloned repository. That makes them harder to find via &lt;code&gt;fzf&lt;/code&gt;, so be careful.&lt;/p&gt;

&lt;p&gt;With the configuration above, running &lt;code&gt;gwq add feature-branch&lt;/code&gt; produces something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/ghq/
  github.com/shunk031/app                # original repo (ghq)
  github.com/shunk031/app=feature-auth   # worktree (gwq)
  github.com/shunk031/app=bugfix-login   # worktree (gwq)
  ...
  github.com/shunk031/infra              # another repo (ghq)
  github.com/shunk031/infra=refactor-tf  # worktree (gwq)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Creating a “Jump” Command: ghq + fzf
&lt;/h3&gt;

&lt;p&gt;Since &lt;code&gt;ghq list&lt;/code&gt; outputs all repositories, piping it into &lt;code&gt;fzf&lt;/code&gt; instantly gives you a navigation UI. With &lt;code&gt;ghq list --full-path&lt;/code&gt;, you can jump directly to any directory—almost instantly 🥰.&lt;/p&gt;

&lt;p&gt;Here’s the command I personally use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;ghq-path&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    ghq list &lt;span class="nt"&gt;--full-path&lt;/span&gt; | fzf
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;dev&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;local &lt;/span&gt;moveto
    &lt;span class="nv"&gt;moveto&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;ghq-path&lt;span class="si"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;moveto&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;1

    &lt;span class="c"&gt;# rename session if in tmux&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TMUX&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
        &lt;/span&gt;&lt;span class="nb"&gt;local &lt;/span&gt;repo_name
        &lt;span class="nv"&gt;repo_name&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;moveto&lt;/span&gt;&lt;span class="p"&gt;##*/&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

        tmux rename-session &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;repo_name&lt;/span&gt;&lt;span class="p"&gt;//./-&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running &lt;code&gt;dev&lt;/code&gt; shows all repositories under &lt;code&gt;ghq&lt;/code&gt; in &lt;code&gt;fzf&lt;/code&gt;. Selecting one immediately &lt;code&gt;cd&lt;/code&gt;s into it. If you’re inside a tmux session, the session name is also updated to match the repository, making terminal navigation even smoother.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary: Centralize, Select, and Run in Parallel
&lt;/h2&gt;

&lt;p&gt;In this article, we explored how combining &lt;strong&gt;ghq + gwq + fzf&lt;/strong&gt; helps you organize cloned repositories, move between them instantly, and comfortably run coding agents in parallel.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ghq&lt;/code&gt; centralizes your working directories&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;gwq&lt;/code&gt; simplifies worktree management&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;fzf&lt;/code&gt; enables fast, intuitive navigation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Together, these tools reduce confusion when juggling multiple tasks or coding agents at the same time—and significantly boost productivity. Give it a try!&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Git - git-worktree Documentation &lt;a href="https://git-scm.com/docs/git-worktree" rel="noopener noreferrer"&gt;https://git-scm.com/docs/git-worktree&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;Claude Code Best Practices \ Anthropic &lt;a href="https://www.anthropic.com/engineering/claude-code-best-practices#:~:text=c.%20Use%20git%20worktrees" rel="noopener noreferrer"&gt;https://www.anthropic.com/engineering/claude-code-best-practices#:~:text=c.%20Use%20git%20worktrees&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;ghq-handbook/ja/05-command-list.md at master · Songmu/ghq-handbook &lt;a href="https://github.com/Songmu/ghq-handbook/blob/master/ja/05-command-list.md" rel="noopener noreferrer"&gt;https://github.com/Songmu/ghq-handbook/blob/master/ja/05-command-list.md&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>ghq</category>
      <category>gwq</category>
      <category>fzf</category>
      <category>claudecode</category>
    </item>
    <item>
      <title>Testable Dotfiles Management: Building Development Environment with Chezmoi</title>
      <dc:creator>Shunsuke Kitada</dc:creator>
      <pubDate>Mon, 06 Oct 2025 12:32:48 +0000</pubDate>
      <link>https://dev.to/shunk031/testable-dotfiles-management-building-development-environment-with-chezmoi-pbn</link>
      <guid>https://dev.to/shunk031/testable-dotfiles-management-building-development-environment-with-chezmoi-pbn</guid>
      <description>&lt;p&gt;This article explains an approach to dotfiles management that emphasizes testability, using the author's dotfiles repository &lt;a href="https://github.com/shunk031/dotfiles" rel="noopener noreferrer"&gt;shunk031/dotfiles&lt;/a&gt; as a case study.&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/shunk031" rel="noopener noreferrer"&gt;
        shunk031
      &lt;/a&gt; / &lt;a href="https://github.com/shunk031/dotfiles" rel="noopener noreferrer"&gt;
        dotfiles
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      💻 My dotfiles powered by chezmoi; Primarily built with Rust-based applications (sheldon/startship/mise etc.)
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
    &lt;a rel="noopener noreferrer" href="https://github.com/shunk031/dotfiles/./.github/header.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fshunk031%2Fdotfiles%2F.%2F.github%2Fheader.png" alt="shunk031's"&gt;&lt;/a&gt;
    &lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;📂 dotfiles&lt;/h1&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;&lt;a href="https://github.com/shunk031/dotfiles/actions/workflows/remote.yaml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/shunk031/dotfiles/actions/workflows/remote.yaml/badge.svg" alt="Snippet install"&gt;&lt;/a&gt;
&lt;a href="https://github.com/shunk031/dotfiles/actions/workflows/test.yaml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/shunk031/dotfiles/actions/workflows/test.yaml/badge.svg" alt="Unit test"&gt;&lt;/a&gt;
&lt;a href="https://codecov.io/gh/shunk031/dotfiles" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/2ecc41d5a8c2fc2f48028fcb90ef72bbc52041a3e61a3eecf51523090de36700/68747470733a2f2f636f6465636f762e696f2f67682f7368756e6b3033312f646f7466696c65732f67726170682f62616467652e7376673f746f6b656e3d3456554a574b47415237" alt="codecov"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/zsh-users/zsh" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/08beec9e32578330bf8f1232a863df77b8a497c2b80d61054d2a851a1fe1a701/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f7461672f7a73682d75736572732f7a73683f636f6c6f723d32383835463126646973706c61795f6e616d653d72656c65617365266c6162656c3d7a7368266c6f676f3d7a7368266c6f676f436f6c6f723d32383835463126736f72743d73656d766572" alt="zsh-users/zsh"&gt;&lt;/a&gt;
&lt;a href="https://github.com/tmux/tmux" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9db3e71c5f1d35969bd975036e24a69140e526fdb8f4cbccd1c480bbd7a28d7f/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f7461672f746d75782f746d75783f636f6c6f723d31424239314626646973706c61795f6e616d653d72656c65617365266c6162656c3d746d7578266c6f676f3d746d7578266c6f676f436f6c6f723d31424239314626736f72743d73656d766572" alt="tmux/tmux"&gt;&lt;/a&gt;
&lt;a href="https://github.com/rossmacarthur/sheldon" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0b2c4d6bb65fd6a2ce32a300602c4e15aca91b48b5024a0bdc31d8e10728d7bf/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f7461672f726f73736d61636172746875722f7368656c646f6e3f636f6c6f723d32383264336626646973706c61795f6e616d653d72656c65617365266c6162656c3d2546302539462539412538302532307368656c646f6e26736f72743d73656d766572" alt="rossmacarthur/sheldon"&gt;&lt;/a&gt;
&lt;a href="https://github.com/starship/starship" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3c2cec3b70e687c723b8f8a7939d1a1825d9b0861d32dc69c6d7d9eaf2d941a7/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f7461672f73746172736869702f73746172736869703f636f6c6f723d44443042373826646973706c61795f6e616d653d72656c65617365266c6162656c3d7374617273686970266c6f676f3d7374617273686970266c6f676f436f6c6f723d44443042373826736f72743d73656d766572" alt="starship/starship"&gt;&lt;/a&gt;
&lt;a href="https://github.com/jdx/mise" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4084aed0303c37931f0f7316bfc03ab7b80bbd54792f19921088bd1f4e091531/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f7461672f6a64782f6d6973653f636f6c6f723d30306163633126646973706c61795f6e616d653d72656c65617365266c6162656c3d6d697365266c6f676f3d676e6f6d657465726d696e616c266c6f676f436f6c6f723d30306163633126736f72743d73656d766572" alt="jdx/mise"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/anthropics/claude-code" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/394f7fcb412eabdb75d9aacc2af0652dfe008496a08d3f90d05dc3da203a0dec/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f7461672f616e7468726f706963732f636c617564652d636f64653f636f6c6f723d44393737353726646973706c61795f6e616d653d72656c65617365266c6162656c3d636c617564652d636f6465266c6f676f3d636c61756465266c6f676f436f6c6f723d44393737353726736f72743d73656d766572" alt="anthropics/claude-code"&gt;&lt;/a&gt;
&lt;a href="https://github.com/openai/codex" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f9f9cb151ac45feeb2b0242f1f5415e8adbd28c81caf99efb9ddef85dc007cd7/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f7461672f6f70656e61692f636f6465783f636f6c6f723d30303831413526646973706c61795f6e616d653d72656c65617365266c6162656c3d636f646578266c6f676f3d6f70656e616967796d266c6f676f436f6c6f723d30303831413526736f72743d73656d766572" alt="openai/codex"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🗿 Overview&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;This &lt;a href="https://github.com/shunk031/dotfiles" rel="noopener noreferrer"&gt;dotfiles&lt;/a&gt; repository is managed with &lt;a href="https://www.chezmoi.io/" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;chezmoi🏠&lt;/code&gt;&lt;/a&gt;, a great dotfiles manager
The setup scripts are aimed for &lt;a href="https://www.apple.com/jp/macos" rel="nofollow noopener noreferrer"&gt;MacOS&lt;/a&gt;, &lt;a href="https://ubuntu.com/desktop" rel="nofollow noopener noreferrer"&gt;Ubuntu Desktop&lt;/a&gt;, and &lt;a href="https://ubuntu.com/server" rel="nofollow noopener noreferrer"&gt;Ubuntu Server&lt;/a&gt;. The first two (MacOS/Ubuntu Desktop) include settings for &lt;code&gt;client&lt;/code&gt; machines and the latter one (Ubuntu Server) for &lt;code&gt;server&lt;/code&gt; machines.&lt;/p&gt;
&lt;p&gt;The actual dotfiles exist under the &lt;a href="https://github.com/shunk031/dotfiles/tree/master/home" rel="noopener noreferrer"&gt;&lt;code&gt;home&lt;/code&gt;&lt;/a&gt; directory specified in the &lt;a href="https://github.com/shunk031/dotfiles/blob/master/.chezmoiroot" rel="noopener noreferrer"&gt;&lt;code&gt;.chezmoiroot&lt;/code&gt;&lt;/a&gt;.
See &lt;a href="https://www.chezmoi.io/reference/special-files-and-directories/chezmoiroot/" rel="nofollow noopener noreferrer"&gt;.chezmoiroot - chezmoi&lt;/a&gt; more detail on the setting.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;📥 Setup&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;To set up the dotfiles run the appropriate snippet in the terminal.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;💻 &lt;code&gt;MacOS&lt;/code&gt; &lt;a href="https://github.com/shunk031/dotfiles/actions/workflows/macos.yaml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/shunk031/dotfiles/actions/workflows/macos.yaml/badge.svg" alt="MacOS"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Configuration snippet of the Apple Silicon MacOS environment for client macnine:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c1"&gt;bash -c "$(curl -fsLS http://shunk031.me/dotfiles/setup.sh)"&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/shunk031/dotfiles/.github/screenshot-macos-client.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fshunk031%2Fdotfiles%2F.github%2Fscreenshot-macos-client.png" alt="Screenshot of setup on MacOS Client machine"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;🖥️ &lt;code&gt;Ubuntu&lt;/code&gt; &lt;a href="https://github.com/shunk031/dotfiles/actions/workflows/ubuntu.yaml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/shunk031/dotfiles/actions/workflows/ubuntu.yaml/badge.svg" alt="Ubuntu"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Configuration snippet of the Ubuntu environment for both client and server machine:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c1"&gt;bash -c "$(wget -qO - http://shunk031.me/dotfiles/setup.sh)"&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/shunk031/dotfiles/.github/screenshot-ubuntu-server.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fshunk031%2Fdotfiles%2F.github%2Fscreenshot-ubuntu-server.png" alt="Screenshot of setup on Ubuntu Server machine"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Minimal setup&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;The following is a minimal setup command to install chezmoi and my dotfiles from the github repository on a new empty machine:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;sh -c…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/shunk031/dotfiles" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;




&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Dotfiles and Dotfiles Repositories
&lt;/h3&gt;

&lt;p&gt;The &lt;em&gt;&lt;code&gt;dotfiles&lt;/code&gt;&lt;/em&gt; refer to configuration files that start with a "&lt;code&gt;.&lt;/code&gt;" (dot) such as &lt;code&gt;.bashrc&lt;/code&gt;, &lt;code&gt;.vimrc&lt;/code&gt;, and &lt;code&gt;.gitconfig&lt;/code&gt;. In recent years, &lt;a href="https://awesomeopensource.com/projects/dotfiles" rel="noopener noreferrer"&gt;dotfiles repositories&lt;/a&gt; that manage these files using Git repositories have become widely popular among developers.&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/webpro" rel="noopener noreferrer"&gt;
        webpro
      &lt;/a&gt; / &lt;a href="https://github.com/webpro/awesome-dotfiles" rel="noopener noreferrer"&gt;
        awesome-dotfiles
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A curated list of dotfiles resources.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Awesome Dotfiles &lt;a href="https://awesome.re" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9d49598b873146ec650fb3f275e8a532c765dabb1f61d5afa25be41e79891aa7/68747470733a2f2f617765736f6d652e72652f62616467652e737667" alt="Awesome"&gt;&lt;/a&gt;
&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;A curated list of dotfiles resources. Inspired by the &lt;a href="https://github.com/sindresorhus/awesome" rel="noopener noreferrer"&gt;awesome&lt;/a&gt; list thing. Note that some articles or tools may look
old or old-fashioned, but this usually means they're battle-tested and mature (like dotfiles themselves). Feel free to
propose new articles, projects or tools!&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Articles&lt;/h2&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Introductions&lt;/h3&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.webpro.nl/articles/getting-started-with-dotfiles" rel="nofollow noopener noreferrer"&gt;Getting started with dotfiles&lt;/a&gt;, &lt;a href="https://github.com/webpro" rel="noopener noreferrer"&gt;Lars Kappert&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://driesvints.com/blog/getting-started-with-dotfiles/" rel="nofollow noopener noreferrer"&gt;Getting started with dotfiles&lt;/a&gt;, &lt;a href="https://github.com/driesvints" rel="noopener noreferrer"&gt;Dries Vints&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.webpro.nl/articles/managing-your-dotfiles" rel="nofollow noopener noreferrer"&gt;Managing your dotfiles&lt;/a&gt;, &lt;a href="https://github.com/webpro" rel="noopener noreferrer"&gt;Lars Kappert&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://zachholman.com/2010/08/dotfiles-are-meant-to-be-forked/" rel="nofollow noopener noreferrer"&gt;Dotfiles Are Meant to Be Forked&lt;/a&gt;, &lt;a href="https://zachholman.com" rel="nofollow noopener noreferrer"&gt;Zach Holman&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://wynnnetherland.com/journal/dotfiles-discovery/" rel="nofollow noopener noreferrer"&gt;Dotfile discovery&lt;/a&gt;, &lt;a href="https://wynnnetherland.com" rel="nofollow noopener noreferrer"&gt;Wynn Netherland&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://jogendra.dev/i-do-dotfiles" rel="nofollow noopener noreferrer"&gt;I do Dotfiles!&lt;/a&gt;, &lt;a href="https://jogendra.dev" rel="nofollow noopener noreferrer"&gt;Jogendra&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Tutorials&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://mattstauffer.com/blog/setting-up-a-new-os-x-development-machine-part-3-dotfiles-rc-files-and-ssh-config/" rel="nofollow noopener noreferrer"&gt;Setting up a new (OS X) development machine: Part 3 - Dotfiles and custom SSH config&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://code.tutsplus.com/setting-up-a-mac-dev-machine-from-zero-to-hero-with-dotfiles--net-35449t" rel="nofollow noopener noreferrer"&gt;Setting Up a Mac Dev Machine From Zero to Hero With Dotfiles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://blog.smalleycreative.com/tutorials/using-git-and-github-to-manage-your-dotfiles/" rel="nofollow noopener noreferrer"&gt;Using Git and GitHub to manage your dotfiles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://chr4.org/blog/2014/09/10/conf-dot-d-like-directories-for-zsh-slash-bash-dotfiles/" rel="nofollow noopener noreferrer"&gt;conf.d like directories for zsh/bash dotfiles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.anishathalye.com/2014/08/03/managing-your-dotfiles/" rel="nofollow noopener noreferrer"&gt;Managing your dotfiles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.atlassian.com/git/tutorials/dotfiles" rel="nofollow noopener noreferrer"&gt;The best way to store your dotfiles: A bare Git repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://mitxela.com/projects/dotfiles_management" rel="nofollow noopener noreferrer"&gt;Dotfiles Management&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Shell startup&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://blog.flowblok.id.au/2013-02/shell-startup-scripts.html" rel="nofollow noopener noreferrer"&gt;Shell startup scripts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/webpro/awesome-dotfiles" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;




&lt;p&gt;The &lt;em&gt;&lt;code&gt;dotfiles repositories&lt;/code&gt;&lt;/em&gt; often function not just as configuration file management tools, but as automated development environment setup tools that include configuration files, installation scripts, and setup scripts. This enables quick and consistent setup on new machines and environments.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Problem of Untested Scripts
&lt;/h3&gt;

&lt;p&gt;Most setup and installation scripts included in dotfiles repositories are not tested for proper functionality (which is painful). As a result, various problems can occur when setting up in new environments. Script errors, installation failures of some tools due to dependency issues, and script malfunctions due to OS updates may go unnoticed until actually executed. It's extremely stressful when you get a new computer or environment and excitedly start the setup process, only to have errors occur midway through, preventing the environment setup from completing.&lt;/p&gt;

&lt;p&gt;This lack of quality assurance results in what should be automated environment construction consuming a lot of time on manual problem-solving and debugging.&lt;/p&gt;

&lt;h3&gt;
  
  
  My Repository's Approach: Testable Configuration
&lt;/h3&gt;

&lt;p&gt;To solve the above problems, my dotfiles repository builds an architecture that emphasizes testability. Setup scripts are managed as independent files to enable individual testing, quality is ensured through automated testing with &lt;a href="https://github.com/bats-core/bats-core" rel="noopener noreferrer"&gt;Bats&lt;/a&gt;, and continuous testing and code coverage measurement are performed in macOS and Ubuntu environments using GitHub Actions.&lt;/p&gt;

&lt;p&gt;For managing dotfiles, I've adopted &lt;a href="https://www.chezmoi.io/" rel="noopener noreferrer"&gt;chezmoi&lt;/a&gt;. chezmoi is a modern dotfiles management tool with high popularity on GitHub (&lt;a href="https://github.com/twpayne/chezmoi/stargazers" rel="noopener noreferrer"&gt;10,000+⭐️&lt;/a&gt;). Written in Go as a single, dependency-free binary, chezmoi is easy to install even on a brand-new, clean environment.&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/twpayne" rel="noopener noreferrer"&gt;
        twpayne
      &lt;/a&gt; / &lt;a href="https://github.com/twpayne/chezmoi" rel="noopener noreferrer"&gt;
        chezmoi
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Manage your dotfiles across multiple diverse machines, securely.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;
&lt;a rel="noopener noreferrer" href="https://github.com/twpayne/chezmoi/assets/images/logo-144px.svg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Ftwpayne%2Fchezmoi%2Fassets%2Fimages%2Flogo-144px.svg" alt="chezmoi logo"&gt;&lt;/a&gt; chezmoi&lt;/h1&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/twpayne/chezmoi/releases" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/388be90560d1d6c2b0408d429cb7bfc4abf836a7e109340af310f6406ad5eb3f/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f72656c656173652f74777061796e652f6368657a6d6f692e737667" alt="GitHub Release"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Manage your dotfiles across multiple diverse machines, securely.&lt;/p&gt;
&lt;p&gt;chezmoi's documentation is at &lt;a href="https://chezmoi.io/" rel="nofollow noopener noreferrer"&gt;chezmoi.io&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you're contributing to chezmoi, then please read the &lt;a href="https://www.chezmoi.io/developer-guide/" rel="nofollow noopener noreferrer"&gt;developer guide&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Contributors&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/717996d6be7ecdb6694e2b61bfb56d4f7f93b042c8bebd465b386a669746b333/68747470733a2f2f636f6e747269622e726f636b732f696d6167653f7265706f3d74777061796e652f6368657a6d6f69266d61783d31303234"&gt;&lt;img src="https://camo.githubusercontent.com/717996d6be7ecdb6694e2b61bfb56d4f7f93b042c8bebd465b386a669746b333/68747470733a2f2f636f6e747269622e726f636b732f696d6167653f7265706f3d74777061796e652f6368657a6d6f69266d61783d31303234" alt="Contributor avatars"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;License&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;MIT&lt;/p&gt;
&lt;/div&gt;



&lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/twpayne/chezmoi" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;





&lt;p&gt;Environment setup on a new machine can be executed with the following very simple one-liner using chezmoi's official installer&lt;sup id="fnref1"&gt;1&lt;/sup&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;curl &lt;span class="nt"&gt;-fsLS&lt;/span&gt; get.chezmoi.io&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; init &lt;span class="nt"&gt;--apply&lt;/span&gt; &lt;span class="nv"&gt;$GITHUB_USERNAME&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Environment-specific settings can be dynamically generated using chezmoi's template functionality based on Go's &lt;code&gt;text/template&lt;/code&gt; as follows.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;                           &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;Can&lt;/span&gt; &lt;span class="n"&gt;be&lt;/span&gt; &lt;span class="n"&gt;dynamically&lt;/span&gt; &lt;span class="n"&gt;specified&lt;/span&gt; &lt;span class="n"&gt;via&lt;/span&gt; &lt;span class="n"&gt;template&lt;/span&gt; &lt;span class="n"&gt;functionality&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"{{.name}}"&lt;/span&gt;           &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;User&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
    &lt;span class="n"&gt;email&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"{{.email}}"&lt;/span&gt;         &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;Email&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;eq&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;chezmoi&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt; &lt;span class="s"&gt;"darwin"&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt; &lt;span class="n"&gt;macOS&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;specific&lt;/span&gt; &lt;span class="n"&gt;settings&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;credential&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="n"&gt;helper&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;osxkeychain&lt;/span&gt;
&lt;span class="p"&gt;{{&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt;&lt;span class="p"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;a href="https://www.chezmoi.io/user-guide/templating/" rel="noopener noreferrer"&gt;https://www.chezmoi.io/user-guide/templating/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In this way, we aim to achieve reliable dotfiles management by ensuring script quality through testable configuration and flexibly managing environment-specific settings through chezmoi's template functionality.&lt;/p&gt;
&lt;h2&gt;
  
  
  Architecture Design: Testable Configuration
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Repository Structure
&lt;/h3&gt;

&lt;p&gt;My repository is broadly divided into three directories: &lt;a href="https://github.com/shunk031/dotfiles/tree/master/home" rel="noopener noreferrer"&gt;&lt;code&gt;home/&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://github.com/shunk031/dotfiles/tree/master/install" rel="noopener noreferrer"&gt;&lt;code&gt;install/&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://github.com/shunk031/dotfiles/tree/master/tests" rel="noopener noreferrer"&gt;&lt;code&gt;tests/&lt;/code&gt;&lt;/a&gt;, managing dotfiles, environment setup scripts, and automated tests independently.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── ...
│
├── home/                   # dotfiles under chezmoi management
│   ├── dot_bashrc          # - deployed as ~/.bashrc
│   ├── dot_vimrc           # - deployed as ~/.vimrc
│   ├── dot_config/         # - deployed as ~/.config/
│   └── .chezmoi.yaml.tmpl  # - chezmoi configuration file
│
├── install/                # setup scripts (testable)
│   ├── common/             # - common installation scripts
│   ├── macos/              # - macOS-specific scripts
│   └── ubuntu/             # - Ubuntu-specific scripts
│
├── tests/                  # automated tests with Bats
│   ├── install/            # - tests for installation scripts
│   └── files/              # - tests for files after chezmoi deployment
│
└── ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h3&gt;
  
  
  Design Philosophy
&lt;/h3&gt;

&lt;p&gt;The core of this architecture lies in "separation of concerns" and "maximizing testability". Traditional dotfiles repositories mix configuration files and setup scripts, making testing difficult, but this configuration clearly separates each element.&lt;/p&gt;
&lt;h4&gt;
  
  
  The &lt;code&gt;install/&lt;/code&gt; directory: Easy Unit Testing Through Script Separation
&lt;/h4&gt;

&lt;p&gt;By making setup scripts independent from chezmoi, individual testing becomes possible.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/shunk031/dotfiles/blob/master/install/common/rust.sh" rel="noopener noreferrer"&gt;&lt;code&gt;install/common/rust.sh&lt;/code&gt;&lt;/a&gt;: Installation of tools used commonly across machines (e.g., Rust)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shunk031/dotfiles/blob/master/install/macos/common/brew.sh" rel="noopener noreferrer"&gt;&lt;code&gt;install/macos/common/brew.sh&lt;/code&gt;&lt;/a&gt;: Installation of Homebrew used commonly on macOS&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shunk031/dotfiles/blob/master/install/ubuntu/common/misc.sh" rel="noopener noreferrer"&gt;&lt;code&gt;install/ubuntu/common/misc.sh&lt;/code&gt;&lt;/a&gt;: Installation of tools used commonly on Ubuntu (e.g., curl, jq)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Platform-specific configuration separates OS-specific logic, allowing each to be tested independently. Each script follows the single responsibility principle, handling only the installation of specific tools or packages.&lt;/p&gt;
&lt;h4&gt;
  
  
  The &lt;code&gt;home/&lt;/code&gt; directory: chezmoi Templates and dotfiles
&lt;/h4&gt;

&lt;p&gt;These are the actual dotfiles under chezmoi management. They follow chezmoi's unique file naming conventions &lt;a href="https://www.chezmoi.io/user-guide/frequently-asked-questions/design/#why-does-chezmoi-use-weird-filenames" rel="noopener noreferrer"&gt;(&lt;code&gt;dot_&lt;/code&gt; prefix etc.)&lt;/a&gt; and utilize template functionality. This repository specifies &lt;code&gt;home&lt;/code&gt; as the source directory using the &lt;a href="https://www.chezmoi.io/user-guide/advanced/customize-your-source-directory/" rel="noopener noreferrer"&gt;.chezmoiroot&lt;/a&gt; file&lt;sup id="fnref2"&gt;2&lt;/sup&gt;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/shunk031/dotfiles/blob/master/home/dot_zshrc" rel="noopener noreferrer"&gt;&lt;code&gt;home/dot_zshrc&lt;/code&gt;&lt;/a&gt;: deployed as &lt;code&gt;~/.zshrc&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shunk031/dotfiles/blob/master/home/dot_config/git/config.tmpl" rel="noopener noreferrer"&gt;&lt;code&gt;home/dot_config/git/config.tmpl&lt;/code&gt;&lt;/a&gt;: chezmoi template deployed as &lt;code&gt;~/.config/git/config&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shunk031/dotfiles/blob/master/home/.chezmoi.yaml.tmpl" rel="noopener noreferrer"&gt;&lt;code&gt;home/.chezmoi.yaml.tmpl&lt;/code&gt;&lt;/a&gt;: chezmoi configuration file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It's independent from the scripts in the &lt;code&gt;install/&lt;/code&gt; directory, separating configuration file placement and environment construction.&lt;/p&gt;
&lt;h4&gt;
  
  
  The &lt;code&gt;tests/&lt;/code&gt; directory: Automated Testing with Bats
&lt;/h4&gt;

&lt;p&gt;I use Bash Automated Testing System (Bats) to test scripts in the &lt;code&gt;install/&lt;/code&gt; directory. The test directories and files are configured to be consistent with the script.&lt;/p&gt;

&lt;p&gt;{{&amp;lt; blogcard url="&lt;a href="https://github.com/bats-core/bats-core" rel="noopener noreferrer"&gt;https://github.com/bats-core/bats-core&lt;/a&gt;" &amp;gt;}}&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://github.com/shunk031/dotfiles/blob/master/tests/install/common/rust.bats" rel="noopener noreferrer"&gt;&lt;code&gt;tests/install/common/rust.bats&lt;/code&gt;&lt;/a&gt;: Tests for Rust installation script&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shunk031/dotfiles/blob/master/tests/install/macos/common/brew.bats" rel="noopener noreferrer"&gt;&lt;code&gt;tests/install/macos/common/brew.bats&lt;/code&gt;&lt;/a&gt;: Tests for Homebrew installation script&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/shunk031/dotfiles/blob/master/tests/files/common.bats" rel="noopener noreferrer"&gt;&lt;code&gt;tests/files/common.bats&lt;/code&gt;&lt;/a&gt;: Verification of file existence after chezmoi deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Each test file verifies the script's behavior and confirms that expected results (package installation, configuration file generation, etc.) are obtained.&lt;/p&gt;
&lt;h2&gt;
  
  
  Test &amp;amp; CI/CD Strategy
&lt;/h2&gt;

&lt;p&gt;This repository adopts a test strategy based on the fundamental policy of "continuous verification". We can verify that scripts in the &lt;code&gt;install/&lt;/code&gt; directory work correctly in various environments and discover problems in advance to prevent failures during actual environment construction.&lt;/p&gt;
&lt;h3&gt;
  
  
  Unit Test Implementation with Bats
&lt;/h3&gt;

&lt;p&gt;My repository adopts &lt;a href="https://github.com/bats-core/bats-core" rel="noopener noreferrer"&gt;Bash Automated Testing System (Bats)&lt;/a&gt; to verify the behavior of each installation script. Bats is a testing framework specifically for shell scripts that allows writing tests with simple syntax.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bats&lt;/span&gt;

@test &lt;span class="s2"&gt;"brew installation script exists"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"install/macos/common/brew.sh"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

@test &lt;span class="s2"&gt;"brew installation script is executable"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt; &lt;span class="s2"&gt;"install/macos/common/brew.sh"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

@test &lt;span class="s2"&gt;"brew installation script runs without errors"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  run bash &lt;span class="nb"&gt;install&lt;/span&gt;/macos/common/brew.sh
  &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

@test &lt;span class="s2"&gt;"brew command is available after installation"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  run &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; brew
  &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Each test progressively verifies script existence, executable permissions, actual execution, and expected results (command availability, etc.).&lt;/p&gt;
&lt;h3&gt;
  
  
  Comprehensive Verification with GitHub Actions
&lt;/h3&gt;

&lt;p&gt;My repository uses GitHub Actions for multi-stage verification. In addition to unit tests, the workflow regularly executes actual end-to-end setup to achieve comprehensive quality assurance.&lt;/p&gt;
&lt;h4&gt;
  
  
  Unit Test Execution
&lt;/h4&gt;

&lt;p&gt;My repository runs automated tests in macOS and Ubuntu environments to detect platform-specific issues early.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Test&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;push&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;pull_request&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;test&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ubuntu-latest&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;macos-latest&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.os }}&lt;/span&gt;

    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;actions/checkout@v4&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Install Bats&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;if [[ "${{ matrix.os }}" == "ubuntu-latest" ]]; then&lt;/span&gt;
            &lt;span class="s"&gt;sudo apt-get update &amp;amp;&amp;amp; sudo apt-get install -y bats&lt;/span&gt;
          &lt;span class="s"&gt;else&lt;/span&gt;
            &lt;span class="s"&gt;brew install bats-core&lt;/span&gt;
          &lt;span class="s"&gt;fi&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Run tests&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;bats tests/install/&lt;/span&gt;

      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Upload coverage reports&lt;/span&gt;
        &lt;span class="na"&gt;uses&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;codecov/codecov-action@v3&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Regular Execution of Actual Setup
&lt;/h4&gt;

&lt;p&gt;More importantly, we should verify in environments identical to the actual user experience. This repository's workflow automatically executes the setup process using &lt;a href="https://github.com/shunk031/dotfiles/blob/master/setup.sh" rel="noopener noreferrer"&gt;&lt;code&gt;setup.sh&lt;/code&gt;&lt;/a&gt; on macOS and Ubuntu runners every Friday. This script wraps the chezmoi environment construction one-liner mentioned earlier.&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Snippet install&lt;/span&gt;
&lt;span class="na"&gt;on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;schedule&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;cron&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;*&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;5"&lt;/span&gt;  &lt;span class="c1"&gt;# Every Friday&lt;/span&gt;

&lt;span class="na"&gt;jobs&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;strategy&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;matrix&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;ubuntu-latest&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;macos-14&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="na"&gt;system&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="nv"&gt;client&lt;/span&gt;&lt;span class="pi"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;server&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;
        &lt;span class="na"&gt;exclude&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
          &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;os&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;macos-14&lt;/span&gt;
            &lt;span class="na"&gt;system&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;server&lt;/span&gt;

    &lt;span class="na"&gt;runs-on&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;${{ matrix.os }}&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Setup dotfiles with snippet&lt;/span&gt;
        &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
          &lt;span class="s"&gt;if [ "${OS}" == "macos-14" ]; then&lt;/span&gt;
            &lt;span class="s"&gt;bash -c "$(curl -fsLS https://shunk031.me/dotfiles/setup.sh)"&lt;/span&gt;
          &lt;span class="s"&gt;elif [ "${OS}" == "ubuntu-latest" ]; then&lt;/span&gt;
            &lt;span class="s"&gt;bash -c "$(wget -qO - https://shunk031.me/dotfiles/setup.sh)"&lt;/span&gt;
          &lt;span class="s"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;This regular execution continuously monitors the impact of external dependency changes, OS updates, and package manager changes on environment construction, ensuring reliability when actual users execute the setup.&lt;/p&gt;
&lt;h4&gt;
  
  
  Code Coverage Measurement and Codecov Integration
&lt;/h4&gt;

&lt;p&gt;My repository measures shell script code coverage using &lt;a href="https://github.com/SimonKagstrom/kcov" rel="noopener noreferrer"&gt;kcov&lt;/a&gt; and visualizes it with &lt;a href="https://codecov.io/" rel="noopener noreferrer"&gt;Codecov&lt;/a&gt;. This helps identify untested code paths and improve testing. Actual measurement uses &lt;a href="https://github.com/shunk031/dotfiles/blob/master/scripts/run_unit_test.sh" rel="noopener noreferrer"&gt;&lt;code&gt;scripts/run_unit_test.sh&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/SimonKagstrom" rel="noopener noreferrer"&gt;
        SimonKagstrom
      &lt;/a&gt; / &lt;a href="https://github.com/SimonKagstrom/kcov" rel="noopener noreferrer"&gt;
        kcov
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      Code coverage tool for compiled programs, Python and Bash which uses debugging information to collect and report data without special compilation options
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;p&gt;&lt;a href="https://coveralls.io/r/SimonKagstrom/kcov?branch=master" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/665a5fd66f60afe375dc334025665e53398acc25bde2a7d6f00ec25e42a3cd20/68747470733a2f2f696d672e736869656c64732e696f2f636f766572616c6c732f53696d6f6e4b61677374726f6d2f6b636f762e737667" alt="Coveralls coverage status"&gt;&lt;/a&gt;
&lt;a href="https://codecov.io/gh/SimonKagstrom/kcov" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/042d7ae5ec157fe26e60907d63771489afd4aeec105492776911bcf51723f51f/68747470733a2f2f636f6465636f762e696f2f67682f53696d6f6e4b61677374726f6d2f6b636f762f6272616e63682f6d61737465722f67726170682f62616467652e737667" alt="Codecov coverage status"&gt;&lt;/a&gt;
&lt;a href="https://scan.coverity.com/projects/2844" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/21491526ff627aeaedd5895b8a5286d119f600dba6b05117e886ad4f9c38a4de/68747470733a2f2f7363616e2e636f7665726974792e636f6d2f70726f6a656374732f323834342f62616467652e737667" alt="Coverity Scan Build Status"&gt;&lt;/a&gt;
&lt;a rel="noopener noreferrer nofollow" href="https://camo.githubusercontent.com/5711277466bc74a460aa6829f6a4b54ad66352094d24f7cc32c996e001a9dadb/68747470733a2f2f696d672e736869656c64732e696f2f646f636b65722f70756c6c732f6b636f762f6b636f762e737667"&gt;&lt;img src="https://camo.githubusercontent.com/5711277466bc74a460aa6829f6a4b54ad66352094d24f7cc32c996e001a9dadb/68747470733a2f2f696d672e736869656c64732e696f2f646f636b65722f70756c6c732f6b636f762f6b636f762e737667" alt="Docker Pulls"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://www.paypal.com/cgi-bin/webscr?cmd=_donations&amp;amp;business=simon.kagstrom%40gmail%2ecom&amp;amp;lc=US&amp;amp;item_name=Simon%20Kagstrom&amp;amp;item_number=kcov&amp;amp;currency_code=USD&amp;amp;bn=PP%2dDonationsBF%3abtn_donate_LG%2egif%3aNonHosted" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/b48a7f9ca978349b83c641e4901221d7e84374bcb3300a43f739835cf930e802/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f70617970616c2d646f6e6174652d626c75652e737667" alt="PayPal Donate"&gt;&lt;/a&gt; &lt;a href="https://github.com/SimonKagstrom/kcov/" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3173cb07a971fd3e14d403c39bfbd9088f065de348a98adbcdea66c99f84ee71/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f646f776e6c6f6164732f61746f6d2f61746f6d2f746f74616c2e737667" alt="Github All Releases"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;&lt;em&gt;kcov&lt;/em&gt;&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;Kcov is a FreeBSD/Linux/Mac OS code coverage tester for compiled languages, Python
and Bash.  Kcov was originally a fork of &lt;a href="https://bcov.sourceforge.net/" rel="nofollow noopener noreferrer"&gt;Bcov&lt;/a&gt;, but has
since evolved to support a large feature set in addition to that of Bcov.&lt;/p&gt;
&lt;p&gt;Kcov, like Bcov, uses DWARF debugging information for compiled programs to
make it possible to collect coverage information without special compiler
switches.&lt;/p&gt;
&lt;p&gt;For a video introduction, &lt;a href="https://www.youtube.com/watch?v=1QMHbp5LUKg" rel="nofollow noopener noreferrer"&gt;look at this presentation from SwedenCPP&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;Installing&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Refer to the &lt;a href="https://github.com/SimonKagstrom/kcov/INSTALL.md" rel="noopener noreferrer"&gt;INSTALL&lt;/a&gt; file for build instructions, or use our official Docker image (&lt;code&gt;kcov/kcov&lt;/code&gt;):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://hub.docker.com/r/kcov/kcov/" rel="nofollow noopener noreferrer"&gt;kcov/kcov&lt;/a&gt; for releases since v31.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Docker images and usage is explained more &lt;a href="https://github.com/SimonKagstrom/kcov/doc/docker.md" rel="noopener noreferrer"&gt;in the docker page&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;How to use it&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;Basic usage is straight-forward:&lt;/p&gt;
&lt;div class="highlight highlight-source-shell notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;kcov /path/to/outdir executable [args &lt;span class="pl-k"&gt;for&lt;/span&gt; the executable]&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;em&gt;/path/to/outdir&lt;/em&gt; will contain lcov-style HTML output generated
continuously while the application runs. Kcov will also write cobertura-
compatible XML output and generic JSON coverage information and can easily
be…&lt;/p&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/SimonKagstrom/kcov" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;




&lt;p&gt;&lt;a href="https://about.codecov.io/" rel="noopener noreferrer"&gt;https://about.codecov.io/&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Example of coverage measurement&lt;/span&gt;
kcov &lt;span class="nt"&gt;--clean&lt;/span&gt; &lt;span class="nt"&gt;--include-path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;install&lt;/span&gt;/macos/common/ &lt;span class="se"&gt;\&lt;/span&gt;
  coverage/ &lt;span class="se"&gt;\&lt;/span&gt;
  bats tests/install/macos/common/brew.bats
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Coverage reports are automatically commented on Pull Requests using &lt;a href="https://github.com/codecov/codecov-action" rel="noopener noreferrer"&gt;codecov/codecov-action&lt;/a&gt;, allowing immediate understanding of the impact of changes.&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/codecov" rel="noopener noreferrer"&gt;
        codecov
      &lt;/a&gt; / &lt;a href="https://github.com/codecov/codecov-action" rel="noopener noreferrer"&gt;
        codecov-action
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      GitHub Action that uploads coverage to Codecov ☂️ 
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Codecov GitHub Action&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/marketplace/actions/codecov" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/29d09c8d548da2da334100706b060b3fb4448e1f907a5bedf4a4c69646343995/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f4d61726b6574706c6163652d76352d756e646566696e65642e7376673f6c6f676f3d676974687562266c6f676f436f6c6f723d7768697465267374796c653d666c6174" alt="GitHub Marketplace"&gt;&lt;/a&gt;
&lt;a href="https://app.fossa.com/projects/git%2Bgithub.com%2Fcodecov%2Fcodecov-action?ref=badge_shield" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/912bedef51339e2094e30f555039dbf2e7f2fb567f40bd0b607d1a9cf586a9c9/68747470733a2f2f6170702e666f7373612e636f6d2f6170692f70726f6a656374732f6769742532426769746875622e636f6d253246636f6465636f76253246636f6465636f762d616374696f6e2e7376673f747970653d736869656c64" alt="FOSSA Status"&gt;&lt;/a&gt;
&lt;a href="https://github.com/codecov/codecov-action/actions/workflows/main.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/codecov/codecov-action/actions/workflows/main.yml/badge.svg" alt="Workflow for Codecov Action"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Easily upload coverage reports to Codecov from GitHub Actions&lt;/h3&gt;
&lt;/div&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;v6 Release&lt;/h2&gt;
&lt;/div&gt;
&lt;p&gt;&lt;code&gt;v6&lt;/code&gt; of the Codecov GitHub Action support node24&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;v5 Release&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;&lt;code&gt;v5&lt;/code&gt; of the Codecov GitHub Action will use the &lt;a href="https://github.com/codecov/wrapper" rel="noopener noreferrer"&gt;Codecov Wrapper&lt;/a&gt; to encapsulate the &lt;a href="https://github.com/codecov/codecov-cli" rel="noopener noreferrer"&gt;CLI&lt;/a&gt;. This will help ensure that the Action gets updates quicker.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Migration Guide&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;v5&lt;/code&gt; release also coincides with the opt-out feature for tokens for public repositories. In the &lt;code&gt;Global Upload Token&lt;/code&gt; section of the settings page of an organization in codecov.io, you can set the ability for Codecov to receive a coverage reports from any source. This will allow contributors or other members of a repository to upload without needing access to the Codecov token. For more details see &lt;a href="https://docs.codecov.com/docs/codecov-tokens#uploading-without-a-token" rel="nofollow noopener noreferrer"&gt;how to upload without a token&lt;/a&gt;.&lt;/p&gt;
&lt;div class="markdown-alert markdown-alert-warning"&gt;
&lt;p class="markdown-alert-title"&gt;Warning&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The following arguments have been changed&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;file&lt;/code&gt; (this has been deprecated in favor of &lt;code&gt;files&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;plugin&lt;/code&gt; (this has been deprecated in favor…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/codecov/codecov-action" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;




&lt;h4&gt;
  
  
  Performance Measurement and Benchmark Automation
&lt;/h4&gt;

&lt;p&gt;To continuously monitor shell startup performance after dotfiles application and detect the impact of configuration changes early, I've automated benchmark measurement in the workflow of GitHub Actions.&lt;/p&gt;

&lt;p&gt;This implementation references the following article using &lt;a href="https://github.com/benchmark-action/github-action-benchmark" rel="noopener noreferrer"&gt;benchmark-action/github-action-benchmark&lt;/a&gt;. The GitHub Actions workflow measures both initial shell startup time and average startup time (measured 10 times) to quantify the impact of dotfiles configuration on shell startup.&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/benchmark-action" rel="noopener noreferrer"&gt;
        benchmark-action
      &lt;/a&gt; / &lt;a href="https://github.com/benchmark-action/github-action-benchmark" rel="noopener noreferrer"&gt;
        github-action-benchmark
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      GitHub Action for continuous benchmarking to keep performance
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;GitHub Action for Continuous Benchmarking&lt;/h1&gt;
&lt;/div&gt;
&lt;p&gt;&lt;a href="https://github.com/marketplace/actions/continuous-benchmark" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3bb6862a3ab150eca160d9a57b80d311db912cbeef34e3bb70831dc8133788fe/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f72656c656173652f62656e63686d61726b2d616374696f6e2f6769746875622d616374696f6e2d62656e63686d61726b2e737667" alt="Action Marketplace"&gt;&lt;/a&gt;
&lt;a href="https://github.com/benchmark-action/github-action-benchmark/actions?query=workflow%3ACI" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/benchmark-action/github-action-benchmark/actions/workflows/ci.yml/badge.svg" alt="Build Status"&gt;&lt;/a&gt;
&lt;a href="https://app.codecov.io/gh/benchmark-action/github-action-benchmark" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/fe3005a5644da7e278fd92e1d644061baa54ecf6c6a5cb31156d73775b6a0b3c/68747470733a2f2f636f6465636f762e696f2f67682f62656e63686d61726b2d616374696f6e2f6769746875622d616374696f6e2d62656e63686d61726b2f6272616e63682f6d61737465722f67726170682f62616467652e737667" alt="codecov"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/benchmark-action/github-action-benchmark" rel="noopener noreferrer"&gt;This repository&lt;/a&gt; provides a &lt;a href="https://github.com/features/actions" rel="noopener noreferrer"&gt;GitHub Action&lt;/a&gt; for continuous benchmarking
If your project has some benchmark suites, this action collects data from the benchmark outputs
and monitor the results on GitHub Actions workflow.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This action can store collected benchmark results in &lt;a href="https://pages.github.com/" rel="noopener noreferrer"&gt;GitHub pages&lt;/a&gt; branch and provide
a chart view. Benchmark results are visualized on the GitHub pages of your project.&lt;/li&gt;
&lt;li&gt;This action can detect possible performance regressions by comparing benchmark results. When
benchmark results get worse than previous exceeding the specified threshold, it can raise an alert
via commit comment or workflow failure.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This action currently supports the following tools:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://doc.rust-lang.org/cargo/commands/cargo-bench.html" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;cargo bench&lt;/code&gt;&lt;/a&gt; for Rust projects&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;go test -bench&lt;/code&gt; for Go projects&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://benchmarkjs.com/" rel="nofollow noopener noreferrer"&gt;benchmark.js&lt;/a&gt; for JavaScript/TypeScript projects&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pypi.org/project/pytest-benchmark/" rel="nofollow noopener noreferrer"&gt;pytest-benchmark&lt;/a&gt; for Python projects with &lt;a href="https://pypi.org/project/pytest/" rel="nofollow noopener noreferrer"&gt;pytest&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/google/benchmark" rel="noopener noreferrer"&gt;Google Benchmark Framework&lt;/a&gt; for C++ projects&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/catchorg/Catch2" rel="noopener noreferrer"&gt;Catch2&lt;/a&gt; for C++ projects&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/JuliaCI/BaseBenchmarks.jl" rel="noopener noreferrer"&gt;BenchmarkTools.jl&lt;/a&gt; for Julia packages&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://benchmarkdotnet.org" rel="nofollow noopener noreferrer"&gt;Benchmark.Net&lt;/a&gt; for .Net projects&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/Roblox/luau/tree/master/bench" rel="noopener noreferrer"&gt;benchmarkluau&lt;/a&gt; for Luau projects&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://openjdk.java.net/projects/code-tools/jmh/" rel="nofollow noopener noreferrer"&gt;JMH&lt;/a&gt; for Java…&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/benchmark-action/github-action-benchmark" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;




&lt;p&gt;Measurement results are published on &lt;a href="https://shunk031.me/my-dotfiles-benchmarks/" rel="noopener noreferrer"&gt;GitHub Pages&lt;/a&gt;, achieving continuous performance monitoring. We can numerically confirm the impact of adding new plugins or configurations on shell startup time, preventing performance degradation before it occurs.&lt;/p&gt;

&lt;p&gt;{{&amp;lt; blogcard url="&lt;a href="https://shunk031.me/my-dotfiles-benchmarks/" rel="noopener noreferrer"&gt;https://shunk031.me/my-dotfiles-benchmarks/&lt;/a&gt;" &amp;gt;}}&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation Details and Operational Flow
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Structure and Implementation Examples of Setup Scripts
&lt;/h3&gt;

&lt;p&gt;Scripts in the &lt;code&gt;install/&lt;/code&gt; directory are designed following the single responsibility principle. Each script handles only the installation and configuration of specific tools, creating an independently testable structure.&lt;/p&gt;

&lt;p&gt;As a basic script structure, OS-specific processing is separated into different files and implemented as platform-specific scripts. All installation scripts follow the following common pattern. For shell script writing practices, &lt;a href="https://betterdev.blog/minimal-safe-bash-script-template/" rel="noopener noreferrer"&gt;Minimal safe Bash script template&lt;/a&gt; is helpful.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://betterdev.blog/minimal-safe-bash-script-template/" rel="noopener noreferrer"&gt;https://betterdev.blog/minimal-safe-bash-script-template/&lt;/a&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;#!/usr/bin/env bash&lt;/span&gt;
&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-Eeuo&lt;/span&gt; pipefail

&lt;span class="c"&gt;# Debug mode setting&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;DOTFILES_DEBUG&lt;/span&gt;&lt;span class="k"&gt;:-}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;&lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;-x&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="c"&gt;# Tool-specific functions&lt;/span&gt;
&lt;span class="k"&gt;function &lt;/span&gt;is_tool_exists&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="nb"&gt;command&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; tool_name &amp;amp;&amp;gt;/dev/null
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;install_tool&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt; is_tool_exists&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then&lt;/span&gt;
        &lt;span class="c"&gt;# Platform-specific installation process&lt;/span&gt;
        &lt;span class="c"&gt;# macOS: brew install tool_name&lt;/span&gt;
        &lt;span class="c"&gt;# Ubuntu: sudo apt-get install -y tool_name&lt;/span&gt;
    &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;# Main process&lt;/span&gt;
&lt;span class="k"&gt;function &lt;/span&gt;main&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
    install_tool
    &lt;span class="c"&gt;# Execute additional configuration process if needed&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;BASH_SOURCE&lt;/span&gt;&lt;span class="p"&gt;[0]&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;0&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;]]&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;then
    &lt;/span&gt;main
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The conditional statement &lt;code&gt;if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then&lt;/code&gt; executes the &lt;code&gt;main&lt;/code&gt; function only when the script is directly executed. When a script is loaded from another file using the &lt;code&gt;source&lt;/code&gt; command (e.g., when calling functions from test files), only function definitions are loaded and &lt;code&gt;main&lt;/code&gt; is not executed&lt;sup id="fnref3"&gt;3&lt;/sup&gt;. This allows the same script to be used both for "execution" and "library" purposes, greatly improving testability.&lt;/p&gt;

&lt;p&gt;For example, Homebrew installation is separated into &lt;code&gt;install/macos/common/brew.sh&lt;/code&gt;, and chezmoi Ubuntu installation is in &lt;code&gt;install/ubuntu/common/chezmoi.sh&lt;/code&gt;. This structure achieves platform optimization and testability.&lt;/p&gt;
&lt;h3&gt;
  
  
  Development and Maintenance Flow
&lt;/h3&gt;
&lt;h4&gt;
  
  
  New Application Addition Procedure
&lt;/h4&gt;

&lt;p&gt;(1). Create installation script&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create install/macos/common/new_tool.sh&lt;/span&gt;
&lt;span class="c"&gt;# Implement following the basic structure above&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;(2). Create test file&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Create tests/install/macos/common/new_tool.bats&lt;/span&gt;
@test &lt;span class="s2"&gt;"new_tool installation script exists"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nt"&gt;-f&lt;/span&gt; &lt;span class="s2"&gt;"install/macos/common/new_tool.sh"&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

@test &lt;span class="s2"&gt;"new_tool can be installed"&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  run bash &lt;span class="nb"&gt;install&lt;/span&gt;/macos/common/new_tool.sh
  &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$status&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-eq&lt;/span&gt; 0 &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;(3). Run local tests&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bats tests/install/macos/common/new_tool.bats
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h4&gt;
  
  
  Test-Driven Development Process
&lt;/h4&gt;

&lt;p&gt;Development always proceeds test-first.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create test cases: First write expected behavior as tests&lt;/li&gt;
&lt;li&gt;Minimal implementation: Implement minimal script that passes tests&lt;/li&gt;
&lt;li&gt;Refactoring: Improve code while maintaining behavior&lt;/li&gt;
&lt;li&gt;Integration testing: Verify operation in CI environment&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This operational flow allows continuous improvement of dotfiles while maintaining quality and maintainability. Each change is necessarily covered by tests and verified in the CI pipeline, minimizing the risk of problems occurring in actual environments.&lt;/p&gt;
&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This article explained the approach of "testable dotfiles management" combining chezmoi and test-driven development. We presented a comprehensive solution to the fundamental problem that traditional dotfiles repositories face: "not knowing if setup scripts work correctly until execution". Specifically, this was an approach combining unit testing with Bats, continuous verification with GitHub Actions, and regular execution of actual end-to-end setup. Please consider incorporating testability into your own dotfiles management to achieve reliable development environment construction.&lt;/p&gt;

&lt;p&gt;

&lt;/p&gt;
&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/shunk031" rel="noopener noreferrer"&gt;
        shunk031
      &lt;/a&gt; / &lt;a href="https://github.com/shunk031/dotfiles" rel="noopener noreferrer"&gt;
        dotfiles
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      💻 My dotfiles powered by chezmoi; Primarily built with Rust-based applications (sheldon/startship/mise etc.)
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;
&lt;div&gt;
    &lt;a rel="noopener noreferrer" href="https://github.com/shunk031/dotfiles/./.github/header.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fshunk031%2Fdotfiles%2F.%2F.github%2Fheader.png" alt="shunk031's"&gt;&lt;/a&gt;
    &lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;📂 dotfiles&lt;/h1&gt;
&lt;/div&gt;


&lt;/div&gt;

&lt;div&gt;
&lt;p&gt;&lt;a href="https://github.com/shunk031/dotfiles/actions/workflows/remote.yaml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/shunk031/dotfiles/actions/workflows/remote.yaml/badge.svg" alt="Snippet install"&gt;&lt;/a&gt;
&lt;a href="https://github.com/shunk031/dotfiles/actions/workflows/test.yaml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/shunk031/dotfiles/actions/workflows/test.yaml/badge.svg" alt="Unit test"&gt;&lt;/a&gt;
&lt;a href="https://codecov.io/gh/shunk031/dotfiles" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/2ecc41d5a8c2fc2f48028fcb90ef72bbc52041a3e61a3eecf51523090de36700/68747470733a2f2f636f6465636f762e696f2f67682f7368756e6b3033312f646f7466696c65732f67726170682f62616467652e7376673f746f6b656e3d3456554a574b47415237" alt="codecov"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/zsh-users/zsh" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/08beec9e32578330bf8f1232a863df77b8a497c2b80d61054d2a851a1fe1a701/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f7461672f7a73682d75736572732f7a73683f636f6c6f723d32383835463126646973706c61795f6e616d653d72656c65617365266c6162656c3d7a7368266c6f676f3d7a7368266c6f676f436f6c6f723d32383835463126736f72743d73656d766572" alt="zsh-users/zsh"&gt;&lt;/a&gt;
&lt;a href="https://github.com/tmux/tmux" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/9db3e71c5f1d35969bd975036e24a69140e526fdb8f4cbccd1c480bbd7a28d7f/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f7461672f746d75782f746d75783f636f6c6f723d31424239314626646973706c61795f6e616d653d72656c65617365266c6162656c3d746d7578266c6f676f3d746d7578266c6f676f436f6c6f723d31424239314626736f72743d73656d766572" alt="tmux/tmux"&gt;&lt;/a&gt;
&lt;a href="https://github.com/rossmacarthur/sheldon" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/0b2c4d6bb65fd6a2ce32a300602c4e15aca91b48b5024a0bdc31d8e10728d7bf/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f7461672f726f73736d61636172746875722f7368656c646f6e3f636f6c6f723d32383264336626646973706c61795f6e616d653d72656c65617365266c6162656c3d2546302539462539412538302532307368656c646f6e26736f72743d73656d766572" alt="rossmacarthur/sheldon"&gt;&lt;/a&gt;
&lt;a href="https://github.com/starship/starship" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/3c2cec3b70e687c723b8f8a7939d1a1825d9b0861d32dc69c6d7d9eaf2d941a7/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f7461672f73746172736869702f73746172736869703f636f6c6f723d44443042373826646973706c61795f6e616d653d72656c65617365266c6162656c3d7374617273686970266c6f676f3d7374617273686970266c6f676f436f6c6f723d44443042373826736f72743d73656d766572" alt="starship/starship"&gt;&lt;/a&gt;
&lt;a href="https://github.com/jdx/mise" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4084aed0303c37931f0f7316bfc03ab7b80bbd54792f19921088bd1f4e091531/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f7461672f6a64782f6d6973653f636f6c6f723d30306163633126646973706c61795f6e616d653d72656c65617365266c6162656c3d6d697365266c6f676f3d676e6f6d657465726d696e616c266c6f676f436f6c6f723d30306163633126736f72743d73656d766572" alt="jdx/mise"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/anthropics/claude-code" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/394f7fcb412eabdb75d9aacc2af0652dfe008496a08d3f90d05dc3da203a0dec/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f7461672f616e7468726f706963732f636c617564652d636f64653f636f6c6f723d44393737353726646973706c61795f6e616d653d72656c65617365266c6162656c3d636c617564652d636f6465266c6f676f3d636c61756465266c6f676f436f6c6f723d44393737353726736f72743d73656d766572" alt="anthropics/claude-code"&gt;&lt;/a&gt;
&lt;a href="https://github.com/openai/codex" rel="noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/f9f9cb151ac45feeb2b0242f1f5415e8adbd28c81caf99efb9ddef85dc007cd7/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f762f7461672f6f70656e61692f636f6465783f636f6c6f723d30303831413526646973706c61795f6e616d653d72656c65617365266c6162656c3d636f646578266c6f676f3d6f70656e616967796d266c6f676f436f6c6f723d30303831413526736f72743d73656d766572" alt="openai/codex"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;

&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;🗿 Overview&lt;/h2&gt;
&lt;/div&gt;

&lt;p&gt;This &lt;a href="https://github.com/shunk031/dotfiles" rel="noopener noreferrer"&gt;dotfiles&lt;/a&gt; repository is managed with &lt;a href="https://www.chezmoi.io/" rel="nofollow noopener noreferrer"&gt;&lt;code&gt;chezmoi🏠&lt;/code&gt;&lt;/a&gt;, a great dotfiles manager
The setup scripts are aimed for &lt;a href="https://www.apple.com/jp/macos" rel="nofollow noopener noreferrer"&gt;MacOS&lt;/a&gt;, &lt;a href="https://ubuntu.com/desktop" rel="nofollow noopener noreferrer"&gt;Ubuntu Desktop&lt;/a&gt;, and &lt;a href="https://ubuntu.com/server" rel="nofollow noopener noreferrer"&gt;Ubuntu Server&lt;/a&gt;. The first two (MacOS/Ubuntu Desktop) include settings for &lt;code&gt;client&lt;/code&gt; machines and the latter one (Ubuntu Server) for &lt;code&gt;server&lt;/code&gt; machines.&lt;/p&gt;
&lt;p&gt;The actual dotfiles exist under the &lt;a href="https://github.com/shunk031/dotfiles/tree/master/home" rel="noopener noreferrer"&gt;&lt;code&gt;home&lt;/code&gt;&lt;/a&gt; directory specified in the &lt;a href="https://github.com/shunk031/dotfiles/blob/master/.chezmoiroot" rel="noopener noreferrer"&gt;&lt;code&gt;.chezmoiroot&lt;/code&gt;&lt;/a&gt;.
See &lt;a href="https://www.chezmoi.io/reference/special-files-and-directories/chezmoiroot/" rel="nofollow noopener noreferrer"&gt;.chezmoiroot - chezmoi&lt;/a&gt; more detail on the setting.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h2 class="heading-element"&gt;📥 Setup&lt;/h2&gt;

&lt;/div&gt;
&lt;p&gt;To set up the dotfiles run the appropriate snippet in the terminal.&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;💻 &lt;code&gt;MacOS&lt;/code&gt; &lt;a href="https://github.com/shunk031/dotfiles/actions/workflows/macos.yaml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/shunk031/dotfiles/actions/workflows/macos.yaml/badge.svg" alt="MacOS"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Configuration snippet of the Apple Silicon MacOS environment for client macnine:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c1"&gt;bash -c "$(curl -fsLS http://shunk031.me/dotfiles/setup.sh)"&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/shunk031/dotfiles/.github/screenshot-macos-client.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fshunk031%2Fdotfiles%2F.github%2Fscreenshot-macos-client.png" alt="Screenshot of setup on MacOS Client machine"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;🖥️ &lt;code&gt;Ubuntu&lt;/code&gt; &lt;a href="https://github.com/shunk031/dotfiles/actions/workflows/ubuntu.yaml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/shunk031/dotfiles/actions/workflows/ubuntu.yaml/badge.svg" alt="Ubuntu"&gt;&lt;/a&gt;
&lt;/h3&gt;

&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Configuration snippet of the Ubuntu environment for both client and server machine:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight highlight-text-shell-session notranslate position-relative overflow-auto js-code-highlight"&gt;
&lt;pre&gt;&lt;span class="pl-c1"&gt;bash -c "$(wget -qO - http://shunk031.me/dotfiles/setup.sh)"&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/shunk031/dotfiles/.github/screenshot-ubuntu-server.png"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fshunk031%2Fdotfiles%2F.github%2Fscreenshot-ubuntu-server.png" alt="Screenshot of setup on Ubuntu Server machine"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class="markdown-heading"&gt;
&lt;h3 class="heading-element"&gt;Minimal setup&lt;/h3&gt;

&lt;/div&gt;
&lt;p&gt;The following is a minimal setup command to install chezmoi and my dotfiles from the github repository on a new empty machine:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;sh -c…&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/div&gt;
  &lt;/div&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/shunk031/dotfiles" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;/div&gt;







&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;&lt;a href="https://www.chezmoi.io/quick-start/#start-using-chezmoi-on-your-current-machine:~:text=Create%20a%20new%20repository%20on%20GitHub%20called%20dotfiles%20and%20then%20push%20your%20repo%3A" rel="noopener noreferrer"&gt;chezmoi starts setup by referencing &lt;code&gt;$GITHUB_USERNAME/dotfiles&lt;/code&gt; on GitHub.&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;By default, chezmoi uses &lt;a href="https://www.chezmoi.io/user-guide/advanced/customize-your-source-directory/" rel="noopener noreferrer"&gt;the repository root as the source directory&lt;/a&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;This is the same mechanism as Python's &lt;code&gt;if __name__ == "__main__"&lt;/code&gt;. ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>dotfiles</category>
      <category>chezmoi</category>
      <category>bash</category>
      <category>githubactions</category>
    </item>
  </channel>
</rss>
