aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAkshay <[email protected]>2022-09-04 08:05:38 +0100
committerAkshay <[email protected]>2022-09-04 08:05:38 +0100
commitc3669921a8ab3fd4953f0ac8b8d50827c4c80191 (patch)
treef66c87b1b154598f75cbddf35326dfe68a313b29
parente0f5114b70b2d9619478848296d1be0bca31e5dc (diff)
new post: curing a case of git-ux
-rw-r--r--docs/index.html16
-rw-r--r--docs/index.xml184
-rw-r--r--docs/posts/curing_a_case_of_git-UX/index.html253
-rw-r--r--docs/posts/index.html17
-rw-r--r--posts/curing_a_case_of_git-UX.md320
5 files changed, 782 insertions, 8 deletions
diff --git a/docs/index.html b/docs/index.html
index 3973034..b3d6de9 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -42,15 +42,15 @@
42 <tr> 42 <tr>
43 <td class=table-post> 43 <td class=table-post>
44 <div class="date"> 44 <div class="date">
45 28/08 — 2022 45 03/09 — 2022
46 </div> 46 </div>
47 <a href="/posts/programming_on_34_keys" class="post-link"> 47 <a href="/posts/curing_a_case_of_git-UX" class="post-link">
48 <span class="post-link">Programming On 34 Keys</span> 48 <span class="post-link">Curing A Case Of Git-UX</span>
49 </a> 49 </a>
50 </td> 50 </td>
51 <td class=table-stats> 51 <td class=table-stats>
52 <span class="stats-number"> 52 <span class="stats-number">
53 6.2 53 9.5
54 </span> 54 </span>
55 <span class=stats-unit>min</span> 55 <span class=stats-unit>min</span>
56 </td> 56 </td>
@@ -59,15 +59,15 @@
59 <tr> 59 <tr>
60 <td class=table-post> 60 <td class=table-post>
61 <div class="date"> 61 <div class="date">
62 02/08 — 2022 62 28/08 — 2022
63 </div> 63 </div>
64 <a href="/posts/a_reference_counted_afterlife" class="post-link"> 64 <a href="/posts/programming_on_34_keys" class="post-link">
65 <span class="post-link">A Reference Counted Afterlife</span> 65 <span class="post-link">Programming On 34 Keys</span>
66 </a> 66 </a>
67 </td> 67 </td>
68 <td class=table-stats> 68 <td class=table-stats>
69 <span class="stats-number"> 69 <span class="stats-number">
70 1.6 70 6.2
71 </span> 71 </span>
72 <span class=stats-unit>min</span> 72 <span class=stats-unit>min</span>
73 </td> 73 </td>
diff --git a/docs/index.xml b/docs/index.xml
index 62c8871..5586abd 100644
--- a/docs/index.xml
+++ b/docs/index.xml
@@ -12,6 +12,190 @@
12 <language>en-us</language> 12 <language>en-us</language>
13 <copyright>Creative Commons BY-NC-SA 4.0</copyright> 13 <copyright>Creative Commons BY-NC-SA 4.0</copyright>
14 <item> 14 <item>
15<title>Curing A Case Of Git-UX</title>
16<description>&lt;p&gt;Git worktrees are great, but they fall behind the venerable &lt;code&gt;git checkout&lt;/code&gt; sometimes. I attempted to fix that with &lt;a href="https://github.com/junegunn/fzf"&gt;fzf&lt;/a&gt; and a bit of bash.&lt;/p&gt;
17&lt;p&gt;&lt;a href="https://asciinema.org/a/D297ztKRzpE4gAHbPTPmkqYps"&gt;&lt;img src="https://asciinema.org/a/D297ztKRzpE4gAHbPTPmkqYps.svg" /&gt;&lt;/a&gt;&lt;/p&gt;
18&lt;p&gt;Fear not if you haven’t heard of “worktrees”, I have included a primer here.&lt;br /&gt;
19&lt;a href="#what-makes-them-clunky"&gt;Skip the primer -&amp;gt;&lt;/a&gt;.&lt;/p&gt;
20&lt;h3 id="why-worktrees"&gt;Why Worktrees?&lt;/h3&gt;
21&lt;p&gt;Picture this. You are whacking away on a feature branch. Halfway there, in fact. Your friend asks you fix something urgently. You proceed to do one of three things:&lt;/p&gt;
22&lt;ul&gt;
23&lt;li&gt;create a temporary branch, make a WIP commit, begin working on the fix&lt;/li&gt;
24&lt;li&gt;stash away your changes, begin working on the fix&lt;/li&gt;
25&lt;li&gt;unfriend said friend for disturbing your flow&lt;/li&gt;
26&lt;/ul&gt;
27&lt;p&gt;All of these options are … subpar. With the temporary branch, you are forced to create a partial, non-working commit, and then reset said commit once done with the fix. With the stash approach, you are required to now keep a mental model of the stash, be aware of untracked files that don’t get stashed by default, etc. Why won’t git just let you work on two things at the same time without &lt;em&gt;thinking&lt;/em&gt; so much?&lt;/p&gt;
28&lt;p&gt;That is exactly what worktrees let you do. Worktrees let you have more than one checkout at a time, each checkout in a separate directory. Like creating a new clone, but safer (it disallows checking out the same branch twice) and a lot more space efficient (the new working tree is “linked” to the “main” worktree, and a good amount of stuff is shared). When your friend asks you to make the fix, you proceed like so:&lt;/p&gt;
29&lt;ol type="1"&gt;
30&lt;li&gt;Create a new working tree with:&lt;/li&gt;
31&lt;/ol&gt;
32&lt;div class="sourceCode" id="cb1"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb1-1"&gt;&lt;a href="#cb1-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# git worktree add -b &amp;lt;branch-name&amp;gt; &amp;lt;path&amp;gt; &amp;lt;from&amp;gt;&lt;/span&gt;&lt;/span&gt;
33&lt;span id="cb1-2"&gt;&lt;a href="#cb1-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;git&lt;/span&gt; worktree add &lt;span class="at"&gt;-b&lt;/span&gt; fix-stuff /path/to/tree master&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
34&lt;ol start="2" type="1"&gt;
35&lt;li&gt;&lt;code&gt;cd&lt;/code&gt; into &lt;code&gt;/path/to/tree&lt;/code&gt;&lt;/li&gt;
36&lt;li&gt;Fix, test, commit, push, party&lt;/li&gt;
37&lt;li&gt;Go back to your work, &lt;code&gt;cd -&lt;/code&gt;&lt;/li&gt;
38&lt;/ol&gt;
39&lt;p&gt;Easy as cake. You didn’t have to settle for a partially working commit, you didn’t to deal with this “stash” thing, &lt;em&gt;and&lt;/em&gt; you didn’t have to unfriend your friend. Treating each branch as a directory just &lt;em&gt;feels&lt;/em&gt; more intuitive, more UNIX-y.&lt;/p&gt;
40&lt;p&gt;A few weeks later, you find yourself singing in praise of worktrees, working on several things simultaneously. And at the same time, cursing them for being a little … clunky.&lt;/p&gt;
41&lt;h3 id="what-makes-them-clunky"&gt;What makes them clunky?&lt;/h3&gt;
42&lt;p&gt;Worktrees are great at what they claim to do. They stay out of the way when you need a checkout posthaste. However, as you start using them regularly, you realize they are not as flexible as &lt;code&gt;git checkout&lt;/code&gt; or &lt;code&gt;git switch&lt;/code&gt;.&lt;/p&gt;
43&lt;h4 id="branch-hopping"&gt;Branch-hopping&lt;/h4&gt;
44&lt;p&gt;You can &lt;code&gt;git checkout &amp;lt;branch&amp;gt;&lt;/code&gt; from anywhere within a git repository. You can’t “jump” to a worktree in the same fashion. The closest you can get, is to run &lt;code&gt;git worktree list&lt;/code&gt;, copy the path corresponding to your branch, and &lt;code&gt;cd&lt;/code&gt; into it.&lt;/p&gt;
45&lt;p&gt;Branch-hopping with the good ol’ git-checkout:&lt;/p&gt;
46&lt;div class="sourceCode" id="cb2"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb2-1"&gt;&lt;a href="#cb2-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# anywhere, anytime&lt;/span&gt;&lt;/span&gt;
47&lt;span id="cb2-2"&gt;&lt;a href="#cb2-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git checkout feature/is-ascii-octdigit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
48&lt;p&gt;Meanwhile, in worktree world:&lt;/p&gt;
49&lt;div class="sourceCode" id="cb3"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb3-1"&gt;&lt;a href="#cb3-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# keeping these paths in your head is hard&lt;/span&gt;&lt;/span&gt;
50&lt;span id="cb3-2"&gt;&lt;a href="#cb3-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git worktree list&lt;/span&gt;
51&lt;span id="cb3-3"&gt;&lt;a href="#cb3-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/worktrees/rustc/master&lt;/span&gt; eac6c33bc63 [master]&lt;/span&gt;
52&lt;span id="cb3-4"&gt;&lt;a href="#cb3-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/worktrees/rustc/improve-std-char-docs&lt;/span&gt; 94cba88553e [improve-std-char-docs]&lt;/span&gt;
53&lt;span id="cb3-5"&gt;&lt;a href="#cb3-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/worktrees/rustc/is-ascii-octdigit&lt;/span&gt; bc57be3af7a [feature/is-ascii-octdigit]&lt;/span&gt;
54&lt;span id="cb3-6"&gt;&lt;a href="#cb3-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/my/other/path/oh/god&lt;/span&gt; op57or3ns7n [fix/some-error]&lt;/span&gt;
55&lt;span id="cb3-7"&gt;&lt;a href="#cb3-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
56&lt;span id="cb3-8"&gt;&lt;a href="#cb3-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; cd ~/worktrees/rustc/is-ascii-octdigit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
57&lt;h4 id="branch-previewing"&gt;Branch-previewing&lt;/h4&gt;
58&lt;p&gt;You can “preview” branches with &lt;code&gt;git branch -v&lt;/code&gt;. However, to get an idea of what “recent activity” on a worktree looks like, you might need some juggling. You can’t glean much info about a worktree in a jiffy.&lt;/p&gt;
59&lt;p&gt;Branch-previewing with the good ol’ git-branch:&lt;/p&gt;
60&lt;div class="sourceCode" id="cb4"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb4-1"&gt;&lt;a href="#cb4-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git branch &lt;span class="at"&gt;-v&lt;/span&gt;&lt;/span&gt;
61&lt;span id="cb4-2"&gt;&lt;a href="#cb4-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;+&lt;/span&gt; feature/is-ascii-octdigit bc57be3af7a introduce {char, u8}::is_ ...&lt;/span&gt;
62&lt;span id="cb4-3"&gt;&lt;a href="#cb4-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;+&lt;/span&gt; improve-std-char-docs 94cba88553e add whitespace in assert ...&lt;/span&gt;
63&lt;span id="cb4-4"&gt;&lt;a href="#cb4-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;*&lt;/span&gt; master eac6c33bc63 Auto merge of &lt;span class="co"&gt;#100869 - n ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
64&lt;p&gt;Meanwhile in worktree wonderland:&lt;/p&gt;
65&lt;pre&gt;&lt;code&gt;λ git worktree list
66~/worktrees/rustc/master eac6c33bc63 [master]
67~/worktrees/rustc/improve-std-char-docs 94cba88553e [improve-std-char-docs]
68~/worktrees/rustc/is-ascii-octdigit bc57be3af7a [feature/is-ascii-octdigit]
69
70# aha, so ../is-ascii-octdigit corresponds to `feature/is-ascii-octdigit`
71λ git log feature/is-ascii-octdigit
72bc57be3af7a introduce {char, u8}::is_ascii_octdigit
73eac6c33bc63 Auto merge of #100869 - nnethercote:repl ...
74b32223fec10 Auto merge of #100707 - dzvon:fix-typo, ...
75aa857eb953e Auto merge of #100537 - petrochenkov:pic ...
76
77# extra work to make the branch &amp;lt;-&amp;gt; worktree correspondence&lt;/code&gt;&lt;/pre&gt;
78&lt;h4 id="shell-completions"&gt;Shell completions&lt;/h4&gt;
79&lt;p&gt;Lastly, you can bank on shell completions to fill in your branch whilst using &lt;code&gt;git checkout&lt;/code&gt;. Worktrees have no such conveniences.&lt;/p&gt;
80&lt;p&gt;We can mend these minor faults with fzf.&lt;/p&gt;
81&lt;h3 id="unclunkifying-worktrees"&gt;Unclunkifying worktrees&lt;/h3&gt;
82&lt;p&gt;I’d suggest looking up &lt;a href="https://github.com/junegunn/fzf"&gt;fzf&lt;/a&gt; (or &lt;a href="https://github.com/lotabout/skim"&gt;skim&lt;/a&gt; or &lt;a href="https://github.com/jhawthorn/fzy"&gt;fzy&lt;/a&gt;). These things make it cake-easy to add interactivity to your shell. Onto fixing the first minor fault, the inability to “jump” to a worktree from anywhere within a git repository.&lt;/p&gt;
83&lt;p&gt;I have a little function called &lt;code&gt;gwj&lt;/code&gt; which stands for “git worktree jump”. The idea is to list all the worktrees, select one with fzf, and &lt;code&gt;cd&lt;/code&gt; to it upon selection:&lt;/p&gt;
84&lt;div class="sourceCode" id="cb6"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb6-1"&gt;&lt;a href="#cb6-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;gwj ()&lt;/span&gt; &lt;span class="kw"&gt;{&lt;/span&gt;&lt;/span&gt;
85&lt;span id="cb6-2"&gt;&lt;a href="#cb6-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;local&lt;/span&gt; &lt;span class="va"&gt;out&lt;/span&gt;&lt;/span&gt;
86&lt;span id="cb6-3"&gt;&lt;a href="#cb6-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;out&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="va"&gt;$(&lt;/span&gt;&lt;span class="fu"&gt;git&lt;/span&gt; worktree list &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="ex"&gt;fzf&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt; &lt;span class="fu"&gt;awk&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{print $1}&amp;#39;&lt;/span&gt;&lt;span class="va"&gt;)&lt;/span&gt;&lt;/span&gt;
87&lt;span id="cb6-4"&gt;&lt;a href="#cb6-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;cd&lt;/span&gt; &lt;span class="va"&gt;$out&lt;/span&gt;&lt;/span&gt;
88&lt;span id="cb6-5"&gt;&lt;a href="#cb6-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
89&lt;p&gt;That is all of it really. Head into a git repository:&lt;/p&gt;
90&lt;div class="sourceCode" id="cb7"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb7-1"&gt;&lt;a href="#cb7-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# here, &amp;quot;master&amp;quot; is a directory, which contains my main&lt;/span&gt;&lt;/span&gt;
91&lt;span id="cb7-2"&gt;&lt;a href="#cb7-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# worktree: a checkout of the master branch on rust-lang/rust &lt;/span&gt;&lt;/span&gt;
92&lt;span id="cb7-3"&gt;&lt;a href="#cb7-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; cd ~/worktrees/rustc/master/library/core/src&lt;/span&gt;
93&lt;span id="cb7-4"&gt;&lt;a href="#cb7-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; &lt;span class="co"&gt;# hack away&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
94&lt;p&gt;Preferably one with a few worktrees:&lt;/p&gt;
95&lt;div class="sourceCode" id="cb8"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb8-1"&gt;&lt;a href="#cb8-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git worktree list&lt;/span&gt;
96&lt;span id="cb8-2"&gt;&lt;a href="#cb8-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/worktrees/rustc/master&lt;/span&gt; eac6c33bc63 [master]&lt;/span&gt;
97&lt;span id="cb8-3"&gt;&lt;a href="#cb8-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/worktrees/rustc/improve-std-char-docs&lt;/span&gt; 94cba88553e [improve-std-char-docs]&lt;/span&gt;
98&lt;span id="cb8-4"&gt;&lt;a href="#cb8-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;~/worktrees/rustc/is-ascii-octdigit&lt;/span&gt; bc57be3af7a [feature/is-ascii-octdigit]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
99&lt;p&gt;And hit &lt;code&gt;gwj&lt;/code&gt; (pretend that the pipe, |, is your cursor):&lt;/p&gt;
100&lt;div class="sourceCode" id="cb9"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb9-1"&gt;&lt;a href="#cb9-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; gwj&lt;/span&gt;
101&lt;span id="cb9-2"&gt;&lt;a href="#cb9-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt;&lt;/span&gt;
102&lt;span id="cb9-3"&gt;&lt;a href="#cb9-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;4/4&lt;/span&gt;&lt;/span&gt;
103&lt;span id="cb9-4"&gt;&lt;a href="#cb9-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; ~/worktrees/rustc/master &lt;span class="ex"&gt;eac6c33bc63&lt;/span&gt; [master]&lt;/span&gt;
104&lt;span id="cb9-5"&gt;&lt;a href="#cb9-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;~/worktrees/rustc/improve-std-char-docs&lt;/span&gt; 94cba88553e [improve-std-char-docs]&lt;/span&gt;
105&lt;span id="cb9-6"&gt;&lt;a href="#cb9-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;~/worktrees/rustc/is-ascii-octdigit&lt;/span&gt; bc57be3af7a [feature/is-ascii-octdigit]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
106&lt;p&gt;Approximately type in your branch of choice:&lt;/p&gt;
107&lt;div class="sourceCode" id="cb10"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb10-1"&gt;&lt;a href="#cb10-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; gwj&lt;/span&gt;
108&lt;span id="cb10-2"&gt;&lt;a href="#cb10-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; docs&lt;span class="kw"&gt;|&lt;/span&gt;&lt;/span&gt;
109&lt;span id="cb10-3"&gt;&lt;a href="#cb10-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;4/4&lt;/span&gt;&lt;/span&gt;
110&lt;span id="cb10-4"&gt;&lt;a href="#cb10-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; ~/worktrees/rustc/improve-std-char-docs &lt;span class="ex"&gt;94cba88553e&lt;/span&gt; [improve-std-char-docs]&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
111&lt;p&gt;And hit enter. You should find yourself in the selected worktree.&lt;/p&gt;
112&lt;p&gt;Onward, to the next fault, lack of preview-bility. We can utilize fzf’s aptly named &lt;code&gt;--preview&lt;/code&gt; flag, to, well, preview our worktree before performing a selection:&lt;/p&gt;
113&lt;div class="sourceCode" id="cb11"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb11-1"&gt;&lt;a href="#cb11-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;gwj ()&lt;/span&gt; &lt;span class="kw"&gt;{&lt;/span&gt;&lt;/span&gt;
114&lt;span id="cb11-2"&gt;&lt;a href="#cb11-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;local&lt;/span&gt; &lt;span class="va"&gt;out&lt;/span&gt;&lt;/span&gt;
115&lt;span id="cb11-3"&gt;&lt;a href="#cb11-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;out&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="va"&gt;$(&lt;/span&gt;&lt;/span&gt;
116&lt;span id="cb11-4"&gt;&lt;a href="#cb11-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="fu"&gt;git&lt;/span&gt; worktree list &lt;span class="kw"&gt;|&lt;/span&gt;&lt;/span&gt;
117&lt;span id="cb11-5"&gt;&lt;a href="#cb11-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;fzf&lt;/span&gt; &lt;span class="at"&gt;--preview&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;#39;git log --oneline -n10 {2}&amp;#39;&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt;&lt;/span&gt;
118&lt;span id="cb11-6"&gt;&lt;a href="#cb11-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="fu"&gt;awk&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{print $1}&amp;#39;&lt;/span&gt;&lt;/span&gt;
119&lt;span id="cb11-7"&gt;&lt;a href="#cb11-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;)&lt;/span&gt;&lt;/span&gt;
120&lt;span id="cb11-8"&gt;&lt;a href="#cb11-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;cd&lt;/span&gt; &lt;span class="va"&gt;$out&lt;/span&gt;&lt;/span&gt;
121&lt;span id="cb11-9"&gt;&lt;a href="#cb11-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
122&lt;p&gt;Once again, hit &lt;code&gt;gwj&lt;/code&gt; inside a git repository with linked worktrees:&lt;/p&gt;
123&lt;div class="sourceCode" id="cb12"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb12-1"&gt;&lt;a href="#cb12-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; gwj&lt;/span&gt;
124&lt;span id="cb12-2"&gt;&lt;a href="#cb12-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;╭─────────────────────────────────────────────────────────╮&lt;/span&gt;&lt;/span&gt;
125&lt;span id="cb12-3"&gt;&lt;a href="#cb12-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;│&lt;/span&gt; eac6c33bc63 Auto merge of 100869 nnethercote:replace... │&lt;/span&gt;
126&lt;span id="cb12-4"&gt;&lt;a href="#cb12-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;│&lt;/span&gt; b32223fec10 Auto merge of 100707 dzvon:fix-typo, r=d... │&lt;/span&gt;
127&lt;span id="cb12-5"&gt;&lt;a href="#cb12-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;│&lt;/span&gt; aa857eb953e Auto merge of 100537 petrochenkov:picche... │&lt;/span&gt;
128&lt;span id="cb12-6"&gt;&lt;a href="#cb12-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;│&lt;/span&gt; 3892b7074da Auto merge of 100210 mystor:proc_macro_d... │&lt;/span&gt;
129&lt;span id="cb12-7"&gt;&lt;a href="#cb12-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;│&lt;/span&gt; db00199d999 Auto merge of 101249 matthiaskrgr:rollup... │&lt;/span&gt;
130&lt;span id="cb12-8"&gt;&lt;a href="#cb12-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;│&lt;/span&gt; 14d216d33ba Rollup merge of 101240 JohnTitor:JohnTit... │&lt;/span&gt;
131&lt;span id="cb12-9"&gt;&lt;a href="#cb12-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;│&lt;/span&gt; 3da66f03531 Rollup merge of 101236 thomcc:winfs-noze... │&lt;/span&gt;
132&lt;span id="cb12-10"&gt;&lt;a href="#cb12-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;│&lt;/span&gt; 0620f6e90af Rollup merge of 101230 davidtwco:transla... │&lt;/span&gt;
133&lt;span id="cb12-11"&gt;&lt;a href="#cb12-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;│&lt;/span&gt; c30c42ee299 Rollup merge of 101229 mgeisler:link-try... │&lt;/span&gt;
134&lt;span id="cb12-12"&gt;&lt;a href="#cb12-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;│&lt;/span&gt; e5356712b9e Rollup merge of 101165 ldm0:drain_to_ite... │&lt;/span&gt;
135&lt;span id="cb12-13"&gt;&lt;a href="#cb12-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;╰─────────────────────────────────────────────────────────╯&lt;/span&gt;&lt;/span&gt;
136&lt;span id="cb12-14"&gt;&lt;a href="#cb12-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
137&lt;span id="cb12-15"&gt;&lt;a href="#cb12-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;4/4&lt;/span&gt;&lt;/span&gt;
138&lt;span id="cb12-16"&gt;&lt;a href="#cb12-16" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; /home/np/worktrees/compiler/master &lt;span class="ex"&gt;eac6c...&lt;/span&gt;&lt;/span&gt;
139&lt;span id="cb12-17"&gt;&lt;a href="#cb12-17" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;/home/np/worktrees/compiler/improve-std-char-docs&lt;/span&gt; 94cba...&lt;/span&gt;
140&lt;span id="cb12-18"&gt;&lt;a href="#cb12-18" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;/home/np/worktrees/compiler/is-ascii-octdigit&lt;/span&gt; bc57b...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
141&lt;p&gt;A fancy preview of the last 10 commits on the branch that the selected worktree corresponds to. In other words, sight for sore eyes. Our little script is already shaping up to be useful, you hit &lt;code&gt;gwj&lt;/code&gt;, browse through your worktrees, preview each one and automatically &lt;code&gt;cd&lt;/code&gt; to your selection. But we are not done yet.&lt;/p&gt;
142&lt;p&gt;The last fault was lack shell completions. A quick review of what a shell completion really does:&lt;/p&gt;
143&lt;div class="sourceCode" id="cb13"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb13-1"&gt;&lt;a href="#cb13-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git checkout f&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;tab&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
144&lt;span id="cb13-2"&gt;&lt;a href="#cb13-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;feature/is-ascii-octdigit&lt;/span&gt;&lt;/span&gt;
145&lt;span id="cb13-3"&gt;&lt;a href="#cb13-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;fix/some-error&lt;/span&gt;&lt;/span&gt;
146&lt;span id="cb13-4"&gt;&lt;a href="#cb13-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;format-doc-tests&lt;/span&gt;&lt;/span&gt;
147&lt;span id="cb13-5"&gt;&lt;a href="#cb13-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
148&lt;span id="cb13-6"&gt;&lt;a href="#cb13-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git checkout feat&lt;span class="op"&gt;&amp;lt;&lt;/span&gt;tab&lt;span class="op"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;
149&lt;span id="cb13-7"&gt;&lt;a href="#cb13-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
150&lt;span id="cb13-8"&gt;&lt;a href="#cb13-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; git checkout feature/is-ascii-octdigit&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
151&lt;p&gt;Each time you hit “tab”, the shell produces a few “completion candidates”, and once you have just a single candidate left, the shell inserts that for you directly into your edit line. Of course, this process varies from shell to shell.&lt;/p&gt;
152&lt;p&gt;fzf narrows down your options as you type into the prompt, but you still have to:&lt;/p&gt;
153&lt;ol type="1"&gt;
154&lt;li&gt;Type &lt;code&gt;gwj&lt;/code&gt;&lt;/li&gt;
155&lt;li&gt;Hit enter&lt;/li&gt;
156&lt;li&gt;Type out a query and narrow down your search&lt;/li&gt;
157&lt;li&gt;Hit enter&lt;/li&gt;
158&lt;/ol&gt;
159&lt;p&gt;We can speed that up a bit, have fzf narrow down the candidates on startup, just like our shell does:&lt;/p&gt;
160&lt;div class="sourceCode" id="cb14"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb14-1"&gt;&lt;a href="#cb14-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="fu"&gt;gwj ()&lt;/span&gt; &lt;span class="kw"&gt;{&lt;/span&gt;&lt;/span&gt;
161&lt;span id="cb14-2"&gt;&lt;a href="#cb14-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;local&lt;/span&gt; &lt;span class="va"&gt;out&lt;/span&gt; &lt;span class="va"&gt;query&lt;/span&gt;&lt;/span&gt;
162&lt;span id="cb14-3"&gt;&lt;a href="#cb14-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;query&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;${1&lt;/span&gt;&lt;span class="op"&gt;:-&lt;/span&gt; &lt;span class="va"&gt;}&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
163&lt;span id="cb14-4"&gt;&lt;a href="#cb14-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;out&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="va"&gt;$(&lt;/span&gt;&lt;/span&gt;
164&lt;span id="cb14-5"&gt;&lt;a href="#cb14-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="fu"&gt;git&lt;/span&gt; worktree list &lt;span class="kw"&gt;|&lt;/span&gt;&lt;/span&gt;
165&lt;span id="cb14-6"&gt;&lt;a href="#cb14-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;fzf&lt;/span&gt; &lt;span class="at"&gt;--preview&lt;/span&gt;&lt;span class="op"&gt;=&lt;/span&gt;&lt;span class="st"&gt;&amp;#39;git log --oneline -n10 {2}&amp;#39;&lt;/span&gt; &lt;span class="at"&gt;--query&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$query&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; &lt;span class="at"&gt;-1&lt;/span&gt; &lt;span class="kw"&gt;|&lt;/span&gt;&lt;/span&gt;
166&lt;span id="cb14-7"&gt;&lt;a href="#cb14-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="fu"&gt;awk&lt;/span&gt; &lt;span class="st"&gt;&amp;#39;{print $1}&amp;#39;&lt;/span&gt;&lt;/span&gt;
167&lt;span id="cb14-8"&gt;&lt;a href="#cb14-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="va"&gt;)&lt;/span&gt;&lt;/span&gt;
168&lt;span id="cb14-9"&gt;&lt;a href="#cb14-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="bu"&gt;cd&lt;/span&gt; &lt;span class="va"&gt;$out&lt;/span&gt;&lt;/span&gt;
169&lt;span id="cb14-10"&gt;&lt;a href="#cb14-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
170&lt;p&gt;The change is extremely tiny, blink-and-you’ll-miss-it kinda tiny. We added a little &lt;code&gt;--query&lt;/code&gt; flag, that allows you to prefill the prompt, and the &lt;code&gt;-1&lt;/code&gt; flag, that avoids the interactive finder if only one match exists on startup:&lt;/p&gt;
171&lt;div class="sourceCode" id="cb15"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb15-1"&gt;&lt;a href="#cb15-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# skip through the fzf prompt:&lt;/span&gt;&lt;/span&gt;
172&lt;span id="cb15-2"&gt;&lt;a href="#cb15-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; gwj master&lt;/span&gt;
173&lt;span id="cb15-3"&gt;&lt;a href="#cb15-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# cd -- ~/worktrees/rustc/master&lt;/span&gt;&lt;/span&gt;
174&lt;span id="cb15-4"&gt;&lt;a href="#cb15-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
175&lt;span id="cb15-5"&gt;&lt;a href="#cb15-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# more than one option, we end up in the interactive finder&lt;/span&gt;&lt;/span&gt;
176&lt;span id="cb15-6"&gt;&lt;a href="#cb15-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;λ&lt;/span&gt; gwj improve&lt;/span&gt;
177&lt;span id="cb15-7"&gt;&lt;a href="#cb15-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;╭─────────────────────────────────────────────────────────╮&lt;/span&gt;&lt;/span&gt;
178&lt;span id="cb15-8"&gt;&lt;a href="#cb15-8" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;│&lt;/span&gt; eac6c33bc63 Auto merge of 100869 nnethercote:replace... │&lt;/span&gt;
179&lt;span id="cb15-9"&gt;&lt;a href="#cb15-9" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;│&lt;/span&gt; b32223fec10 Auto merge of 100707 dzvon:fix-typo, r=d... │&lt;/span&gt;
180&lt;span id="cb15-10"&gt;&lt;a href="#cb15-10" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;│&lt;/span&gt; aa857eb953e Auto merge of 100537 petrochenkov:picche... │&lt;/span&gt;
181&lt;span id="cb15-11"&gt;&lt;a href="#cb15-11" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="ex"&gt;╰─────────────────────────────────────────────────────────╯&lt;/span&gt;&lt;/span&gt;
182&lt;span id="cb15-12"&gt;&lt;a href="#cb15-12" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; improve&lt;/span&gt;
183&lt;span id="cb15-13"&gt;&lt;a href="#cb15-13" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;2/2&lt;/span&gt;&lt;/span&gt;
184&lt;span id="cb15-14"&gt;&lt;a href="#cb15-14" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="op"&gt;&amp;gt;&lt;/span&gt; /home/np/worktrees/compiler/improve-const-perf &lt;span class="ex"&gt;eac6c...&lt;/span&gt;&lt;/span&gt;
185&lt;span id="cb15-15"&gt;&lt;a href="#cb15-15" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="ex"&gt;/home/np/worktrees/compiler/improve-std-char-docs&lt;/span&gt; 94cba...&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
186&lt;p&gt;Throw some error handling in there, hook up a similar script to improve the UX of &lt;code&gt;git worktree remove&lt;/code&gt;, go wild. A few more helpers I’ve got:&lt;/p&gt;
187&lt;div class="sourceCode" id="cb16"&gt;&lt;pre class="sourceCode bash"&gt;&lt;code class="sourceCode bash"&gt;&lt;span id="cb16-1"&gt;&lt;a href="#cb16-1" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# gwa /path/to/branch-name&lt;/span&gt;&lt;/span&gt;
188&lt;span id="cb16-2"&gt;&lt;a href="#cb16-2" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="co"&gt;# creates a new branch and &amp;quot;switches&amp;quot; to it&lt;/span&gt;&lt;/span&gt;
189&lt;span id="cb16-3"&gt;&lt;a href="#cb16-3" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;function&lt;/span&gt;&lt;span class="fu"&gt; gwa ()&lt;/span&gt; &lt;span class="kw"&gt;{&lt;/span&gt;&lt;/span&gt;
190&lt;span id="cb16-4"&gt;&lt;a href="#cb16-4" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt; &lt;span class="fu"&gt;git&lt;/span&gt; worktree add &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$1&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt; &lt;span class="kw"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="bu"&gt;cd&lt;/span&gt; &lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;span class="va"&gt;$1&lt;/span&gt;&lt;span class="st"&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
191&lt;span id="cb16-5"&gt;&lt;a href="#cb16-5" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="kw"&gt;}&lt;/span&gt;&lt;/span&gt;
192&lt;span id="cb16-6"&gt;&lt;a href="#cb16-6" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;/span&gt;
193&lt;span id="cb16-7"&gt;&lt;a href="#cb16-7" aria-hidden="true" tabindex="-1"&gt;&lt;/a&gt;&lt;span class="bu"&gt;alias&lt;/span&gt; gwls=&lt;span class="st"&gt;&amp;quot;git worktree list&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</description>
194<link>https://peppe.rs/posts/curing_a_case_of_git-UX/</link>
195<pubDate>Sat, 03 Sep 2022 03:18:00 +0000</pubDate>
196<guid>https://peppe.rs/posts/curing_a_case_of_git-UX/</guid>
197</item>
198<item>
15<title>Programming On 34 Keys</title> 199<title>Programming On 34 Keys</title>
16<description>&lt;p&gt;Minimizing your keyboard layout is a slippery slope. A few months ago, I built the &lt;a href="https://github.com/icyphox/ferricy"&gt;Ferricy&lt;/a&gt;, a 34-key-split-ortho-ergo keyboard. The Ferricy is a fork of the &lt;a href="https://github.com/davidphilipbarr/Sweep/tree/main/Sweep%20Bling%20MX"&gt;Ferris Sweep MX Bling&lt;/a&gt;.&lt;/p&gt; 200<description>&lt;p&gt;Minimizing your keyboard layout is a slippery slope. A few months ago, I built the &lt;a href="https://github.com/icyphox/ferricy"&gt;Ferricy&lt;/a&gt;, a 34-key-split-ortho-ergo keyboard. The Ferricy is a fork of the &lt;a href="https://github.com/davidphilipbarr/Sweep/tree/main/Sweep%20Bling%20MX"&gt;Ferris Sweep MX Bling&lt;/a&gt;.&lt;/p&gt;
17&lt;figure&gt; 201&lt;figure&gt;
diff --git a/docs/posts/curing_a_case_of_git-UX/index.html b/docs/posts/curing_a_case_of_git-UX/index.html
new file mode 100644
index 0000000..9c4761c
--- /dev/null
+++ b/docs/posts/curing_a_case_of_git-UX/index.html
@@ -0,0 +1,253 @@
1<!DOCTYPE html>
2<html lang="en">
3 <head>
4 <link rel="stylesheet" href="/style.css">
5 <link rel="stylesheet" href="/syntax.css">
6 <meta charset="UTF-8">
7 <meta name="viewport" content="initial-scale=1">
8 <meta content="#ffffff" name="theme-color">
9 <meta name="HandheldFriendly" content="true">
10 <meta property="og:title" content="Curing A Case Of Git-UX">
11 <meta property="og:type" content="website">
12 <meta property="og:description" content="a static site {for, by, about} me ">
13 <meta property="og:url" content="https://peppe.rs">
14 <link rel="icon" type="image/x-icon" href="/favicon.png">
15 <title>Curing A Case Of Git-UX · peppe.rs</title>
16 <body>
17 <div class="posts">
18 <div class="post">
19 <a href="/" class="post-end-link">Home</a>
20 <span>/</span>
21 <a href="/posts" class="post-end-link">Posts</a>
22 <span>/</span>
23 <a class="post-end-link">Curing A Case Of Git-UX</a>
24 <a class="stats post-end-link" href="https://git.peppe.rs/web/site/plain/posts/curing_a_case_of_git-UX.md
25">View Raw</a>
26 <div class="separator"></div>
27 <div class="date">
28 03/09 — 2022
29 <div class="stats">
30 <span class="stats-number">
31 127.87
32 </span>
33 <span class="stats-unit">cm</span>
34 &nbsp
35 <span class="stats-number">
36 9.5
37 </span>
38 <span class="stats-unit">min</span>
39 </div>
40 </div>
41 <h1>
42 Curing A Case Of Git-UX
43 </h1>
44 <div class="post-text">
45 <p>Git worktrees are great, but they fall behind the venerable <code>git checkout</code> sometimes. I attempted to fix that with <a href="https://github.com/junegunn/fzf">fzf</a> and a bit of bash.</p>
46<p><a href="https://asciinema.org/a/D297ztKRzpE4gAHbPTPmkqYps"><img src="https://asciinema.org/a/D297ztKRzpE4gAHbPTPmkqYps.svg" /></a></p>
47<p>Fear not if you haven’t heard of “worktrees”, I have included a primer here.<br />
48<a href="#what-makes-them-clunky">Skip the primer -&gt;</a>.</p>
49<h3 id="why-worktrees">Why Worktrees?</h3>
50<p>Picture this. You are whacking away on a feature branch. Halfway there, in fact. Your friend asks you fix something urgently. You proceed to do one of three things:</p>
51<ul>
52<li>create a temporary branch, make a WIP commit, begin working on the fix</li>
53<li>stash away your changes, begin working on the fix</li>
54<li>unfriend said friend for disturbing your flow</li>
55</ul>
56<p>All of these options are … subpar. With the temporary branch, you are forced to create a partial, non-working commit, and then reset said commit once done with the fix. With the stash approach, you are required to now keep a mental model of the stash, be aware of untracked files that don’t get stashed by default, etc. Why won’t git just let you work on two things at the same time without <em>thinking</em> so much?</p>
57<p>That is exactly what worktrees let you do. Worktrees let you have more than one checkout at a time, each checkout in a separate directory. Like creating a new clone, but safer (it disallows checking out the same branch twice) and a lot more space efficient (the new working tree is “linked” to the “main” worktree, and a good amount of stuff is shared). When your friend asks you to make the fix, you proceed like so:</p>
58<ol type="1">
59<li>Create a new working tree with:</li>
60</ol>
61<div class="sourceCode" id="cb1"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co"># git worktree add -b &lt;branch-name&gt; &lt;path&gt; &lt;from&gt;</span></span>
62<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="fu">git</span> worktree add <span class="at">-b</span> fix-stuff /path/to/tree master</span></code></pre></div>
63<ol start="2" type="1">
64<li><code>cd</code> into <code>/path/to/tree</code></li>
65<li>Fix, test, commit, push, party</li>
66<li>Go back to your work, <code>cd -</code></li>
67</ol>
68<p>Easy as cake. You didn’t have to settle for a partially working commit, you didn’t to deal with this “stash” thing, <em>and</em> you didn’t have to unfriend your friend. Treating each branch as a directory just <em>feels</em> more intuitive, more UNIX-y.</p>
69<p>A few weeks later, you find yourself singing in praise of worktrees, working on several things simultaneously. And at the same time, cursing them for being a little … clunky.</p>
70<h3 id="what-makes-them-clunky">What makes them clunky?</h3>
71<p>Worktrees are great at what they claim to do. They stay out of the way when you need a checkout posthaste. However, as you start using them regularly, you realize they are not as flexible as <code>git checkout</code> or <code>git switch</code>.</p>
72<h4 id="branch-hopping">Branch-hopping</h4>
73<p>You can <code>git checkout &lt;branch&gt;</code> from anywhere within a git repository. You can’t “jump” to a worktree in the same fashion. The closest you can get, is to run <code>git worktree list</code>, copy the path corresponding to your branch, and <code>cd</code> into it.</p>
74<p>Branch-hopping with the good ol’ git-checkout:</p>
75<div class="sourceCode" id="cb2"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="co"># anywhere, anytime</span></span>
76<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout feature/is-ascii-octdigit</span></code></pre></div>
77<p>Meanwhile, in worktree world:</p>
78<div class="sourceCode" id="cb3"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co"># keeping these paths in your head is hard</span></span>
79<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git worktree list</span>
80<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/master</span> eac6c33bc63 [master]</span>
81<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/improve-std-char-docs</span> 94cba88553e [improve-std-char-docs]</span>
82<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/is-ascii-octdigit</span> bc57be3af7a [feature/is-ascii-octdigit]</span>
83<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="ex">~/my/other/path/oh/god</span> op57or3ns7n [fix/some-error]</span>
84<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a></span>
85<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> cd ~/worktrees/rustc/is-ascii-octdigit</span></code></pre></div>
86<h4 id="branch-previewing">Branch-previewing</h4>
87<p>You can “preview” branches with <code>git branch -v</code>. However, to get an idea of what “recent activity” on a worktree looks like, you might need some juggling. You can’t glean much info about a worktree in a jiffy.</p>
88<p>Branch-previewing with the good ol’ git-branch:</p>
89<div class="sourceCode" id="cb4"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git branch <span class="at">-v</span></span>
90<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="ex">+</span> feature/is-ascii-octdigit bc57be3af7a introduce {char, u8}::is_ ...</span>
91<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a><span class="ex">+</span> improve-std-char-docs 94cba88553e add whitespace in assert ...</span>
92<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="ex">*</span> master eac6c33bc63 Auto merge of <span class="co">#100869 - n ...</span></span></code></pre></div>
93<p>Meanwhile in worktree wonderland:</p>
94<pre><code>λ git worktree list
95~/worktrees/rustc/master eac6c33bc63 [master]
96~/worktrees/rustc/improve-std-char-docs 94cba88553e [improve-std-char-docs]
97~/worktrees/rustc/is-ascii-octdigit bc57be3af7a [feature/is-ascii-octdigit]
98
99# aha, so ../is-ascii-octdigit corresponds to `feature/is-ascii-octdigit`
100λ git log feature/is-ascii-octdigit
101bc57be3af7a introduce {char, u8}::is_ascii_octdigit
102eac6c33bc63 Auto merge of #100869 - nnethercote:repl ...
103b32223fec10 Auto merge of #100707 - dzvon:fix-typo, ...
104aa857eb953e Auto merge of #100537 - petrochenkov:pic ...
105
106# extra work to make the branch &lt;-&gt; worktree correspondence</code></pre>
107<h4 id="shell-completions">Shell completions</h4>
108<p>Lastly, you can bank on shell completions to fill in your branch whilst using <code>git checkout</code>. Worktrees have no such conveniences.</p>
109<p>We can mend these minor faults with fzf.</p>
110<h3 id="unclunkifying-worktrees">Unclunkifying worktrees</h3>
111<p>I’d suggest looking up <a href="https://github.com/junegunn/fzf">fzf</a> (or <a href="https://github.com/lotabout/skim">skim</a> or <a href="https://github.com/jhawthorn/fzy">fzy</a>). These things make it cake-easy to add interactivity to your shell. Onto fixing the first minor fault, the inability to “jump” to a worktree from anywhere within a git repository.</p>
112<p>I have a little function called <code>gwj</code> which stands for “git worktree jump”. The idea is to list all the worktrees, select one with fzf, and <code>cd</code> to it upon selection:</p>
113<div class="sourceCode" id="cb6"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="fu">gwj ()</span> <span class="kw">{</span></span>
114<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">local</span> <span class="va">out</span></span>
115<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a> <span class="va">out</span><span class="op">=</span><span class="va">$(</span><span class="fu">git</span> worktree list <span class="kw">|</span> <span class="ex">fzf</span> <span class="kw">|</span> <span class="fu">awk</span> <span class="st">&#39;{print $1}&#39;</span><span class="va">)</span></span>
116<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a> <span class="bu">cd</span> <span class="va">$out</span></span>
117<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre></div>
118<p>That is all of it really. Head into a git repository:</p>
119<div class="sourceCode" id="cb7"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="co"># here, &quot;master&quot; is a directory, which contains my main</span></span>
120<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="co"># worktree: a checkout of the master branch on rust-lang/rust </span></span>
121<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> cd ~/worktrees/rustc/master/library/core/src</span>
122<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> <span class="co"># hack away</span></span></code></pre></div>
123<p>Preferably one with a few worktrees:</p>
124<div class="sourceCode" id="cb8"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git worktree list</span>
125<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/master</span> eac6c33bc63 [master]</span>
126<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/improve-std-char-docs</span> 94cba88553e [improve-std-char-docs]</span>
127<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/is-ascii-octdigit</span> bc57be3af7a [feature/is-ascii-octdigit]</span></code></pre></div>
128<p>And hit <code>gwj</code> (pretend that the pipe, |, is your cursor):</p>
129<div class="sourceCode" id="cb9"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj</span>
130<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> <span class="kw">|</span></span>
131<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a> <span class="ex">4/4</span></span>
132<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> ~/worktrees/rustc/master <span class="ex">eac6c33bc63</span> [master]</span>
133<span id="cb9-5"><a href="#cb9-5" aria-hidden="true" tabindex="-1"></a> <span class="ex">~/worktrees/rustc/improve-std-char-docs</span> 94cba88553e [improve-std-char-docs]</span>
134<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a> <span class="ex">~/worktrees/rustc/is-ascii-octdigit</span> bc57be3af7a [feature/is-ascii-octdigit]</span></code></pre></div>
135<p>Approximately type in your branch of choice:</p>
136<div class="sourceCode" id="cb10"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj</span>
137<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> docs<span class="kw">|</span></span>
138<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> <span class="ex">4/4</span></span>
139<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> ~/worktrees/rustc/improve-std-char-docs <span class="ex">94cba88553e</span> [improve-std-char-docs]</span></code></pre></div>
140<p>And hit enter. You should find yourself in the selected worktree.</p>
141<p>Onward, to the next fault, lack of preview-bility. We can utilize fzf’s aptly named <code>--preview</code> flag, to, well, preview our worktree before performing a selection:</p>
142<div class="sourceCode" id="cb11"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="fu">gwj ()</span> <span class="kw">{</span></span>
143<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">local</span> <span class="va">out</span></span>
144<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a> <span class="va">out</span><span class="op">=</span><span class="va">$(</span></span>
145<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">git</span> worktree list <span class="kw">|</span></span>
146<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a> <span class="ex">fzf</span> <span class="at">--preview</span><span class="op">=</span><span class="st">&#39;git log --oneline -n10 {2}&#39;</span> <span class="kw">|</span></span>
147<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a> <span class="fu">awk</span> <span class="st">&#39;{print $1}&#39;</span></span>
148<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a> <span class="va">)</span></span>
149<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a> <span class="bu">cd</span> <span class="va">$out</span></span>
150<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre></div>
151<p>Once again, hit <code>gwj</code> inside a git repository with linked worktrees:</p>
152<div class="sourceCode" id="cb12"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj</span>
153<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="ex">╭─────────────────────────────────────────────────────────╮</span></span>
154<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> eac6c33bc63 Auto merge of 100869 nnethercote:replace... │</span>
155<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> b32223fec10 Auto merge of 100707 dzvon:fix-typo, r=d... │</span>
156<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> aa857eb953e Auto merge of 100537 petrochenkov:picche... │</span>
157<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> 3892b7074da Auto merge of 100210 mystor:proc_macro_d... │</span>
158<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> db00199d999 Auto merge of 101249 matthiaskrgr:rollup... │</span>
159<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> 14d216d33ba Rollup merge of 101240 JohnTitor:JohnTit... │</span>
160<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> 3da66f03531 Rollup merge of 101236 thomcc:winfs-noze... │</span>
161<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> 0620f6e90af Rollup merge of 101230 davidtwco:transla... │</span>
162<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> c30c42ee299 Rollup merge of 101229 mgeisler:link-try... │</span>
163<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> e5356712b9e Rollup merge of 101165 ldm0:drain_to_ite... │</span>
164<span id="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a><span class="ex">╰─────────────────────────────────────────────────────────╯</span></span>
165<span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span></span>
166<span id="cb12-15"><a href="#cb12-15" aria-hidden="true" tabindex="-1"></a> <span class="ex">4/4</span></span>
167<span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> /home/np/worktrees/compiler/master <span class="ex">eac6c...</span></span>
168<span id="cb12-17"><a href="#cb12-17" aria-hidden="true" tabindex="-1"></a> <span class="ex">/home/np/worktrees/compiler/improve-std-char-docs</span> 94cba...</span>
169<span id="cb12-18"><a href="#cb12-18" aria-hidden="true" tabindex="-1"></a> <span class="ex">/home/np/worktrees/compiler/is-ascii-octdigit</span> bc57b...</span></code></pre></div>
170<p>A fancy preview of the last 10 commits on the branch that the selected worktree corresponds to. In other words, sight for sore eyes. Our little script is already shaping up to be useful, you hit <code>gwj</code>, browse through your worktrees, preview each one and automatically <code>cd</code> to your selection. But we are not done yet.</p>
171<p>The last fault was lack shell completions. A quick review of what a shell completion really does:</p>
172<div class="sourceCode" id="cb13"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout f<span class="op">&lt;</span>tab<span class="op">&gt;</span></span>
173<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="ex">feature/is-ascii-octdigit</span></span>
174<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="ex">fix/some-error</span></span>
175<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="ex">format-doc-tests</span></span>
176<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a></span>
177<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout feat<span class="op">&lt;</span>tab<span class="op">&gt;</span></span>
178<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a></span>
179<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout feature/is-ascii-octdigit</span></code></pre></div>
180<p>Each time you hit “tab”, the shell produces a few “completion candidates”, and once you have just a single candidate left, the shell inserts that for you directly into your edit line. Of course, this process varies from shell to shell.</p>
181<p>fzf narrows down your options as you type into the prompt, but you still have to:</p>
182<ol type="1">
183<li>Type <code>gwj</code></li>
184<li>Hit enter</li>
185<li>Type out a query and narrow down your search</li>
186<li>Hit enter</li>
187</ol>
188<p>We can speed that up a bit, have fzf narrow down the candidates on startup, just like our shell does:</p>
189<div class="sourceCode" id="cb14"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="fu">gwj ()</span> <span class="kw">{</span></span>
190<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">local</span> <span class="va">out</span> <span class="va">query</span></span>
191<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a> <span class="va">query</span><span class="op">=</span><span class="st">&quot;</span><span class="va">${1</span><span class="op">:-</span> <span class="va">}</span><span class="st">&quot;</span></span>
192<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a> <span class="va">out</span><span class="op">=</span><span class="va">$(</span></span>
193<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a> <span class="fu">git</span> worktree list <span class="kw">|</span></span>
194<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a> <span class="ex">fzf</span> <span class="at">--preview</span><span class="op">=</span><span class="st">&#39;git log --oneline -n10 {2}&#39;</span> <span class="at">--query</span> <span class="st">&quot;</span><span class="va">$query</span><span class="st">&quot;</span> <span class="at">-1</span> <span class="kw">|</span></span>
195<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a> <span class="fu">awk</span> <span class="st">&#39;{print $1}&#39;</span></span>
196<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a> <span class="va">)</span></span>
197<span id="cb14-9"><a href="#cb14-9" aria-hidden="true" tabindex="-1"></a> <span class="bu">cd</span> <span class="va">$out</span></span>
198<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre></div>
199<p>The change is extremely tiny, blink-and-you’ll-miss-it kinda tiny. We added a little <code>--query</code> flag, that allows you to prefill the prompt, and the <code>-1</code> flag, that avoids the interactive finder if only one match exists on startup:</p>
200<div class="sourceCode" id="cb15"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="co"># skip through the fzf prompt:</span></span>
201<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj master</span>
202<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="co"># cd -- ~/worktrees/rustc/master</span></span>
203<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a></span>
204<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a><span class="co"># more than one option, we end up in the interactive finder</span></span>
205<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj improve</span>
206<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a><span class="ex">╭─────────────────────────────────────────────────────────╮</span></span>
207<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> eac6c33bc63 Auto merge of 100869 nnethercote:replace... │</span>
208<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> b32223fec10 Auto merge of 100707 dzvon:fix-typo, r=d... │</span>
209<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a><span class="ex">│</span> aa857eb953e Auto merge of 100537 petrochenkov:picche... │</span>
210<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a><span class="ex">╰─────────────────────────────────────────────────────────╯</span></span>
211<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> improve</span>
212<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a> <span class="ex">2/2</span></span>
213<span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a><span class="op">&gt;</span> /home/np/worktrees/compiler/improve-const-perf <span class="ex">eac6c...</span></span>
214<span id="cb15-15"><a href="#cb15-15" aria-hidden="true" tabindex="-1"></a> <span class="ex">/home/np/worktrees/compiler/improve-std-char-docs</span> 94cba...</span></code></pre></div>
215<p>Throw some error handling in there, hook up a similar script to improve the UX of <code>git worktree remove</code>, go wild. A few more helpers I’ve got:</p>
216<div class="sourceCode" id="cb16"><pre class="sourceCode bash"><code class="sourceCode bash"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a><span class="co"># gwa /path/to/branch-name</span></span>
217<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="co"># creates a new branch and &quot;switches&quot; to it</span></span>
218<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a><span class="kw">function</span><span class="fu"> gwa ()</span> <span class="kw">{</span></span>
219<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">git</span> worktree add <span class="st">&quot;</span><span class="va">$1</span><span class="st">&quot;</span> <span class="kw">&amp;&amp;</span> <span class="bu">cd</span> <span class="st">&quot;</span><span class="va">$1</span><span class="st">&quot;</span></span>
220<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span>
221<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a></span>
222<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a><span class="bu">alias</span> gwls=<span class="st">&quot;git worktree list&quot;</span></span></code></pre></div>
223
224 </div>
225
226 <div class="intro">
227 Hi.
228 <div class="hot-links">
229 <a href="https://peppe.rs/index.xml" class="feed-button">Subscribe</a>
230 <a href="https://liberapay.com/nerdypepper/donate" class="donate-button">Donate</a>
231 </div>
232 <p>I'm Akshay, I go by nerd or nerdypepper on the internet.</p>
233 <p>
234 I am a compsci undergrad, Rust programmer and an enthusiastic Vimmer.
235 I write <a href="https://git.peppe.rs">open-source stuff</a> to pass time.
236 I also design fonts:
237 <a href="https://git.peppe.rs/fonts/scientifica">scientifica</a>,
238 <a href="https://git.peppe.rs/fonts/curie">curie</a>.
239 </p>
240 <p>Send me a mail at [email protected] or a message at [email protected].</p>
241 </div>
242
243 <a href="/" class="post-end-link">Home</a>
244 <span>/</span>
245 <a href="/posts" class="post-end-link">Posts</a>
246 <span>/</span>
247 <a class="post-end-link">Curing A Case Of Git-UX</a>
248 <a class="stats post-end-link" href="https://git.peppe.rs/web/site/plain/posts/curing_a_case_of_git-UX.md
249">View Raw</a>
250 </div>
251 </div>
252 </body>
253</html>
diff --git a/docs/posts/index.html b/docs/posts/index.html
index c211d3b..48452c0 100644
--- a/docs/posts/index.html
+++ b/docs/posts/index.html
@@ -27,6 +27,23 @@
27 <tr> 27 <tr>
28 <td class=table-post> 28 <td class=table-post>
29 <div class="date"> 29 <div class="date">
30 03/09 — 2022
31 </div>
32 <a href="/posts/curing_a_case_of_git-UX" class="post-link">
33 <span class="post-link">Curing A Case Of Git-UX</span>
34 </a>
35 </td>
36 <td class=table-stats>
37 <span class="stats-number">
38 9.5
39 </span>
40 <span class=stats-unit>min</span>
41 </td>
42 </tr>
43
44 <tr>
45 <td class=table-post>
46 <div class="date">
30 28/08 — 2022 47 28/08 — 2022
31 </div> 48 </div>
32 <a href="/posts/programming_on_34_keys" class="post-link"> 49 <a href="/posts/programming_on_34_keys" class="post-link">
diff --git a/posts/curing_a_case_of_git-UX.md b/posts/curing_a_case_of_git-UX.md
new file mode 100644
index 0000000..556df1b
--- /dev/null
+++ b/posts/curing_a_case_of_git-UX.md
@@ -0,0 +1,320 @@
1Git worktrees are great, but they fall behind the venerable
2`git checkout` sometimes. I attempted to fix that with
3[fzf](https://github.com/junegunn/fzf) and
4a bit of bash.
5
6[![](https://asciinema.org/a/D297ztKRzpE4gAHbPTPmkqYps.svg)](https://asciinema.org/a/D297ztKRzpE4gAHbPTPmkqYps)
7
8Fear not if you haven't heard of "worktrees", I have
9included a primer here.
10[Skip the primer
11->](#what-makes-them-clunky).
12
13### Why Worktrees?
14
15Picture this. You are whacking away on a feature branch.
16Halfway there, in fact. Your friend asks you fix something
17urgently. You proceed to do one of three things:
18
19- create a temporary branch, make a WIP commit, begin
20 working on the fix
21- stash away your changes, begin working on the fix
22- unfriend said friend for disturbing your flow
23
24All of these options are ... subpar. With the temporary
25branch, you are forced to create a partial, non-working
26commit, and then reset said commit once done with the fix.
27With the stash approach, you are required to now keep a
28mental model of the stash, be aware of untracked files that
29don't get stashed by default, etc. Why won't git just let
30you work on two things at the same time without _thinking_
31so much?
32
33That is exactly what worktrees let you do. Worktrees let you
34have more than one checkout at a time, each checkout in a
35separate directory. Like creating a new clone, but safer (it
36disallows checking out the same branch twice) and a lot more
37space efficient (the new working tree is "linked" to the
38"main" worktree, and a good amount of stuff is shared). When
39your friend asks you to make the fix, you proceed like so:
40
411. Create a new working tree with:
42 ```bash
43 # git worktree add -b <branch-name> <path> <from>
44 git worktree add -b fix-stuff /path/to/tree master
45 ```
462. `cd` into `/path/to/tree`
473. Fix, test, commit, push, party
484. Go back to your work, `cd -`
49
50Easy as cake. You didn't have to settle for a partially
51working commit, you didn't to deal with this "stash" thing,
52_and_ you didn't have to unfriend your friend. Treating each
53branch as a directory just _feels_ more intuitive, more
54UNIX-y.
55
56A few weeks later, you find yourself singing in praise of
57worktrees, working on several things simultaneously. And at
58the same time, cursing them for being a little ... clunky.
59
60### What makes them clunky?
61
62Worktrees are great at what they claim to do. They stay out
63of the way when you need a checkout posthaste. However, as
64you start using them regularly, you realize they are not as
65flexible as `git checkout` or `git switch`.
66
67#### Branch-hopping
68You can `git checkout <branch>` from anywhere within a git
69repository. You can't "jump" to a worktree in the same
70fashion. The closest you can get, is to run `git worktree
71list`, copy the path corresponding to your branch, and `cd`
72into it.
73
74Branch-hopping with the good ol' git-checkout:
75```bash
76# anywhere, anytime
77λ git checkout feature/is-ascii-octdigit
78```
79
80Meanwhile, in worktree world:
81```bash
82# keeping these paths in your head is hard
83λ git worktree list
84~/worktrees/rustc/master eac6c33bc63 [master]
85~/worktrees/rustc/improve-std-char-docs 94cba88553e [improve-std-char-docs]
86~/worktrees/rustc/is-ascii-octdigit bc57be3af7a [feature/is-ascii-octdigit]
87~/my/other/path/oh/god op57or3ns7n [fix/some-error]
88
89λ cd ~/worktrees/rustc/is-ascii-octdigit
90```
91
92#### Branch-previewing
93
94You can "preview" branches with `git branch -v`. However, to
95get an idea of what "recent activity" on a worktree looks
96like, you might need some juggling. You can't glean much
97info about a worktree in a jiffy.
98
99Branch-previewing with the good ol' git-branch:
100```bash
101λ git branch -v
102+ feature/is-ascii-octdigit bc57be3af7a introduce {char, u8}::is_ ...
103+ improve-std-char-docs 94cba88553e add whitespace in assert ...
104* master eac6c33bc63 Auto merge of #100869 - n ...
105```
106
107Meanwhile in worktree wonderland:
108```
109λ git worktree list
110~/worktrees/rustc/master eac6c33bc63 [master]
111~/worktrees/rustc/improve-std-char-docs 94cba88553e [improve-std-char-docs]
112~/worktrees/rustc/is-ascii-octdigit bc57be3af7a [feature/is-ascii-octdigit]
113
114# aha, so ../is-ascii-octdigit corresponds to `feature/is-ascii-octdigit`
115λ git log feature/is-ascii-octdigit
116bc57be3af7a introduce {char, u8}::is_ascii_octdigit
117eac6c33bc63 Auto merge of #100869 - nnethercote:repl ...
118b32223fec10 Auto merge of #100707 - dzvon:fix-typo, ...
119aa857eb953e Auto merge of #100537 - petrochenkov:pic ...
120
121# extra work to make the branch <-> worktree correspondence
122```
123
124#### Shell completions
125
126Lastly, you can bank on shell completions to fill in your
127branch whilst using `git checkout`. Worktrees have no such
128conveniences.
129
130We can mend these minor faults with fzf.
131
132### Unclunkifying worktrees
133
134I'd suggest looking up
135[fzf](https://github.com/junegunn/fzf) (or
136[skim](https://github.com/lotabout/skim) or
137[fzy](https://github.com/jhawthorn/fzy)). These things make
138it cake-easy to add interactivity to your shell. Onto fixing
139the first minor fault, the inability to "jump" to a worktree
140from anywhere within a git repository.
141
142I have a little function called `gwj` which stands for "git
143worktree jump". The idea is to list all the worktrees,
144select one with fzf, and `cd` to it upon selection:
145
146```bash
147gwj () {
148 local out
149 out=$(git worktree list | fzf | awk '{print $1}')
150 cd $out
151}
152```
153
154That is all of it really. Head into a git repository:
155
156```bash
157# here, "master" is a directory, which contains my main
158# worktree: a checkout of the master branch on rust-lang/rust
159λ cd ~/worktrees/rustc/master/library/core/src
160λ # hack away
161```
162
163Preferably one with a few worktrees:
164
165```bash
166λ git worktree list
167~/worktrees/rustc/master eac6c33bc63 [master]
168~/worktrees/rustc/improve-std-char-docs 94cba88553e [improve-std-char-docs]
169~/worktrees/rustc/is-ascii-octdigit bc57be3af7a [feature/is-ascii-octdigit]
170```
171
172And hit `gwj` (pretend that the pipe, |, is your cursor):
173
174```bash
175λ gwj
176> |
177 4/4
178> ~/worktrees/rustc/master eac6c33bc63 [master]
179 ~/worktrees/rustc/improve-std-char-docs 94cba88553e [improve-std-char-docs]
180 ~/worktrees/rustc/is-ascii-octdigit bc57be3af7a [feature/is-ascii-octdigit]
181```
182
183Approximately type in your branch of choice:
184
185```bash
186λ gwj
187> docs|
188 4/4
189> ~/worktrees/rustc/improve-std-char-docs 94cba88553e [improve-std-char-docs]
190```
191
192And hit enter. You should find yourself in the selected
193worktree.
194
195Onward, to the next fault, lack of preview-bility. We can
196utilize fzf's aptly named `--preview` flag, to, well,
197preview our worktree before performing a selection:
198
199```bash
200gwj () {
201 local out
202 out=$(
203 git worktree list |
204 fzf --preview='git log --oneline -n10 {2}' |
205 awk '{print $1}'
206 )
207 cd $out
208}
209```
210
211Once again, hit `gwj` inside a git repository with linked worktrees:
212
213```bash
214λ gwj
215╭─────────────────────────────────────────────────────────╮
216│ eac6c33bc63 Auto merge of 100869 nnethercote:replace... │
217│ b32223fec10 Auto merge of 100707 dzvon:fix-typo, r=d... │
218│ aa857eb953e Auto merge of 100537 petrochenkov:picche... │
219│ 3892b7074da Auto merge of 100210 mystor:proc_macro_d... │
220│ db00199d999 Auto merge of 101249 matthiaskrgr:rollup... │
221│ 14d216d33ba Rollup merge of 101240 JohnTitor:JohnTit... │
222│ 3da66f03531 Rollup merge of 101236 thomcc:winfs-noze... │
223│ 0620f6e90af Rollup merge of 101230 davidtwco:transla... │
224│ c30c42ee299 Rollup merge of 101229 mgeisler:link-try... │
225│ e5356712b9e Rollup merge of 101165 ldm0:drain_to_ite... │
226╰─────────────────────────────────────────────────────────╯
227>
228 4/4
229> /home/np/worktrees/compiler/master eac6c...
230 /home/np/worktrees/compiler/improve-std-char-docs 94cba...
231 /home/np/worktrees/compiler/is-ascii-octdigit bc57b...
232```
233
234A fancy preview of the last 10 commits on the branch that
235the selected worktree corresponds to. In other words, sight
236for sore eyes. Our little script is already shaping up to be
237useful, you hit `gwj`, browse through your worktrees,
238preview each one and automatically `cd` to your selection.
239But we are not done yet.
240
241The last fault was lack shell completions. A quick review of
242what a shell completion really does:
243
244```bash
245λ git checkout f<tab>
246feature/is-ascii-octdigit
247fix/some-error
248format-doc-tests
249
250λ git checkout feat<tab>
251
252λ git checkout feature/is-ascii-octdigit
253```
254
255Each time you hit "tab", the shell produces a few
256"completion candidates", and once you have just a single
257candidate left, the shell inserts that for you directly into
258your edit line. Of course, this process varies from shell to
259shell.
260
261fzf narrows down your options as you type into the prompt,
262but you still have to:
263
2641. Type `gwj`
2652. Hit enter
2663. Type out a query and narrow down your search
2674. Hit enter
268
269We can speed that up a bit, have fzf narrow down the
270candidates on startup, just like our shell does:
271
272```bash
273gwj () {
274 local out query
275 query="${1:- }"
276 out=$(
277 git worktree list |
278 fzf --preview='git log --oneline -n10 {2}' --query "$query" -1 |
279 awk '{print $1}'
280 )
281 cd $out
282}
283```
284
285The change is extremely tiny, blink-and-you'll-miss-it kinda
286tiny. We added a little `--query` flag, that allows you to
287prefill the prompt, and the `-1` flag, that avoids the
288interactive finder if only one match exists on startup:
289
290```bash
291# skip through the fzf prompt:
292λ gwj master
293# cd -- ~/worktrees/rustc/master
294
295# more than one option, we end up in the interactive finder
296λ gwj improve
297╭─────────────────────────────────────────────────────────╮
298│ eac6c33bc63 Auto merge of 100869 nnethercote:replace... │
299│ b32223fec10 Auto merge of 100707 dzvon:fix-typo, r=d... │
300│ aa857eb953e Auto merge of 100537 petrochenkov:picche... │
301╰─────────────────────────────────────────────────────────╯
302> improve
303 2/2
304> /home/np/worktrees/compiler/improve-const-perf eac6c...
305 /home/np/worktrees/compiler/improve-std-char-docs 94cba...
306```
307
308Throw some error handling in there, hook up a similar script
309to improve the UX of `git worktree remove`, go wild. A few
310more helpers I've got:
311
312```bash
313# gwa /path/to/branch-name
314# creates a new branch and "switches" to it
315function gwa () {
316 git worktree add "$1" && cd "$1"
317}
318
319alias gwls="git worktree list"
320```