<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Chezmoi on Tarragon</title><link>https://tarrragon.github.io/blog/tags/chezmoi/</link><description>Recent content in Chezmoi on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Mon, 29 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/chezmoi/index.xml" rel="self" type="application/rss+xml"/><item><title>管理策略與選型</title><link>https://tarrragon.github.io/blog/linux/dotfile/01-dotfile-management/management-strategies/</link><pubDate>Mon, 29 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/dotfile/01-dotfile-management/management-strategies/</guid><description>&lt;p>Dotfile 管理的核心動作是把散落在家目錄各處的配置檔集中到一個 Git repo 裡版控。工具只是幫你處理「repo 裡的檔案怎麼對應到家目錄正確位置」這一層映射，選型看的是你的機器數量、OS 組合和 secret 需求。&lt;/p>
&lt;h2 id="git-bare-repo直接把家目錄當-work-tree">Git bare repo：直接把家目錄當 work tree&lt;/h2>
&lt;p>bare repo 的概念是在家目錄建一個沒有工作目錄的 Git 倉庫，然後用 alias 指定 &lt;code>--work-tree=$HOME&lt;/code>，讓 Git 直接追蹤家目錄下的檔案，不需要 symlink、不需要額外工具。&lt;/p>
&lt;p>初始化：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">git init --bare &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$HOME&lt;/span>&lt;span class="s2">/.dotfiles&amp;#34;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>在 shell 配置裡加一行 alias：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="nb">alias&lt;/span> &lt;span class="nv">dotfiles&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;git --git-dir=&amp;#34;$HOME/.dotfiles&amp;#34; --work-tree=&amp;#34;$HOME&amp;#34;&amp;#39;&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>之後所有 dotfile 操作都透過這個 alias：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">dotfiles add ~/.zshrc
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">dotfiles commit -m &lt;span class="s2">&amp;#34;add zshrc&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">dotfiles remote add origin git@github.com:you/dotfiles.git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">dotfiles push -u origin main&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>第一件要做的事是隱藏未追蹤檔案。家目錄底下有成千上萬個檔案，如果不設定這一行，&lt;code>dotfiles status&lt;/code> 會列出所有未追蹤的東西：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">dotfiles config --local status.showUntrackedFiles no&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>新機器還原的流程：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">git clone --bare git@github.com:you/dotfiles.git &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="nv">$HOME&lt;/span>&lt;span class="s2">/.dotfiles&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="nb">alias&lt;/span> &lt;span class="nv">dotfiles&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s1">&amp;#39;git --git-dir=&amp;#34;$HOME/.dotfiles&amp;#34; --work-tree=&amp;#34;$HOME&amp;#34;&amp;#39;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">dotfiles config --local status.showUntrackedFiles no
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">dotfiles checkout&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>&lt;code>checkout&lt;/code> 這步會把 repo 裡的檔案寫到家目錄。如果家目錄已經有同名檔案（例如系統預設的 &lt;code>.bashrc&lt;/code>），checkout 會失敗並列出衝突檔案，需要先手動備份或刪除。&lt;/p>
&lt;p>bare repo 適合配置量少、只管一台機器、不想安裝任何額外工具的人。它的限制是：概念對 Git 初學者不直覺（bare repo + work-tree 的組合不常見）、沒有模組化的概念（無法選擇性安裝某些配置）、多 profile 支援弱（不同機器要不同配置時只能靠 branch，長期維護困難）。&lt;/p>
&lt;h2 id="gnu-stowsymlink-農場管理器">GNU Stow：symlink 農場管理器&lt;/h2>
&lt;p>Stow 的概念是把 dotfile 集中放在一個普通目錄（如 &lt;code>~/dotfiles&lt;/code>），然後用 stow 指令在家目錄建立 symlink。stow 的核心規則是：package 目錄內的路徑結構，就是安裝後相對於目標目錄的路徑結構。&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 安裝 stow&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="c1"># macOS&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">brew install stow
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="c1"># Arch Linux&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">sudo pacman -S stow
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">&lt;span class="c1"># Ubuntu/Debian&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">sudo apt install stow&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>以 zsh 配置為例，目錄結構長這樣：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">~/dotfiles/zsh/.zshrc&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>執行 &lt;code>stow zsh&lt;/code> 後，stow 會在 &lt;code>$HOME&lt;/code> 建一個 symlink：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">~/.zshrc -&amp;gt; ~/dotfiles/zsh/.zshrc&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>對於放在 &lt;code>~/.config/&lt;/code> 底下的工具（XDG 規範），目錄結構映射同樣的邏輯：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">~/dotfiles/nvim/.config/nvim/init.lua
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">~/dotfiles/nvim/.config/nvim/lua/plugins.lua&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>執行 &lt;code>stow nvim&lt;/code> 後：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-text" data-lang="text">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">~/.config/nvim -&amp;gt; ~/dotfiles/nvim/.config/nvim&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>stow 會自動判斷該 symlink 整個目錄還是個別檔案——如果目標目錄不存在或目錄內所有檔案都由同一個 package 管理，stow 會 symlink 整個目錄（folding）；如果目標目錄已有其他檔案，stow 會展開（unfolding）成逐檔 symlink。&lt;/p>
&lt;p>初始化和日常操作：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># 初始化&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">mkdir ~/dotfiles &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> &lt;span class="nb">cd&lt;/span> ~/dotfiles
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">git init
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">git remote add origin git@github.com:you/dotfiles.git
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="c1"># 把現有 .zshrc 搬進 dotfiles&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">mkdir -p ~/dotfiles/zsh
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">mv ~/.zshrc ~/dotfiles/zsh/.zshrc
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="nb">cd&lt;/span> ~/dotfiles &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> stow zsh
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="c1"># 現在 ~/.zshrc 是一個 symlink，指向 ~/dotfiles/zsh/.zshrc&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">11&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">12&lt;/span>&lt;span class="cl">&lt;span class="c1"># 日常修改：直接編輯，symlink 透通&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">13&lt;/span>&lt;span class="cl">vim ~/.zshrc &lt;span class="c1"># 實際編輯的是 ~/dotfiles/zsh/.zshrc&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">14&lt;/span>&lt;span class="cl">&lt;span class="nb">cd&lt;/span> ~/dotfiles &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> git add -A &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> git commit -m &lt;span class="s2">&amp;#34;update zshrc&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">15&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">16&lt;/span>&lt;span class="cl">&lt;span class="c1"># 新機器還原&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">17&lt;/span>&lt;span class="cl">git clone git@github.com:you/dotfiles.git ~/dotfiles
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">18&lt;/span>&lt;span class="cl">&lt;span class="nb">cd&lt;/span> ~/dotfiles &lt;span class="o">&amp;amp;&amp;amp;&lt;/span> stow zsh git nvim tmux&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>批次安裝所有 package：&lt;/p></description><content:encoded><![CDATA[<p>Dotfile 管理的核心動作是把散落在家目錄各處的配置檔集中到一個 Git repo 裡版控。工具只是幫你處理「repo 裡的檔案怎麼對應到家目錄正確位置」這一層映射，選型看的是你的機器數量、OS 組合和 secret 需求。</p>
<h2 id="git-bare-repo直接把家目錄當-work-tree">Git bare repo：直接把家目錄當 work tree</h2>
<p>bare repo 的概念是在家目錄建一個沒有工作目錄的 Git 倉庫，然後用 alias 指定 <code>--work-tree=$HOME</code>，讓 Git 直接追蹤家目錄下的檔案，不需要 symlink、不需要額外工具。</p>
<p>初始化：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git init --bare <span class="s2">&#34;</span><span class="nv">$HOME</span><span class="s2">/.dotfiles&#34;</span></span></span></code></pre></div><p>在 shell 配置裡加一行 alias：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">alias</span> <span class="nv">dotfiles</span><span class="o">=</span><span class="s1">&#39;git --git-dir=&#34;$HOME/.dotfiles&#34; --work-tree=&#34;$HOME&#34;&#39;</span></span></span></code></pre></div><p>之後所有 dotfile 操作都透過這個 alias：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">dotfiles add ~/.zshrc
</span></span><span class="line"><span class="ln">2</span><span class="cl">dotfiles commit -m <span class="s2">&#34;add zshrc&#34;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">dotfiles remote add origin git@github.com:you/dotfiles.git
</span></span><span class="line"><span class="ln">4</span><span class="cl">dotfiles push -u origin main</span></span></code></pre></div><p>第一件要做的事是隱藏未追蹤檔案。家目錄底下有成千上萬個檔案，如果不設定這一行，<code>dotfiles status</code> 會列出所有未追蹤的東西：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">dotfiles config --local status.showUntrackedFiles no</span></span></code></pre></div><p>新機器還原的流程：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git clone --bare git@github.com:you/dotfiles.git <span class="s2">&#34;</span><span class="nv">$HOME</span><span class="s2">/.dotfiles&#34;</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">alias</span> <span class="nv">dotfiles</span><span class="o">=</span><span class="s1">&#39;git --git-dir=&#34;$HOME/.dotfiles&#34; --work-tree=&#34;$HOME&#34;&#39;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">dotfiles config --local status.showUntrackedFiles no
</span></span><span class="line"><span class="ln">4</span><span class="cl">dotfiles checkout</span></span></code></pre></div><p><code>checkout</code> 這步會把 repo 裡的檔案寫到家目錄。如果家目錄已經有同名檔案（例如系統預設的 <code>.bashrc</code>），checkout 會失敗並列出衝突檔案，需要先手動備份或刪除。</p>
<p>bare repo 適合配置量少、只管一台機器、不想安裝任何額外工具的人。它的限制是：概念對 Git 初學者不直覺（bare repo + work-tree 的組合不常見）、沒有模組化的概念（無法選擇性安裝某些配置）、多 profile 支援弱（不同機器要不同配置時只能靠 branch，長期維護困難）。</p>
<h2 id="gnu-stowsymlink-農場管理器">GNU Stow：symlink 農場管理器</h2>
<p>Stow 的概念是把 dotfile 集中放在一個普通目錄（如 <code>~/dotfiles</code>），然後用 stow 指令在家目錄建立 symlink。stow 的核心規則是：package 目錄內的路徑結構，就是安裝後相對於目標目錄的路徑結構。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 安裝 stow</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"># macOS</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">brew install stow
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># Arch Linux</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">sudo pacman -S stow
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="c1"># Ubuntu/Debian</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">sudo apt install stow</span></span></code></pre></div><p>以 zsh 配置為例，目錄結構長這樣：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">~/dotfiles/zsh/.zshrc</span></span></code></pre></div><p>執行 <code>stow zsh</code> 後，stow 會在 <code>$HOME</code> 建一個 symlink：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">~/.zshrc -&gt; ~/dotfiles/zsh/.zshrc</span></span></code></pre></div><p>對於放在 <code>~/.config/</code> 底下的工具（XDG 規範），目錄結構映射同樣的邏輯：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">~/dotfiles/nvim/.config/nvim/init.lua
</span></span><span class="line"><span class="ln">2</span><span class="cl">~/dotfiles/nvim/.config/nvim/lua/plugins.lua</span></span></code></pre></div><p>執行 <code>stow nvim</code> 後：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">~/.config/nvim -&gt; ~/dotfiles/nvim/.config/nvim</span></span></code></pre></div><p>stow 會自動判斷該 symlink 整個目錄還是個別檔案——如果目標目錄不存在或目錄內所有檔案都由同一個 package 管理，stow 會 symlink 整個目錄（folding）；如果目標目錄已有其他檔案，stow 會展開（unfolding）成逐檔 symlink。</p>
<p>初始化和日常操作：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 初始化</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">mkdir ~/dotfiles <span class="o">&amp;&amp;</span> <span class="nb">cd</span> ~/dotfiles
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">git init
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">git remote add origin git@github.com:you/dotfiles.git
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c1"># 把現有 .zshrc 搬進 dotfiles</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">mkdir -p ~/dotfiles/zsh
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">mv ~/.zshrc ~/dotfiles/zsh/.zshrc
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="nb">cd</span> ~/dotfiles <span class="o">&amp;&amp;</span> stow zsh
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="c1"># 現在 ~/.zshrc 是一個 symlink，指向 ~/dotfiles/zsh/.zshrc</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"># 日常修改：直接編輯，symlink 透通</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl">vim ~/.zshrc  <span class="c1"># 實際編輯的是 ~/dotfiles/zsh/.zshrc</span>
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="nb">cd</span> ~/dotfiles <span class="o">&amp;&amp;</span> git add -A <span class="o">&amp;&amp;</span> git commit -m <span class="s2">&#34;update zshrc&#34;</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">
</span></span><span class="line"><span class="ln">16</span><span class="cl"><span class="c1"># 新機器還原</span>
</span></span><span class="line"><span class="ln">17</span><span class="cl">git clone git@github.com:you/dotfiles.git ~/dotfiles
</span></span><span class="line"><span class="ln">18</span><span class="cl"><span class="nb">cd</span> ~/dotfiles <span class="o">&amp;&amp;</span> stow zsh git nvim tmux</span></span></code></pre></div><p>批次安裝所有 package：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">cd</span> ~/dotfiles
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"># stow 會把每個頂層目錄當成一個 package</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">stow */</span></span></code></pre></div><p>移除某個 package 的 symlink：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="nb">cd</span> ~/dotfiles <span class="o">&amp;&amp;</span> stow -D nvim</span></span></code></pre></div><p>stow 適合中等複雜度的配置管理。它的優勢是模組化（每個工具獨立一個 package、可選擇性安裝）和概念直覺（目錄結構就是安裝後的樣子）。它的限制是只管 symlink 映射，不管套件安裝；跨 OS 的路徑差異（macOS 和 Linux 某些工具的配置路徑不同）需要自己處理；stow 也不管 file permission——需要 0600 權限的 secret 檔（SSH private key、API token config）靠 symlink 繼承來源檔案權限，不能在部署過程中自動設定。</p>
<h2 id="yadmbare-repo-的升級版">yadm：bare repo 的升級版</h2>
<p>yadm 包裝了 Git bare repo 的操作，加上三個 bare repo 缺少的能力：alternate files（依 OS、hostname、甚至 user 條件選擇安裝不同版本的配置檔）、encrypt（用 GPG 或 OpenSSL 加密敏感檔案、不依賴外部密碼管理器）、bootstrap script（clone 後自動跑初始化）。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 安裝</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">brew install yadm          <span class="c1"># macOS</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">sudo pacman -S yadm        <span class="c1"># Arch</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1"># 初始化（等同 git init --bare + 自動設定 alias）</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">yadm init
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">yadm remote add origin git@github.com:you/dotfiles.git
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="c1"># 操作方式跟 Git 完全一樣</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">yadm add ~/.zshrc
</span></span><span class="line"><span class="ln">11</span><span class="cl">yadm commit -m <span class="s2">&#34;add zshrc&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">yadm push</span></span></code></pre></div><p>Alternate files 的概念是在同一個 repo 裡放多個版本的同一個檔案，yadm 依條件決定用哪一個：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">~/.config/alacritty/alacritty.toml##os.Darwin
</span></span><span class="line"><span class="ln">2</span><span class="cl">~/.config/alacritty/alacritty.toml##os.Linux</span></span></code></pre></div><p>macOS 上 yadm 自動 checkout Darwin 版本、Linux 上 checkout Linux 版本。比 stow 的 shell if-else 判斷更乾淨，比 chezmoi 的 Go template 學習曲線低。</p>
<p>yadm 適合想要 bare repo 的簡單性、但需要條件安裝或 secret 加密的人。它的限制是沒有 stow 的模組化概念（無法選擇性只安裝某些工具的配置）、沒有 chezmoi 的 template 細粒度（alternate files 是整個檔案切換，不是檔案內的段落條件）。</p>
<h2 id="chezmoi多機器-dotfile-管理工具">Chezmoi：多機器 dotfile 管理工具</h2>
<p>Chezmoi 是專為 dotfile 管理設計的工具，原生處理 template、secret 管理和多機器差異。它把 dotfile 存在自己的 source directory（<code>~/.local/share/chezmoi</code>），用 <code>chezmoi apply</code> 把檔案實際寫入目標位置（不是 symlink，是複製）。</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 安裝</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">brew install chezmoi        <span class="c1"># macOS</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">pacman -S chezmoi           <span class="c1"># Arch</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">sh -c <span class="s2">&#34;</span><span class="k">$(</span>curl -fsLS get.chezmoi.io<span class="k">)</span><span class="s2">&#34;</span>  <span class="c1"># 通用</span></span></span></code></pre></div><p>基本操作：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># 初始化（會建立 source directory 和 Git repo）</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">chezmoi init
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1"># 加入現有配置</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">chezmoi add ~/.zshrc
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">chezmoi add ~/.config/nvim
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="c1"># 編輯（在 source directory 裡編輯，不是直接改家目錄的檔案）</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">chezmoi edit ~/.zshrc
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="c1"># 預覽差異</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl">chezmoi diff
</span></span><span class="line"><span class="ln">13</span><span class="cl">
</span></span><span class="line"><span class="ln">14</span><span class="cl"><span class="c1"># 套用到家目錄</span>
</span></span><span class="line"><span class="ln">15</span><span class="cl">chezmoi apply
</span></span><span class="line"><span class="ln">16</span><span class="cl">
</span></span><span class="line"><span class="ln">17</span><span class="cl"><span class="c1"># 推上遠端</span>
</span></span><span class="line"><span class="ln">18</span><span class="cl">chezmoi <span class="nb">cd</span>  <span class="c1"># 進入 source directory</span>
</span></span><span class="line"><span class="ln">19</span><span class="cl">git add -A <span class="o">&amp;&amp;</span> git commit -m <span class="s2">&#34;update&#34;</span> <span class="o">&amp;&amp;</span> git push</span></span></code></pre></div><p>chezmoi 的核心優勢是 template。同一份配置檔在不同機器可以產生不同內容：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># chezmoi 的 source directory 裡，檔案名稱加 .tmpl 後綴</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1"># dot_zshrc.tmpl</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl">
</span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="nb">export</span> <span class="nv">EDITOR</span><span class="o">=</span><span class="s2">&#34;nvim&#34;</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="o">{{</span>- <span class="k">if</span> eq .chezmoi.os <span class="s2">&#34;darwin&#34;</span> <span class="o">}}</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="nb">export</span> <span class="nv">HOMEBREW_PREFIX</span><span class="o">=</span><span class="s2">&#34;/opt/homebrew&#34;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="nb">eval</span> <span class="s2">&#34;</span><span class="k">$(</span><span class="nv">$HOMEBREW_PREFIX</span>/bin/brew shellenv<span class="k">)</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="o">{{</span>- end <span class="o">}}</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="o">{{</span>- <span class="k">if</span> eq .chezmoi.os <span class="s2">&#34;linux&#34;</span> <span class="o">}}</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="nb">export</span> <span class="nv">PATH</span><span class="o">=</span><span class="s2">&#34;</span><span class="nv">$HOME</span><span class="s2">/.local/bin:</span><span class="nv">$PATH</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">13</span><span class="cl"><span class="o">{{</span>- end <span class="o">}}</span></span></span></code></pre></div><p><code>chezmoi apply</code> 會根據當前機器的 OS 展開 template，macOS 上產生的 <code>.zshrc</code> 會包含 Homebrew 設定，Linux 上不會。</p>
<p>Secret 管理是另一個殺手功能。chezmoi 整合了 1Password、Bitwarden、pass、gopass、LastPass 等密碼管理器：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl"># dot_gitconfig.tmpl
</span></span><span class="line"><span class="ln">2</span><span class="cl">[user]
</span></span><span class="line"><span class="ln">3</span><span class="cl">    name = Your Name
</span></span><span class="line"><span class="ln">4</span><span class="cl">    email = {{ (onepasswordRead &#34;op://Personal/Git Config/email&#34;).value }}</span></span></code></pre></div><p><code>chezmoi apply</code> 時會即時從 1Password 拉值填入，secret 不會存在 Git repo 裡。</p>
<p>chezmoi 適合管理多台異質機器（macOS 工作機 + Linux 伺服器 + Linux 桌面 VM）且有 secret 需求的人。它的代價是學習曲線最陡——要理解 chezmoi 自己的目錄命名慣例（<code>dot_</code> 前綴代表 <code>.</code> 開頭、<code>private_</code> 前綴代表權限 0600）、template 語法（Go template）、以及「source directory 和目標位置是兩份獨立的檔案」這個心智模型。</p>
<h2 id="選型判讀">選型判讀</h2>
<p>選工具看三個維度：機器數量、OS 組合、secret 需求。</p>
<p>只有一台機器、配置簡單 — bare repo 或 stow 都夠用，差別在於你喜不喜歡 symlink 的管理方式。bare repo 最輕量，stow 多一層模組化。</p>
<p>多台同質機器（都是 macOS 或都是 Linux）— stow。配置檔在同 OS 間差異小，不需要 template，stow 的模組化讓你可以只在桌面機安裝 hyprland package、伺服器只裝 zsh + git + tmux。</p>
<p>多台異質機器（macOS + Linux）但 secret 需求不高 — stow 加上 OS 分流仍然可行，<a href="/blog/linux/dotfile/01-dotfile-management/cross-platform-one-repo/" data-link-title="跨平台共用一個 Repo" data-link-desc="macOS 跟 Linux 要共用同一個 dotfile repo、不想維護兩份時回來讀">跨平台共用一個 Repo</a> 會完整說明做法。</p>
<p>多台異質機器、需要條件安裝但不想學 template 語法 — yadm。alternate files 讓你依 OS/hostname 切換整個配置檔，內建 encrypt 處理 secret，Git 操作方式跟 bare repo 相同。</p>
<p>多台異質機器（macOS + Linux）、有細粒度 template 或密碼管理器整合需求 — chezmoi。檔案內的段落條件、跟 1Password/Bitwarden 的整合、<code>private_</code> 前綴的 permission 管理是它存在的理由。</p>
<p>不確定 — 從 stow 開始。它的概念最直覺（目錄結構 = 安裝後位置）、遷移成本最低（要換到 yadm 是加一層 wrapper、要換到 chezmoi 時目錄結構的概念是相通的）。</p>
]]></content:encoded></item><item><title>模組一：管理工具與目錄結構</title><link>https://tarrragon.github.io/blog/linux/dotfile/01-dotfile-management/</link><pubDate>Mon, 29 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/dotfile/01-dotfile-management/</guid><description>&lt;p>Dotfile 管理的核心動作是把散落在家目錄各處的配置檔集中到一個 Git repo 裡版控。工具只是幫你處理「repo 裡的檔案怎麼對應到家目錄正確位置」這一層映射，選型看的是你的機器數量、OS 組合和 secret 需求。&lt;/p>
&lt;p>開始之前，確認 SSH key 和 Git 已經設好、dotfile repo 已經 clone 到本機——這些前置步驟見&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/00-dotfile-mindset/setup-order-guide/" data-link-title="環境建置的操作順序" data-link-desc="第一次從零建立 Linux 或 macOS 開發環境、不確定先做什麼後做什麼時讀 — 依賴順序路線圖，每一步附對應模組連結">環境建置的操作順序&lt;/a>的階段一。&lt;/p>
&lt;h2 id="章節文章">章節文章&lt;/h2>
&lt;table>
 &lt;thead>
 &lt;tr>
 &lt;th>文章&lt;/th>
 &lt;th>主題&lt;/th>
 &lt;/tr>
 &lt;/thead>
 &lt;tbody>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/01-dotfile-management/management-strategies/" data-link-title="管理策略與選型" data-link-desc="要選 dotfile 管理工具時回來讀 — bare repo、stow、chezmoi 的適用場景與選型判讀">管理策略與選型&lt;/a>&lt;/td>
 &lt;td>bare repo / stow / chezmoi 三種策略的操作方式、優劣與選型判讀&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/01-dotfile-management/cross-platform-one-repo/" data-link-title="跨平台共用一個 Repo" data-link-desc="macOS 跟 Linux 要共用同一個 dotfile repo、不想維護兩份時回來讀">跨平台共用一個 Repo&lt;/a>&lt;/td>
 &lt;td>macOS + Linux 用同一個 repo 的三層模型：stow 選擇性安裝、OS 分流、local.zsh 機器專屬&lt;/td>
 &lt;/tr>
 &lt;tr>
 &lt;td>&lt;a href="https://tarrragon.github.io/blog/linux/dotfile/01-dotfile-management/directory-structure-workflow/" data-link-title="目錄結構、Git 工作流與常見陷阱" data-link-desc="設計 dotfile repo 的目錄結構、或遇到 symlink 衝突和私鑰外洩等問題時回來讀">目錄結構、Git 工作流與常見陷阱&lt;/a>&lt;/td>
 &lt;td>stow 的目錄結構設計原則、日常 Git 操作流程、私鑰外洩等常見陷阱&lt;/td>
 &lt;/tr>
 &lt;/tbody>
&lt;/table>
&lt;h2 id="跨分類引用">跨分類引用&lt;/h2>
&lt;ul>
&lt;li>→ &lt;a href="https://tarrragon.github.io/blog/linux/dotfile/00-dotfile-mindset/" data-link-title="模組零：Dotfile 心智模型" data-link-desc="換機器、開 VM、重灌系統時需要快速還原開發環境，或想釐清哪些配置該版控、哪些該排除時回來讀">模組零：Dotfile 心智模型&lt;/a>：為什麼要管理、哪些東西該進 repo&lt;/li>
&lt;li>→ &lt;a href="https://tarrragon.github.io/blog/linux/dotfile/02-shell-config/" data-link-title="模組二：Shell 配置" data-link-desc="shell 配置檔長成一坨不敢動時回來讀 — .zshrc/.bashrc 的結構化拆分、alias/function/PATH 的模組化設計">模組二：Shell 配置&lt;/a>：目錄結構裡 zsh package 的具體拆法&lt;/li>
&lt;li>→ &lt;a href="https://tarrragon.github.io/blog/linux/dotfile/08-sync-bootstrap/" data-link-title="模組八：同步、Bootstrap 與環境重建" data-link-desc="換機器或重灌時怎麼還原工作環境 — bootstrap script 設計、套件清單管理、跨機器同步策略、secret 排除，以及 VM 快照和 dotfile 重建兩種思路的場景判讀">模組八：同步、Bootstrap 與環境重建&lt;/a>：跨機器同步策略與 secret 管理&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>Dotfile 管理的核心動作是把散落在家目錄各處的配置檔集中到一個 Git repo 裡版控。工具只是幫你處理「repo 裡的檔案怎麼對應到家目錄正確位置」這一層映射，選型看的是你的機器數量、OS 組合和 secret 需求。</p>
<p>開始之前，確認 SSH key 和 Git 已經設好、dotfile repo 已經 clone 到本機——這些前置步驟見<a href="/blog/linux/dotfile/00-dotfile-mindset/setup-order-guide/" data-link-title="環境建置的操作順序" data-link-desc="第一次從零建立 Linux 或 macOS 開發環境、不確定先做什麼後做什麼時讀 — 依賴順序路線圖，每一步附對應模組連結">環境建置的操作順序</a>的階段一。</p>
<h2 id="章節文章">章節文章</h2>
<table>
  <thead>
      <tr>
          <th>文章</th>
          <th>主題</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><a href="/blog/linux/dotfile/01-dotfile-management/management-strategies/" data-link-title="管理策略與選型" data-link-desc="要選 dotfile 管理工具時回來讀 — bare repo、stow、chezmoi 的適用場景與選型判讀">管理策略與選型</a></td>
          <td>bare repo / stow / chezmoi 三種策略的操作方式、優劣與選型判讀</td>
      </tr>
      <tr>
          <td><a href="/blog/linux/dotfile/01-dotfile-management/cross-platform-one-repo/" data-link-title="跨平台共用一個 Repo" data-link-desc="macOS 跟 Linux 要共用同一個 dotfile repo、不想維護兩份時回來讀">跨平台共用一個 Repo</a></td>
          <td>macOS + Linux 用同一個 repo 的三層模型：stow 選擇性安裝、OS 分流、local.zsh 機器專屬</td>
      </tr>
      <tr>
          <td><a href="/blog/linux/dotfile/01-dotfile-management/directory-structure-workflow/" data-link-title="目錄結構、Git 工作流與常見陷阱" data-link-desc="設計 dotfile repo 的目錄結構、或遇到 symlink 衝突和私鑰外洩等問題時回來讀">目錄結構、Git 工作流與常見陷阱</a></td>
          <td>stow 的目錄結構設計原則、日常 Git 操作流程、私鑰外洩等常見陷阱</td>
      </tr>
  </tbody>
</table>
<h2 id="跨分類引用">跨分類引用</h2>
<ul>
<li>→ <a href="/blog/linux/dotfile/00-dotfile-mindset/" data-link-title="模組零：Dotfile 心智模型" data-link-desc="換機器、開 VM、重灌系統時需要快速還原開發環境，或想釐清哪些配置該版控、哪些該排除時回來讀">模組零：Dotfile 心智模型</a>：為什麼要管理、哪些東西該進 repo</li>
<li>→ <a href="/blog/linux/dotfile/02-shell-config/" data-link-title="模組二：Shell 配置" data-link-desc="shell 配置檔長成一坨不敢動時回來讀 — .zshrc/.bashrc 的結構化拆分、alias/function/PATH 的模組化設計">模組二：Shell 配置</a>：目錄結構裡 zsh package 的具體拆法</li>
<li>→ <a href="/blog/linux/dotfile/08-sync-bootstrap/" data-link-title="模組八：同步、Bootstrap 與環境重建" data-link-desc="換機器或重灌時怎麼還原工作環境 — bootstrap script 設計、套件清單管理、跨機器同步策略、secret 排除，以及 VM 快照和 dotfile 重建兩種思路的場景判讀">模組八：同步、Bootstrap 與環境重建</a>：跨機器同步策略與 secret 管理</li>
</ul>
]]></content:encoded></item><item><title>跨機器同步、Secret 管理與環境重建流程</title><link>https://tarrragon.github.io/blog/linux/dotfile/08-sync-bootstrap/sync-strategy-secret/</link><pubDate>Mon, 29 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/linux/dotfile/08-sync-bootstrap/sync-strategy-secret/</guid><description>&lt;h2 id="跨機器同步策略">跨機器同步策略&lt;/h2>
&lt;p>多台機器共用 dotfile repo 時，需要一套同步策略來處理「改了配置後怎麼讓其他機器也更新」。&lt;/p>
&lt;h3 id="git-pushpull手動">Git push/pull（手動）&lt;/h3>
&lt;p>最基本的做法：改了就 commit + push，另一台機器 pull + 重新 apply。優點是簡單、沒有額外依賴。缺點是容易忘記——在公司機器上改了一個 alias，回家忘記 push，隔天公司又改了一版，兩邊 diverge。&lt;/p>
&lt;p>適合只有一兩台機器、改動不頻繁的人。&lt;/p>
&lt;h3 id="自動同步">自動同步&lt;/h3>
&lt;p>chezmoi 內建 &lt;code>chezmoi update&lt;/code> 指令（pull + apply 一步完成），搭配 cron 或 systemd timer 定期執行：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ini" data-lang="ini">&lt;span class="line">&lt;span class="ln"> 1&lt;/span>&lt;span class="cl">&lt;span class="c1"># ~/.config/systemd/user/chezmoi-update.timer&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 2&lt;/span>&lt;span class="cl">&lt;span class="k">[Unit]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 3&lt;/span>&lt;span class="cl">&lt;span class="na">Description&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">Update dotfiles daily&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 5&lt;/span>&lt;span class="cl">&lt;span class="k">[Timer]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 6&lt;/span>&lt;span class="cl">&lt;span class="na">OnCalendar&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">daily&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 7&lt;/span>&lt;span class="cl">&lt;span class="na">Persistent&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">true&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 8&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln"> 9&lt;/span>&lt;span class="cl">&lt;span class="k">[Install]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">10&lt;/span>&lt;span class="cl">&lt;span class="na">WantedBy&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">timers.target&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>




&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-ini" data-lang="ini">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># ~/.config/systemd/user/chezmoi-update.service&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="k">[Unit]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="na">Description&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">chezmoi update&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="k">[Service]&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">&lt;span class="na">Type&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">oneshot&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">&lt;span class="na">ExecStart&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s">/usr/bin/chezmoi update --no-tty&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>自動同步減少手動操作，但要注意衝突處理——如果兩台機器同時改了同一個檔案且都 push，後面那台的自動 pull 會遇到 merge conflict。實務上 dotfile 很少有真正的衝突（兩台機器同時改同一行的機率低），但偶爾發生時需要手動介入。&lt;/p>
&lt;h3 id="機器差異的處理">機器差異的處理&lt;/h3>
&lt;p>推薦的模式是 main branch 放所有共用配置，機器差異用條件判斷處理。&lt;/p>
&lt;p>用 shell 的 OS 判斷：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># ~/.zshrc&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="k">if&lt;/span> &lt;span class="o">[[&lt;/span> &lt;span class="s2">&amp;#34;&lt;/span>&lt;span class="k">$(&lt;/span>uname -s&lt;span class="k">)&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span> &lt;span class="o">==&lt;/span> &lt;span class="s2">&amp;#34;Darwin&amp;#34;&lt;/span> &lt;span class="o">]]&lt;/span>&lt;span class="p">;&lt;/span> &lt;span class="k">then&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl"> &lt;span class="nb">export&lt;/span> &lt;span class="nv">PATH&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/opt/homebrew/bin:&lt;/span>&lt;span class="nv">$PATH&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl"> &lt;span class="nb">alias&lt;/span> &lt;span class="nv">ls&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;ls -G&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">&lt;span class="k">else&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl"> &lt;span class="nb">alias&lt;/span> &lt;span class="nv">ls&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;ls --color=auto&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">&lt;span class="k">fi&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>用 chezmoi template（Go template 語法）：&lt;/p>





&lt;div class="highlight">&lt;pre tabindex="0" class="chroma">&lt;code class="language-bash" data-lang="bash">&lt;span class="line">&lt;span class="ln">1&lt;/span>&lt;span class="cl">&lt;span class="c1"># chezmoi 管理的 .zshrc.tmpl&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">2&lt;/span>&lt;span class="cl">&lt;span class="o">{{&lt;/span> &lt;span class="k">if&lt;/span> eq .chezmoi.os &lt;span class="s2">&amp;#34;darwin&amp;#34;&lt;/span> -&lt;span class="o">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">3&lt;/span>&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">PATH&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;/opt/homebrew/bin:&lt;/span>&lt;span class="nv">$PATH&lt;/span>&lt;span class="s2">&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">4&lt;/span>&lt;span class="cl">&lt;span class="o">{{&lt;/span> end -&lt;span class="o">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">5&lt;/span>&lt;span class="cl">
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">6&lt;/span>&lt;span class="cl">&lt;span class="o">{{&lt;/span> &lt;span class="k">if&lt;/span> eq .chezmoi.hostname &lt;span class="s2">&amp;#34;work-laptop&amp;#34;&lt;/span> -&lt;span class="o">}}&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">7&lt;/span>&lt;span class="cl">&lt;span class="nb">export&lt;/span> &lt;span class="nv">HTTP_PROXY&lt;/span>&lt;span class="o">=&lt;/span>&lt;span class="s2">&amp;#34;http://proxy.corp:8080&amp;#34;&lt;/span>
&lt;/span>&lt;/span>&lt;span class="line">&lt;span class="ln">8&lt;/span>&lt;span class="cl">&lt;span class="o">{{&lt;/span> end -&lt;span class="o">}}&lt;/span>&lt;/span>&lt;/span>&lt;/code>&lt;/pre>&lt;/div>&lt;p>chezmoi template 的優勢是條件判斷發生在 apply 階段，產出的檔案裡看不到 template 語法，乾淨且不依賴 shell 的 runtime 判斷。&lt;/p>
&lt;p>不推薦每台機器一個 branch 的做法。短期可行，長期一定 diverge——main 加了新配置，各 branch 要 rebase 或 merge，忘了就漂移。一份 main + template 條件判斷是長期可維護的結構。&lt;/p>
&lt;h2 id="secret-排除與管理">Secret 排除與管理&lt;/h2>
&lt;p>dotfile repo 通常是 public 或至少多人可見的。以下東西進了 repo 等於把鑰匙掛在門口：&lt;/p>
&lt;ul>
&lt;li>SSH 私鑰（&lt;code>~/.ssh/id_*&lt;/code>、&lt;code>*.pem&lt;/code>）&lt;/li>
&lt;li>API token、password、.env 檔案&lt;/li>
&lt;li>GPG 私鑰&lt;/li>
&lt;li>cloud provider 的 credential 檔案（&lt;code>~/.aws/credentials&lt;/code>、&lt;code>~/.config/gcloud/application_default_credentials.json&lt;/code>）&lt;/li>
&lt;li>browser profile 裡的 cookie / session&lt;/li>
&lt;/ul>
&lt;h3 id="gitignore-是第一道防線">.gitignore 是第一道防線&lt;/h3>





&lt;pre tabindex="0">&lt;code class="language-gitignore" data-lang="gitignore"># SSH 私鑰
*.pem
id_*
known_hosts
authorized_keys

# 環境變數
.env
.env.*

# Cloud credentials
credentials
application_default_credentials.json&lt;/code>&lt;/pre>&lt;p>但 .gitignore 只防「不小心 add」，不防「故意 add -f」。更重要的是建立習慣：repo 裡永遠只放「看到了也沒關係」的東西。&lt;/p>
&lt;h3 id="ssh-config-的特殊處理">SSH config 的特殊處理&lt;/h3>
&lt;p>&lt;code>~/.ssh/config&lt;/code>（host alias、ProxyJump 設定、port forwarding）本身不含 secret，可以進 repo——它記錄的是「連線要怎麼走」而不是「憑證是什麼」。但同一個 &lt;code>~/.ssh/&lt;/code> 目錄下的私鑰絕對排除。&lt;/p></description><content:encoded><![CDATA[<h2 id="跨機器同步策略">跨機器同步策略</h2>
<p>多台機器共用 dotfile repo 時，需要一套同步策略來處理「改了配置後怎麼讓其他機器也更新」。</p>
<h3 id="git-pushpull手動">Git push/pull（手動）</h3>
<p>最基本的做法：改了就 commit + push，另一台機器 pull + 重新 apply。優點是簡單、沒有額外依賴。缺點是容易忘記——在公司機器上改了一個 alias，回家忘記 push，隔天公司又改了一版，兩邊 diverge。</p>
<p>適合只有一兩台機器、改動不頻繁的人。</p>
<h3 id="自動同步">自動同步</h3>
<p>chezmoi 內建 <code>chezmoi update</code> 指令（pull + apply 一步完成），搭配 cron 或 systemd timer 定期執行：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1"># ~/.config/systemd/user/chezmoi-update.timer</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="k">[Unit]</span>
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="na">Description</span><span class="o">=</span><span class="s">Update dotfiles daily</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">[Timer]</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="na">OnCalendar</span><span class="o">=</span><span class="s">daily</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="na">Persistent</span><span class="o">=</span><span class="s">true</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="k">[Install]</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="na">WantedBy</span><span class="o">=</span><span class="s">timers.target</span></span></span></code></pre></div>




<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># ~/.config/systemd/user/chezmoi-update.service</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="k">[Unit]</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="na">Description</span><span class="o">=</span><span class="s">chezmoi update</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="k">[Service]</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="na">Type</span><span class="o">=</span><span class="s">oneshot</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="na">ExecStart</span><span class="o">=</span><span class="s">/usr/bin/chezmoi update --no-tty</span></span></span></code></pre></div><p>自動同步減少手動操作，但要注意衝突處理——如果兩台機器同時改了同一個檔案且都 push，後面那台的自動 pull 會遇到 merge conflict。實務上 dotfile 很少有真正的衝突（兩台機器同時改同一行的機率低），但偶爾發生時需要手動介入。</p>
<h3 id="機器差異的處理">機器差異的處理</h3>
<p>推薦的模式是 main branch 放所有共用配置，機器差異用條件判斷處理。</p>
<p>用 shell 的 OS 判斷：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># ~/.zshrc</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="k">if</span> <span class="o">[[</span> <span class="s2">&#34;</span><span class="k">$(</span>uname -s<span class="k">)</span><span class="s2">&#34;</span> <span class="o">==</span> <span class="s2">&#34;Darwin&#34;</span> <span class="o">]]</span><span class="p">;</span> <span class="k">then</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nb">export</span> <span class="nv">PATH</span><span class="o">=</span><span class="s2">&#34;/opt/homebrew/bin:</span><span class="nv">$PATH</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nb">alias</span> <span class="nv">ls</span><span class="o">=</span><span class="s2">&#34;ls -G&#34;</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="k">else</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="nb">alias</span> <span class="nv">ls</span><span class="o">=</span><span class="s2">&#34;ls --color=auto&#34;</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="k">fi</span></span></span></code></pre></div><p>用 chezmoi template（Go template 語法）：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># chezmoi 管理的 .zshrc.tmpl</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="o">{{</span> <span class="k">if</span> eq .chezmoi.os <span class="s2">&#34;darwin&#34;</span> -<span class="o">}}</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="nb">export</span> <span class="nv">PATH</span><span class="o">=</span><span class="s2">&#34;/opt/homebrew/bin:</span><span class="nv">$PATH</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="o">{{</span> end -<span class="o">}}</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">
</span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="o">{{</span> <span class="k">if</span> eq .chezmoi.hostname <span class="s2">&#34;work-laptop&#34;</span> -<span class="o">}}</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="nb">export</span> <span class="nv">HTTP_PROXY</span><span class="o">=</span><span class="s2">&#34;http://proxy.corp:8080&#34;</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="o">{{</span> end -<span class="o">}}</span></span></span></code></pre></div><p>chezmoi template 的優勢是條件判斷發生在 apply 階段，產出的檔案裡看不到 template 語法，乾淨且不依賴 shell 的 runtime 判斷。</p>
<p>不推薦每台機器一個 branch 的做法。短期可行，長期一定 diverge——main 加了新配置，各 branch 要 rebase 或 merge，忘了就漂移。一份 main + template 條件判斷是長期可維護的結構。</p>
<h2 id="secret-排除與管理">Secret 排除與管理</h2>
<p>dotfile repo 通常是 public 或至少多人可見的。以下東西進了 repo 等於把鑰匙掛在門口：</p>
<ul>
<li>SSH 私鑰（<code>~/.ssh/id_*</code>、<code>*.pem</code>）</li>
<li>API token、password、.env 檔案</li>
<li>GPG 私鑰</li>
<li>cloud provider 的 credential 檔案（<code>~/.aws/credentials</code>、<code>~/.config/gcloud/application_default_credentials.json</code>）</li>
<li>browser profile 裡的 cookie / session</li>
</ul>
<h3 id="gitignore-是第一道防線">.gitignore 是第一道防線</h3>





<pre tabindex="0"><code class="language-gitignore" data-lang="gitignore"># SSH 私鑰
*.pem
id_*
known_hosts
authorized_keys

# 環境變數
.env
.env.*

# Cloud credentials
credentials
application_default_credentials.json</code></pre><p>但 .gitignore 只防「不小心 add」，不防「故意 add -f」。更重要的是建立習慣：repo 裡永遠只放「看到了也沒關係」的東西。</p>
<h3 id="ssh-config-的特殊處理">SSH config 的特殊處理</h3>
<p><code>~/.ssh/config</code>（host alias、ProxyJump 設定、port forwarding）本身不含 secret，可以進 repo——它記錄的是「連線要怎麼走」而不是「憑證是什麼」。但同一個 <code>~/.ssh/</code> 目錄下的私鑰絕對排除。</p>
<p>stow 管理時的目錄結構範例：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl">dotfiles/
</span></span><span class="line"><span class="ln">2</span><span class="cl">└── ssh/
</span></span><span class="line"><span class="ln">3</span><span class="cl">    └── .ssh/
</span></span><span class="line"><span class="ln">4</span><span class="cl">        └── config        # 進 repo
</span></span><span class="line"><span class="ln">5</span><span class="cl">        # id_rsa 不放這裡
</span></span><span class="line"><span class="ln">6</span><span class="cl">        # known_hosts 不放這裡</span></span></code></pre></div><h3 id="三個層級的-secret-管理">三個層級的 secret 管理</h3>
<p><strong>層級一：手動</strong>。.gitignore 排除 secret 檔案，在 README 記錄「這些東西需要在新機器手動設定」。最低成本、對只有一兩台機器的人足夠。</p>
<p><strong>層級二：密碼管理器整合</strong>。chezmoi 支援從 1Password、Bitwarden、pass（Unix password manager）等拉取 secret：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="ln">1</span><span class="cl"># chezmoi template 語法
</span></span><span class="line"><span class="ln">2</span><span class="cl">{{ (onepasswordRead &#34;op://Personal/SSH Key/private key&#34;).value }}</span></span></code></pre></div><p>配置檔的 template 裡引用密碼管理器的條目，apply 時自動填入。secret 不在 repo 裡，但 repo 知道去哪拉。</p>
<p><strong>層級三：加密存放</strong>。用 age 或 sops 把 secret 加密後直接存在 repo 裡。解密需要對應的 key。chezmoi 原生支援 age 加密：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 加密一個檔案</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">chezmoi add --encrypt ~/.ssh/id_rsa
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"># repo 裡看到的是加密後的內容</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">cat ~/.local/share/chezmoi/private_dot_ssh/id_rsa.age</span></span></code></pre></div><p>加密存放的好處是 secret 跟著 repo 走、不用另外設密碼管理器。風險是加密 key 本身變成唯一的依賴——丟了 key，加密的 secret 就拿不回來。</p>
<p>層級選擇取決於安全需求和便利需求的平衡。多數情況從層級一開始，覺得手動處理太煩再往上升級。</p>
<h2 id="環境重建的實際流程">環境重建的實際流程</h2>
<p>假設拿到一台全新的 Arch Linux 機器，要從零重建完整的 Hyprland 桌面環境。以下是 end-to-end 的步驟，對應 <a href="/blog/linux/dotfile/08-sync-bootstrap/bootstrap-script-packages/" data-link-title="Bootstrap Script 與套件清單管理" data-link-desc="寫 dotfile 的 install script、或整理「這台機器裝了什麼」的套件清單時回來讀">bootstrap script</a> 的每個階段。</p>
<h3 id="階段一最小可用環境">階段一：最小可用環境</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># Arch 安裝完成後，base system 只有 bash 和基本工具</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">sudo pacman -S git base-devel</span></span></code></pre></div><p>這是 bootstrap script 的唯一外部前提：有 Git 能 clone repo、有 base-devel 能編譯 AUR 套件。其他一切由 script 處理。</p>
<h3 id="階段二取得-dotfile-repo">階段二：取得 dotfile repo</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">git clone https://github.com/you/dotfiles ~/dotfiles
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="nb">cd</span> ~/dotfiles</span></span></code></pre></div><p>如果 repo 是 private，這一步需要先設定 SSH key 或用 HTTPS + token。這是前面提到的 secret 雞生蛋問題——clone 含有 SSH config 的 repo 本身就需要 SSH key。解法通常是：第一次用 HTTPS clone，deploy 完 SSH config 後把 remote 改成 SSH。</p>
<h3 id="階段三執行-bootstrap">階段三：執行 bootstrap</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl">./scripts/install.sh</span></span></code></pre></div><p>script 依序：安裝套件（Hyprland、waybar、rofi、wezterm、zsh、neovim、stow 等）、用 stow 部署配置到 <code>$HOME</code>、執行初始化（換 shell、安裝 neovim plugin）。</p>
<h3 id="階段四手動處理">階段四：手動處理</h3>
<p>bootstrap 處理不了（或不該處理）的部分：</p>
<ul>
<li><strong>SSH 私鑰</strong>：從備份或密碼管理器取回，放到 <code>~/.ssh/</code>，設定正確權限（<code>chmod 600</code>）</li>
<li><strong>Git 簽署用的 GPG key</strong>：如果有用 commit signing</li>
<li><strong>密碼管理器登入</strong>：如果 secret 管理用了層級二或三</li>
</ul>
<h3 id="階段五硬體相關調整">階段五：硬體相關調整</h3>
<p>Hyprland 的 monitor 設定（解析度、縮放、排列位置）跟實際接的螢幕有關，這部分配置每台機器都不同：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># ~/.config/hypr/hyprland.conf 的 monitor 段</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"># 這幾行在每台機器上都要調</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="na">monitor</span><span class="o">=</span><span class="s">DP-1, 2560x1440@144, 0x0, 1</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="na">monitor</span><span class="o">=</span><span class="s">HDMI-A-1, 1920x1080@60, 2560x0, 1</span></span></span></code></pre></div><p>處理方式有兩種：把 monitor 設定拆成獨立的 <code>monitor.conf</code>，主配置用 <code>source</code> 引入，<code>monitor.conf</code> 不進 repo（加進 .gitignore）、每台機器本地維護；或者用 chezmoi template 按 hostname 判斷。</p>
<p>顯卡驅動（Intel/AMD 通常自動、NVIDIA 需要額外安裝 <code>nvidia-dkms</code> 和設定環境變數）也是硬體相關的步驟，可以放在 bootstrap script 的 OS 判斷裡，但通常 Arch 安裝階段就已經處理。</p>
<h3 id="階段六驗證">階段六：驗證</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1"># 登出 TTY，重新用 Hyprland 登入</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"># 或者直接在 TTY 執行</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">Hyprland</span></span></code></pre></div><p>登入後確認：視窗管理器正常運作、keybind 正確、狀態列出現、字型正確渲染、終端機配色正常。如果某個元件沒反應，通常是套件沒裝或配置路徑不對——回去檢查 bootstrap 的套件清單和 stow 的 symlink。</p>
<h3 id="時間預估">時間預估</h3>
<p>整個流程在網路順暢的情況下，大約 30 分鐘到 1 小時，取決於套件數量和下載速度。主要時間花在套件安裝（pacman 下載 + 編譯 AUR 套件）。配置 deploy 本身是秒級操作（stow 只建 symlink）。</p>
<p>對比沒有 dotfile 管理時的重建：邊想邊裝、裝了忘記某個工具的名稱、配置靠記憶手打、兩天後還在調某個快捷鍵為什麼不對。差距在「可預期 vs 碰運氣」。</p>
<h2 id="維護節奏">維護節奏</h2>
<p>環境重建能力需要持續維護，不是設定完就一勞永逸。</p>
<p>日常習慣：新裝一個工具時，順手更新套件清單（<code>brew bundle dump</code> 或手動加一行到 <code>packages.txt</code>）。改了一個配置後，commit + push。這個習慣的建立成本低，但需要刻意練幾週才會變成反射動作。</p>
<p>定期檢查：每隔幾個月在 VM 或 container 裡跑一次完整的 bootstrap，驗證 script 還能從零跑通。配置會演進、套件會改名或被取代、script 裡硬寫的路徑可能失效——定期驗證才能確保「這份重建指令真的能重建」，而不是一份過期的紀錄。</p>
]]></content:encoded></item></channel></rss>