<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Fzf on 終於明白 | tsungyi knows.</title><link>https://tsungyi.li/Blog/tags/fzf/</link><description>Recent content in Fzf on 終於明白 | tsungyi knows.</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Thu, 29 Oct 2026 10:55:56 +0800</lastBuildDate><atom:link href="https://tsungyi.li/Blog/tags/fzf/index.xml" rel="self" type="application/rss+xml"/><item><title>拆開 fzf 腳本：每支背後真正在跑的 Git 指令</title><link>https://tsungyi.li/Blog/posts/git-commands-behind-fzf-scripts/</link><pubDate>Thu, 29 Oct 2026 10:55:56 +0800</pubDate><guid>https://tsungyi.li/Blog/posts/git-commands-behind-fzf-scripts/</guid><description>&lt;h2 id="起因"&gt;起因&lt;/h2&gt;&#10;&lt;p&gt;&lt;a href="../interactive-git-cli-with-fzf/"&gt;上一篇&lt;/a&gt;講的是這些腳本怎麼設計。這篇反過來：把 fzf 那層剝掉，看每支腳本&lt;strong&gt;實際&lt;/strong&gt;在跑哪幾條 git 指令。&lt;/p&gt;&#10;&lt;p&gt;理由很實際。腳本不在手邊時（別人的機器、CI、container），你還是得自己打這些指令。而且拆的過程中，我挖出了兩個藏了很久的 bug。&lt;/p&gt;&#10;&lt;h2 id="共用底層"&gt;共用底層&lt;/h2&gt;&#10;&lt;p&gt;每支腳本開頭都是同一組檢查：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git rev-parse --is-inside-work-tree &lt;span style="color:#75715e"&gt;# 不在 repo 裡就結束&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git rev-parse --show-toplevel &lt;span style="color:#75715e"&gt;# cd 到 repo 根目錄&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;需要 &lt;code&gt;cd&lt;/code&gt; 到根目錄，是因為 &lt;code&gt;git status --short&lt;/code&gt; 和 &lt;code&gt;git diff --name-status&lt;/code&gt; 印出的路徑都是相對於 repo 根目錄。在子目錄裡直接拿去當 pathspec 用，就會對不上。&lt;/p&gt;&#10;&lt;p&gt;列分支用的是 &lt;code&gt;git branch --format&lt;/code&gt;，語法和 &lt;code&gt;git for-each-ref&lt;/code&gt; 一模一樣，連條件式都能寫：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git branch -l --format&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;%(refname:short) [%(objectname:short)] %(if)%(upstream)%(then)-&amp;gt; %(upstream:short)%(else)&amp;lt;no upstream&amp;gt;%(end)&amp;#39;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="gitbr查分支指向哪裡"&gt;gitbr：查分支指向哪裡&lt;/h2&gt;&#10;&lt;p&gt;&lt;code&gt;gitbr&lt;/code&gt; 的用途是：不 checkout 也能知道一條分支指向哪個 commit、有沒有追蹤 upstream，並把 short SHA 複製到剪貼簿。核心只有三條：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git branch --show-current &lt;span style="color:#75715e"&gt;# 目前分支名稱&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git rev-parse &amp;lt;ref&amp;gt; &lt;span style="color:#75715e"&gt;# ref → SHA&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git rev-parse --abbrev-ref &amp;lt;branch&amp;gt;@&lt;span style="color:#f92672"&gt;{&lt;/span&gt;upstream&lt;span style="color:#f92672"&gt;}&lt;/span&gt; &lt;span style="color:#75715e"&gt;# 追蹤的遠端分支&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;&amp;lt;branch&amp;gt;@{upstream}&lt;/code&gt;（縮寫 &lt;code&gt;@{u}&lt;/code&gt;）指的是 &lt;code&gt;branch.&amp;lt;name&amp;gt;.merge&lt;/code&gt; 設定的那條 remote-tracking branch。如果沒有設定，指令會失敗，所以腳本後面接了 &lt;code&gt;|| true&lt;/code&gt;。&lt;/p&gt;</description></item><item><title>把 Git 包成互動式 CLI：10 支 fzf 腳本的設計筆記</title><link>https://tsungyi.li/Blog/posts/interactive-git-cli-with-fzf/</link><pubDate>Mon, 31 Aug 2026 11:42:11 +0800</pubDate><guid>https://tsungyi.li/Blog/posts/interactive-git-cli-with-fzf/</guid><description>&lt;h2 id="起因"&gt;起因&lt;/h2&gt;&#10;&lt;p&gt;&lt;a href="../git-useful-commands/"&gt;上一篇&lt;/a&gt;整理的那幾條指令，參數本身都不難記。麻煩的是那種&lt;strong&gt;要先查才能打&lt;/strong&gt;的情境。&lt;/p&gt;&#10;&lt;p&gt;想 checkout 一個還沒 checkout 過的遠端分支，得先 &lt;code&gt;git branch -r&lt;/code&gt;，用眼睛掃一遍，再手動打分支名。想把某段 commit 搬到別條分支，&lt;code&gt;git rebase --onto &amp;lt;new-base&amp;gt; &amp;lt;old-base&amp;gt; &amp;lt;until&amp;gt;&lt;/code&gt; 三個參數各是什麼，我每次都要想。想拿某個 commit 的 SHA，&lt;code&gt;git log --oneline&lt;/code&gt; 之後反白複製。&lt;/p&gt;&#10;&lt;p&gt;這些操作花時間的部分是&lt;strong&gt;選&lt;/strong&gt;，不是執行。fzf 剛好就是拿來解決選的問題。&lt;/p&gt;&#10;&lt;p&gt;於是有了 10 支腳本，命名一律是 &lt;code&gt;git&lt;/code&gt; 加兩個字母，取自指令本身的大寫字母。&lt;/p&gt;&#10;&lt;h2 id="共同骨架"&gt;共同骨架&lt;/h2&gt;&#10;&lt;p&gt;每支腳本第一行做的事都一樣：source 同一個 &lt;code&gt;helpers/git_utils.sh&lt;/code&gt;。裡面沒什麼特別的，就是色彩輸出跟前置檢查：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; hl&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; printf &lt;span style="color:#e6db74"&gt;&amp;#39;\033[1;33m%s\033[0m&amp;#39;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$1&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; info&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; printf &lt;span style="color:#e6db74"&gt;&amp;#39;[\033[1;36mINFO\033[0m] %s\n&amp;#39;&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;$1&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; check_git&lt;span style="color:#f92672"&gt;()&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; git rev-parse --is-inside-work-tree &amp;gt; /dev/null 2&amp;gt;&amp;amp;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#f92672"&gt;||&lt;/span&gt; &lt;span style="color:#f92672"&gt;{&lt;/span&gt; err &lt;span style="color:#e6db74"&gt;&amp;#34;Not a git repository.&amp;#34;&lt;/span&gt;; exit 1; &lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;}&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;比較值得提的是 &lt;code&gt;get_local_branches&lt;/code&gt;。用 &lt;code&gt;--format&lt;/code&gt; 把四個欄位塞在同一行：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;local format&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;%(if)%(upstream)%(then)%(refname:short) [%(objectname:short)] -&amp;gt; %(upstream:short)%(else)%(refname:short) [%(objectname:short)] &amp;lt;no upstream&amp;gt;%(end) %(contents:subject)&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git branch -l --format&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;format&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;這樣在 fzf 清單裡一眼看得到分支名、short SHA、追蹤的 upstream、最後一筆 commit 標題，而 &lt;code&gt;awk '{print $1}'&lt;/code&gt; 還是能乾淨取回分支名。&lt;/p&gt;</description></item></channel></rss>