1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
|
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="/style.css">
<link rel="stylesheet" href="/syntax.css">
<meta charset="UTF-8">
<meta name="viewport" content="initial-scale=1">
<meta content="#ffffff" name="theme-color">
<meta name="HandheldFriendly" content="true">
<meta property="og:title" content="Curing A Case Of Git-UX">
<meta property="og:type" content="website">
<meta property="og:description" content="a static site {for, by, about} me ">
<meta property="og:url" content="https://peppe.rs">
<link rel="icon" type="image/x-icon" href="/favicon.png">
<title>Curing A Case Of Git-UX · peppe.rs</title>
<body>
<div class="posts">
<div class="post">
<a href="/" class="post-end-link">Home</a>
<span>/</span>
<a href="/posts" class="post-end-link">Posts</a>
<span>/</span>
<a class="post-end-link">Curing A Case Of Git-UX</a>
<a class="stats post-end-link" href="https://git.peppe.rs/web/site/plain/posts/curing_a_case_of_git-UX.md
">View Raw</a>
<div class="separator"></div>
<div class="date">
03/09 — 2022
<div class="stats">
<span class="stats-number">
127.87
</span>
<span class="stats-unit">cm</span>
 
<span class="stats-number">
9.6
</span>
<span class="stats-unit">min</span>
</div>
</div>
<h1>
Curing A Case Of Git-UX
</h1>
<div class="post-text">
<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>
<p><a href="https://asciinema.org/a/D297ztKRzpE4gAHbPTPmkqYps"><img
src="https://asciinema.org/a/D297ztKRzpE4gAHbPTPmkqYps.svg" /></a></p>
<p>Fear not if you haven’t heard of “worktrees”, I have included a
primer here.<br />
<a href="#what-makes-them-clunky">Skip the primer -></a>.</p>
<h3 id="why-worktrees">Why Worktrees?</h3>
<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>
<ul>
<li>create a temporary branch, make a WIP commit, begin working on the
fix</li>
<li>stash away your changes, begin working on the fix</li>
<li>unfriend said friend for disturbing your flow</li>
</ul>
<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>
<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>
<ol type="1">
<li>Create a new working tree with:</li>
</ol>
<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 <branch-name> <path> <from></span></span>
<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>
<ol start="2" type="1">
<li><code>cd</code> into <code>/path/to/tree</code></li>
<li>Fix, test, commit, push, party</li>
<li>Go back to your work, <code>cd -</code></li>
</ol>
<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>
<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>
<h3 id="what-makes-them-clunky">What makes them clunky?</h3>
<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>
<h4 id="branch-hopping">Branch-hopping</h4>
<p>You can <code>git checkout <branch></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>
<p>Branch-hopping with the good ol’ git-checkout:</p>
<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>
<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>
<p>Meanwhile, in worktree world:</p>
<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>
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git worktree list</span>
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/master</span> eac6c33bc63 <span class="pp">[</span><span class="ss">master</span><span class="pp">]</span></span>
<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 <span class="pp">[</span><span class="ss">improve</span><span class="pp">-</span><span class="ss">std</span><span class="pp">-</span><span class="ss">char</span><span class="pp">-</span><span class="ss">docs</span><span class="pp">]</span></span>
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/is-ascii-octdigit</span> bc57be3af7a <span class="pp">[</span><span class="ss">feature/is</span><span class="pp">-</span><span class="ss">ascii</span><span class="pp">-</span><span class="ss">octdigit</span><span class="pp">]</span></span>
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a><span class="ex">~/my/other/path/oh/god</span> op57or3ns7n <span class="pp">[</span><span class="ss">fix/some</span><span class="pp">-</span><span class="ss">error</span><span class="pp">]</span></span>
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a></span>
<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>
<h4 id="branch-previewing">Branch-previewing</h4>
<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>
<p>Branch-previewing with the good ol’ git-branch:</p>
<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>
<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>
<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>
<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>
<p>Meanwhile in worktree wonderland:</p>
<pre><code>λ git worktree list
~/worktrees/rustc/master eac6c33bc63 [master]
~/worktrees/rustc/improve-std-char-docs 94cba88553e [improve-std-char-docs]
~/worktrees/rustc/is-ascii-octdigit bc57be3af7a [feature/is-ascii-octdigit]
# aha, so ../is-ascii-octdigit corresponds to `feature/is-ascii-octdigit`
λ git log feature/is-ascii-octdigit
bc57be3af7a introduce {char, u8}::is_ascii_octdigit
eac6c33bc63 Auto merge of #100869 - nnethercote:repl ...
b32223fec10 Auto merge of #100707 - dzvon:fix-typo, ...
aa857eb953e Auto merge of #100537 - petrochenkov:pic ...
# extra work to make the branch <-> worktree correspondence</code></pre>
<h4 id="shell-completions">Shell completions</h4>
<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>
<p>We can mend these minor faults with fzf.</p>
<h3 id="unclunkifying-worktrees">Unclunkifying worktrees</h3>
<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>
<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>
<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>
<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>
<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">'{print $1}'</span><span class="va">)</span></span>
<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>
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre></div>
<p>That is all of it really. Head into a git repository:</p>
<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, "master" is a directory, which contains my main</span></span>
<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>
<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>
<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>
<p>Preferably one with a few worktrees:</p>
<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>
<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/master</span> eac6c33bc63 <span class="pp">[</span><span class="ss">master</span><span class="pp">]</span></span>
<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 <span class="pp">[</span><span class="ss">improve</span><span class="pp">-</span><span class="ss">std</span><span class="pp">-</span><span class="ss">char</span><span class="pp">-</span><span class="ss">docs</span><span class="pp">]</span></span>
<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a><span class="ex">~/worktrees/rustc/is-ascii-octdigit</span> bc57be3af7a <span class="pp">[</span><span class="ss">feature/is</span><span class="pp">-</span><span class="ss">ascii</span><span class="pp">-</span><span class="ss">octdigit</span><span class="pp">]</span></span></code></pre></div>
<p>And hit <code>gwj</code> (pretend that the pipe, |, is your
cursor):</p>
<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>
<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a><span class="op">></span> <span class="kw">|</span></span>
<span id="cb9-3"><a href="#cb9-3" aria-hidden="true" tabindex="-1"></a> <span class="ex">4/4</span></span>
<span id="cb9-4"><a href="#cb9-4" aria-hidden="true" tabindex="-1"></a><span class="op">></span> ~/worktrees/rustc/master <span class="ex">eac6c33bc63</span> <span class="pp">[</span><span class="ss">master</span><span class="pp">]</span></span>
<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 <span class="pp">[</span><span class="ss">improve</span><span class="pp">-</span><span class="ss">std</span><span class="pp">-</span><span class="ss">char</span><span class="pp">-</span><span class="ss">docs</span><span class="pp">]</span></span>
<span id="cb9-6"><a href="#cb9-6" aria-hidden="true" tabindex="-1"></a> <span class="ex">~/worktrees/rustc/is-ascii-octdigit</span> bc57be3af7a <span class="pp">[</span><span class="ss">feature/is</span><span class="pp">-</span><span class="ss">ascii</span><span class="pp">-</span><span class="ss">octdigit</span><span class="pp">]</span></span></code></pre></div>
<p>Approximately type in your branch of choice:</p>
<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>
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="op">></span> docs<span class="kw">|</span></span>
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> <span class="ex">4/4</span></span>
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a><span class="op">></span> ~/worktrees/rustc/improve-std-char-docs <span class="ex">94cba88553e</span> <span class="pp">[</span><span class="ss">improve</span><span class="pp">-</span><span class="ss">std</span><span class="pp">-</span><span class="ss">char</span><span class="pp">-</span><span class="ss">docs</span><span class="pp">]</span></span></code></pre></div>
<p>And hit enter. You should find yourself in the selected worktree.</p>
<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>
<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>
<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>
<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>
<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>
<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">'git log --oneline -n10 {2}'</span> <span class="kw">|</span></span>
<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a> <span class="fu">awk</span> <span class="st">'{print $1}'</span></span>
<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a> <span class="va">)</span></span>
<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>
<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre></div>
<p>Once again, hit <code>gwj</code> inside a git repository with linked
worktrees:</p>
<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>
<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="ex">╭─────────────────────────────────────────────────────────╮</span></span>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<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>
<span id="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a><span class="ex">╰─────────────────────────────────────────────────────────╯</span></span>
<span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a><span class="op">></span></span>
<span id="cb12-15"><a href="#cb12-15" aria-hidden="true" tabindex="-1"></a> <span class="ex">4/4</span></span>
<span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a><span class="op">></span> /home/np/worktrees/compiler/master <span class="ex">eac6c...</span></span>
<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>
<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>
<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>
<p>The last fault was lack shell completions. A quick review of what a
shell completion really does:</p>
<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"><</span>tab<span class="op">></span></span>
<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="ex">feature/is-ascii-octdigit</span></span>
<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="ex">fix/some-error</span></span>
<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a><span class="ex">format-doc-tests</span></span>
<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> git checkout feat<span class="op"><</span>tab<span class="op">></span></span>
<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a></span>
<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>
<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>
<p>fzf narrows down your options as you type into the prompt, but you
still have to:</p>
<ol type="1">
<li>Type <code>gwj</code></li>
<li>Hit enter</li>
<li>Type out a query and narrow down your search</li>
<li>Hit enter</li>
</ol>
<p>We can speed that up a bit, have fzf narrow down the candidates on
startup, just like our shell does:</p>
<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>
<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>
<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">"</span><span class="va">${1</span><span class="op">:-</span> <span class="va">}</span><span class="st">"</span></span>
<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>
<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>
<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">'git log --oneline -n10 {2}'</span> <span class="at">--query</span> <span class="st">"</span><span class="va">$query</span><span class="st">"</span> <span class="at">-1</span> <span class="kw">|</span></span>
<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a> <span class="fu">awk</span> <span class="st">'{print $1}'</span></span>
<span id="cb14-8"><a href="#cb14-8" aria-hidden="true" tabindex="-1"></a> <span class="va">)</span></span>
<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>
<span id="cb14-10"><a href="#cb14-10" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span></code></pre></div>
<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>
<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>
<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj master</span>
<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a><span class="co"># cd -- ~/worktrees/rustc/master</span></span>
<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a></span>
<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>
<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a><span class="ex">λ</span> gwj improve</span>
<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a><span class="ex">╭─────────────────────────────────────────────────────────╮</span></span>
<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>
<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>
<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>
<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a><span class="ex">╰─────────────────────────────────────────────────────────╯</span></span>
<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a><span class="op">></span> improve</span>
<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a> <span class="ex">2/2</span></span>
<span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a><span class="op">></span> /home/np/worktrees/compiler/improve-const-perf <span class="ex">eac6c...</span></span>
<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>
<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>
<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>
<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a><span class="co"># creates a new branch and "switches" to it</span></span>
<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>
<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a> <span class="fu">git</span> worktree add <span class="st">"</span><span class="va">$1</span><span class="st">"</span> <span class="kw">&&</span> <span class="bu">cd</span> <span class="st">"</span><span class="va">$1</span><span class="st">"</span></span>
<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a><span class="kw">}</span></span>
<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a></span>
<span id="cb16-7"><a href="#cb16-7" aria-hidden="true" tabindex="-1"></a><span class="bu">alias</span> gwls=<span class="st">"git worktree list"</span></span></code></pre></div>
</div>
<div class="intro">
Hi.
<div class="hot-links">
<a href="https://peppe.rs/index.xml" class="feed-button">Subscribe</a>
<a href="https://liberapay.com/nerdypepper/donate" class="donate-button">Donate</a>
</div>
<p>I'm Akshay, programmer and pixel-artist.</p>
<p>
I write <a href="https://git.peppe.rs">open-source stuff</a> to pass time.
I also design fonts:
<a href="https://git.peppe.rs/fonts/scientifica/about">scientifica</a>,
<a href="https://git.peppe.rs/fonts/curie/about">curie</a>.
</p>
<p>Send me a mail at [email protected] or a message at [email protected].</p>
</div>
<a href="/" class="post-end-link">Home</a>
<span>/</span>
<a href="/posts" class="post-end-link">Posts</a>
<span>/</span>
<a class="post-end-link">Curing A Case Of Git-UX</a>
<a class="stats post-end-link" href="https://git.peppe.rs/web/site/plain/posts/curing_a_case_of_git-UX.md
">View Raw</a>
</div>
</div>
</body>
</html>
|