
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Casthoughts</title><link href="https://tacaswell.github.io/" rel="alternate"></link><link href="https://tacaswell.github.io/feeds/all.atom.xml" rel="self"></link><id>https://tacaswell.github.io/</id><updated>2022-11-25T22:00:00-05:00</updated><subtitle>Software and such</subtitle><entry><title>Reflowing Axes</title><link href="https://tacaswell.github.io/dynamic-axes-count.html" rel="alternate"></link><published>2022-11-25T22:00:00-05:00</published><updated>2022-11-25T22:00:00-05:00</updated><author><name>Thomas A Caswell</name></author><id>tag:tacaswell.github.io,2022-11-25:/dynamic-axes-count.html</id><summary type="html">&lt;p&gt;Dynamically adding Axes to a Figure&lt;/p&gt;</summary><content type="html">&lt;p&gt;At the prompting of a user on Matplotlib&amp;rsquo;s gitter channel I wrote the following
example:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;matplotlib.pyplot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;plt&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;numpy&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;np&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;itertools&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nn"&gt;matplotlib.gridspec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;GridSpec&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;reflow_gen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# we own this figure now so clear it&lt;/span&gt;
    &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;clf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;# running count of the number of axes&lt;/span&gt;
    &lt;span class="n"&gt;axcount&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c1"&gt;# the shape of the grid&lt;/span&gt;
    &lt;span class="n"&gt;row_guess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;col_guess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="c1"&gt;# the current GridSpec object&lt;/span&gt;
    &lt;span class="n"&gt;gs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;

    &lt;span class="c1"&gt;# we are a generator, so loop forever&lt;/span&gt;
    &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="kc"&gt;True&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="c1"&gt;# what number is this Axes?&lt;/span&gt;
        &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;axcount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="c1"&gt;# do we need to re-flow?&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;row_guess&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;col_guess&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="c1"&gt;# Find the smallest square that will work&lt;/span&gt;
            &lt;span class="n"&gt;col_guess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;row_guess&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ceil&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
            &lt;span class="c1"&gt;# and then drop fully empty rows&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row_guess&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row_guess&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;col_guess&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="k"&gt;break&lt;/span&gt;
                &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
                    &lt;span class="n"&gt;row_guess&lt;/span&gt; &lt;span class="o"&gt;-=&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;

            &lt;span class="c1"&gt;# Create the new gridspec object&lt;/span&gt;
            &lt;span class="n"&gt;gs&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GridSpec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row_guess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;col_guess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;figure&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

            &lt;span class="c1"&gt;# for each of the axes, adjust it to use the new gridspec&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;axes&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
                &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_subplotspec&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unravel_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row_guess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;col_guess&lt;/span&gt;&lt;span class="p"&gt;))])&lt;/span&gt;
            &lt;span class="c1"&gt;# resize the figure to have ~ 3:4 ratio and keep the Axes fixed&lt;/span&gt;
            &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_size_inches&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;col_guess&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row_guess&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c1"&gt;# Add the new axes to the Figure at the next open space&lt;/span&gt;
        &lt;span class="n"&gt;new_ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;add_subplot&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gs&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;np&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;unravel_index&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row_guess&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;col_guess&lt;/span&gt;&lt;span class="p"&gt;))])&lt;/span&gt;

        &lt;span class="c1"&gt;# hand the Axes back to the user&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;new_ax&lt;/span&gt;

&lt;span class="c1"&gt;# make a Figure&lt;/span&gt;
&lt;span class="n"&gt;fig&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;figure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;layout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;constrained&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# set up the generator&lt;/span&gt;
&lt;span class="n"&gt;ax_gen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;reflow_gen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fig&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="c1"&gt;# get an Axes&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ax_gen&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;ax&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;set_title&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Axes &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c1"&gt;# fig.savefig(f&amp;#39;dynamic_axes_figs-axes_{j}.svg&amp;#39;)&lt;/span&gt;
&lt;span class="n"&gt;plt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;show&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;1 axes (1x1)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Figure with 1 Axes added" src="/images/dynamic_axes_figs-axes_0.svg" title="1 Axes"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2 axes (2x1)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Figure with 2 Axes added" src="/images/dynamic_axes_figs-axes_1.svg" title="2 Axes"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3 axes (2x2)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Figure with 3 Axes added" src="/images/dynamic_axes_figs-axes_2.svg" title="3 Axes"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;4 axes (2x2)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Figure with 4 Axes added" src="/images/dynamic_axes_figs-axes_3.svg" title="4 Axes"&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;5 axes (3x2)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;img alt="Figure with 5 Axes added" src="/images/dynamic_axes_figs-axes_4.svg" title="5 Axes"&gt;&lt;/p&gt;
&lt;p&gt;and so on up to as many &lt;em&gt;Axes&lt;/em&gt; as you want to add.  Note that the Figure is
getting bigger as more Axes are added so if using this interactively the window
will grow.&lt;/p&gt;
&lt;p&gt;I am not sure that this is general enough to add to Matplotlib, but it is a
cute example of how generators can be useful.  One concern with this code is
that the generator will keep the &lt;em&gt;Figure&lt;/em&gt; object alive which may complicate
resource management.  There are also some questions for me about what the API
should be.  As written the resizing and target aspect ratio behavior is fixed,
I think it is reasonable for users to be able to control both.  Additional, the
scheme for growing the grid and selecting which slots to fill at a given grid
size and fill factor could be elaborated.  It might also be interesting to
promote the generator to a full &lt;a href="https://tacaswell.github.io/coroutines-i.html"&gt;generator
co-routine&lt;/a&gt; to be able to pass arguments the Axes
creation step (to set projections and such).&lt;/p&gt;</content><category term="Matplotlib"></category><category term="Matplotlib generator"></category></entry><entry><title>Coroutines (practical)</title><link href="https://tacaswell.github.io/coroutines-i.html" rel="alternate"></link><published>2022-10-14T17:25:00-04:00</published><updated>2022-10-15T11:15:00-04:00</updated><author><name>Thomas A Caswell</name></author><id>tag:tacaswell.github.io,2022-10-14:/coroutines-i.html</id><summary type="html">&lt;p&gt;So you have been handed a generator co-routine&amp;hellip;&lt;/p&gt;</summary><content type="html">&lt;p&gt;This is a explanation of how to practically work with generator coroutines in
Python.  If you are willing to accept the rules laid out in this (not so) short
guide as empirical observations then you should be able to productively work
with generator co-routines.  In a future post I intend to dive into the &amp;ldquo;why&amp;rdquo;
(and the &amp;ldquo;why this makes sense&amp;rdquo;), but this is the pragmatic view.&lt;/p&gt;
&lt;p&gt;Generator coroutines in Python have two bi-directional communication channels&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;data &lt;code&gt;yield&lt;/code&gt; / &lt;code&gt;send()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;exceptions via &lt;code&gt;raise&lt;/code&gt; / &lt;code&gt;throw()&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;and two unidirectional channels&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;data via &lt;code&gt;return&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;close()&lt;/code&gt; to exit the coroutine immediately&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Another way to look at this is generator co-routines have two &amp;ldquo;happy path&amp;rdquo;
communication channels:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;data &lt;code&gt;yield&lt;/code&gt; / &lt;code&gt;send()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;data via &lt;code&gt;return&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;and two &amp;ldquo;sad path&amp;rdquo; communication channels:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;exceptions via &lt;code&gt;raise&lt;/code&gt; / &lt;code&gt;throw()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;close()&lt;/code&gt; to exit the coroutine immediately&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each of these channels has a different purpose and without one of them
co-routines would be incomplete.  You may not need to (explicitly) use all of
these channels in any given application.&lt;/p&gt;
&lt;h2 id="yield-send-data-channel"&gt;&lt;code&gt;yield&lt;/code&gt; / &lt;code&gt;send()&lt;/code&gt; data channel&lt;/h2&gt;
&lt;p&gt;The first half of this channel is &lt;code&gt;yield&lt;/code&gt; which will (as the name suggests)
yield value out of the coroutine.  If we only use the &lt;code&gt;yield&lt;/code&gt; the we have a
&amp;ldquo;generator function&amp;rdquo;, for example if we write&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;my_gen&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;
    &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;which we can then use with the iteration protocol as:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_gen&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;More explicitly, what &lt;code&gt;list&lt;/code&gt; (or a &lt;code&gt;for&lt;/code&gt; loop) is doing under the hood is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;my_gen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="s1"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="s1"&gt;&amp;#39;c&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="ne"&gt;StopIteration&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The way that the generator communicates that it is exhausted is by raising the
&lt;code&gt;StopIteration&lt;/code&gt;
&lt;a href="https://docs.python.org/3/library/exceptions.html#StopIteration"&gt;exception&lt;/a&gt;.
We will come back to the raised Exception object in a bit.&lt;/p&gt;
&lt;p&gt;Using &lt;code&gt;yield&lt;/code&gt; we can get information &lt;em&gt;out&lt;/em&gt; of generator coroutine, to get data
into the generator coroutine we need to capture a left-hand side of the &lt;code&gt;yield&lt;/code&gt;
as&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;my_gen&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;in1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;got &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;in1&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;in2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;got &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;in2&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If we pass that to &lt;code&gt;list&lt;/code&gt; we see:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;list&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;my_gen&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;What this (and &lt;code&gt;next&lt;/code&gt;) is doing under the hood is&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;my_gen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;span class="s1"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="kc"&gt;None&lt;/span&gt;
&lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="ne"&gt;StopIteration&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The sequence is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Create the generator.  At this point no code has run yet.&lt;/li&gt;
&lt;li&gt;The first &lt;code&gt;.send()&lt;/code&gt; runs the coroutine up to the first &lt;code&gt;yield&lt;/code&gt; and sends the
   right hand side out.  The value of the first &lt;code&gt;.send&lt;/code&gt; &lt;em&gt;must&lt;/em&gt; be &lt;code&gt;None&lt;/code&gt;
   because there is no way to access the value passed in.&lt;/li&gt;
&lt;li&gt;The coroutine is suspended until the next &lt;code&gt;send()&lt;/code&gt;.  The value pass to the
   second &lt;code&gt;send()&lt;/code&gt; is assigned to the left hand side of the &lt;code&gt;yield&lt;/code&gt; expression.&lt;/li&gt;
&lt;li&gt;The coroutine runs until the next &lt;code&gt;yield&lt;/code&gt; and sends out the right hand side.  We
   then go back to step 3 until there are no more &lt;code&gt;yield&lt;/code&gt; expressions in the coroutine.&lt;/li&gt;
&lt;li&gt;when the coroutine returns Python will raise the &lt;code&gt;StopIteration&lt;/code&gt; exception
   for us.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To see this more clearly, re-running the above code but sending in diffrent
values at each step:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;my_gen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;step 1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;step 1&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;step 2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;step 2&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="ne"&gt;StopIteration&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="return-data-channel"&gt;&lt;code&gt;return&lt;/code&gt; data channel&lt;/h2&gt;
&lt;p&gt;So far we have not used &lt;code&gt;return&lt;/code&gt; and relying on the implicit &lt;code&gt;return None&lt;/code&gt; that
Python provides.  As with any Python function we put a &lt;code&gt;return&lt;/code&gt; in our
coroutine:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;my_gen&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
    &lt;span class="n"&gt;in1&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;got &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;in1&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;in2&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;
    &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;got &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;in2&lt;/span&gt;&lt;span class="si"&gt;!r}&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Done!&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;However, this raise the question of how do we get to the returned value?  It
can not come back as the return from &lt;code&gt;.send()&lt;/code&gt; as that is where the &lt;code&gt;yield&lt;/code&gt;
values are carried.  Instead the value is carried on the &lt;code&gt;StopIteration&lt;/code&gt;
exception that is raised when the iterator is exhausted.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;my_gen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;step 1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;step 1&amp;#39;&lt;/span&gt;
&lt;span class="s1"&gt;&amp;#39;b&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;g&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;step 2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;step 2&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="ne"&gt;StopIteration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To get the the value we need to catch the &lt;code&gt;StopIteration&lt;/code&gt;
and access &lt;code&gt;ex.value&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;my_gen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;yielded: &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="n"&gt;yielded&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;a&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;     &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;         &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;yielded: &amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;step &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;     &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;StopIteration&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;         &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Returned: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;         &lt;span class="k"&gt;break&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;step 1&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;yielded&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="n"&gt;b&lt;/span&gt;
&lt;span class="n"&gt;got&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;step 2&amp;#39;&lt;/span&gt;
&lt;span class="n"&gt;Returned&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It may be tempting to try and raise your own &lt;code&gt;StopIteration&lt;/code&gt; rather than
returning, however if you do Python will convert it to a &lt;code&gt;RuntimeError&lt;/code&gt;.  This
is because Python can not tell the difference between your intentionally
raising &lt;code&gt;StopIteration&lt;/code&gt; and something you have called unexpectedly raising
&lt;code&gt;StopIteration&lt;/code&gt;.  Pre &lt;a href="https://peps.python.org/pep-0479/"&gt;Python 3.5&lt;/a&gt; the
&lt;code&gt;StopIteration&lt;/code&gt; would be raised to the outer caller which would be interpreted
as the generator returning normally which in turn would mask bugs in very
confusing ways.&lt;/p&gt;
&lt;h2 id="raise-throw-channel"&gt;&lt;code&gt;raise&lt;/code&gt; / &lt;code&gt;throw&lt;/code&gt; channel&lt;/h2&gt;
&lt;p&gt;Like all Python we can use the standard exception raising and handling tools,
however there are a couple a caveates.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The co-routine must not raise &lt;code&gt;StopIteration&lt;/code&gt; (as noted above)&lt;/li&gt;
&lt;li&gt;If you catch &lt;code&gt;GeneratorExit&lt;/code&gt; the co-routine must return (see the section on
   &lt;code&gt;close()&lt;/code&gt; below).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Any valid exception raised will inturn be raised from the call point of the
&lt;code&gt;obj.send()&lt;/code&gt; in the outer code, identically to how an exception called in a
function will propogate to the call site.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;my_gen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;=&lt;/span&gt; &lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Got &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; ints and are done&amp;quot;&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;        &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;N&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s1"&gt; ints in a row&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="nb"&gt;isinstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;int&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="ne"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;We only take integers!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If we exhaust the &amp;ldquo;happy path&amp;rdquo; of this co-routine we see:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;my_gen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="s1"&gt;&amp;#39;0/3 ints in a row&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="s1"&gt;&amp;#39;1/3 ints in a row&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="s1"&gt;&amp;#39;2/3 ints in a row&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="ne"&gt;StopIteration&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Got&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt; &lt;span class="n"&gt;ints&lt;/span&gt; &lt;span class="ow"&gt;and&lt;/span&gt; &lt;span class="n"&gt;are&lt;/span&gt; &lt;span class="n"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;which raises &lt;code&gt;StopIteration&lt;/code&gt; with the payload of a string as expected.  However, if we
were to send in not an integer&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;my_gen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="s1"&gt;&amp;#39;0/3 ints in a row&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="s1"&gt;&amp;#39;1/3 ints in a row&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;aardvark&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;my_gen&lt;/span&gt;
&lt;span class="ne"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;We&lt;/span&gt; &lt;span class="n"&gt;only&lt;/span&gt; &lt;span class="n"&gt;take&lt;/span&gt; &lt;span class="n"&gt;integers&lt;/span&gt;&lt;span class="err"&gt;!&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;However, if an unhandled exception is raised from a co-routine it is fully
exhausted and subsequently sending in new values will immediantly raise
&lt;code&gt;StopIteration&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Sometimes it is necessary to inject an exception into a co-routine, for example
to let the co-routine know the outer code did not like the last yielded value.
This can be done with the &lt;code&gt;obj.throw&lt;/code&gt; method which causes the passed
&lt;code&gt;Exception&lt;/code&gt; to be raised at the &lt;code&gt;yield&lt;/code&gt;.  Within the co-routine we can use all
of the standard exception handling tools of Python:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;my_gen&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;        &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;            &lt;span class="n"&gt;inp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;        &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;            &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Ignoring ValueError&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;        &lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;            &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;No exception&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;        &lt;span class="k"&gt;finally&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;            &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Finish loop&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;my_gen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;a&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;No&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;
&lt;span class="n"&gt;Finish&lt;/span&gt; &lt;span class="n"&gt;loop&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;No&lt;/span&gt; &lt;span class="n"&gt;exception&lt;/span&gt;
&lt;span class="n"&gt;Finish&lt;/span&gt; &lt;span class="n"&gt;loop&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;throw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ne"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Ignoring&lt;/span&gt; &lt;span class="ne"&gt;ValueError&lt;/span&gt;
&lt;span class="n"&gt;Finish&lt;/span&gt; &lt;span class="n"&gt;loop&lt;/span&gt;
&lt;span class="mi"&gt;3&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;throw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ne"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;Finish&lt;/span&gt; &lt;span class="n"&gt;loop&lt;/span&gt;
&lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;my_gen&lt;/span&gt;
&lt;span class="ne"&gt;RuntimeError&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If the generator is exhausted than any exceptions thrown in are immediately
re-raised.&lt;/p&gt;
&lt;h2 id="close-channel"&gt;&lt;code&gt;close&lt;/code&gt; channel&lt;/h2&gt;
&lt;p&gt;Sometimes the outer caller of a generator needs to tell the co-routine to clean
up and drop-dead.  This is done via the &lt;code&gt;gen.close()&lt;/code&gt; method which will cause a
&lt;code&gt;GeneratorExit&lt;/code&gt; exepction to be raised at the point where the co-routine is
suspended (the &lt;code&gt;yield&lt;/code&gt;).  If the co-routine catches this exception and tries to
yield additional values, then &lt;code&gt;close()&lt;/code&gt; will raise a &lt;code&gt;RuntimeError&lt;/code&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;my_gen&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;     &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;         &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;             &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;         &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;GeneratorExit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;             &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;I refuse to exit&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;my_gen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;I&lt;/span&gt; &lt;span class="n"&gt;refuse&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;exit&lt;/span&gt;
&lt;span class="n"&gt;Traceback&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;most&lt;/span&gt; &lt;span class="n"&gt;recent&lt;/span&gt; &lt;span class="n"&gt;call&lt;/span&gt; &lt;span class="n"&gt;last&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
  &lt;span class="n"&gt;File&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;&amp;lt;stdin&amp;gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;line&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;module&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="ne"&gt;RuntimeError&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;generator&lt;/span&gt; &lt;span class="n"&gt;ignored&lt;/span&gt; &lt;span class="ne"&gt;GeneratorExit&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The reason that &lt;code&gt;GeneratorExit&lt;/code&gt; is not suppressible is that it is as part of
garbage collection and Python must be able to clean up the co-routine.&lt;/p&gt;
&lt;p&gt;If the co-routine catches the exception and &lt;code&gt;returns&lt;/code&gt; there is no way for the
outer caller to access the returned value.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;def&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;my_gen&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;     &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;count&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;         &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;             &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;         &lt;span class="k"&gt;except&lt;/span&gt; &lt;span class="ne"&gt;GeneratorExit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;             &lt;span class="nb"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;I acquiese to your request.&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;             &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;Aardvark&amp;#39;&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;my_gen&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;1&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;send&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;None&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="mi"&gt;2&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;gen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;I&lt;/span&gt; &lt;span class="n"&gt;acquiese&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;your&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;
&lt;span class="o"&gt;&amp;gt;&amp;gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is particularly useful if the co-routine is holding onto resources, such
as open files or sockets, that need to be gracefully shut down.&lt;/p&gt;</content><category term="Computer Science"></category><category term="coroutines"></category><category term="python"></category></entry><entry><title>How this site is maintained and published</title><link href="https://tacaswell.github.io/tech-details.html" rel="alternate"></link><published>2022-07-03T22:00:00-04:00</published><updated>2022-07-24T13:00:00-04:00</updated><author><name>Thomas A Caswell</name></author><id>tag:tacaswell.github.io,2022-07-03:/tech-details.html</id><summary type="html">&lt;p&gt;A good and proper navel gaze.&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;Hosting&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Both the &lt;a href="https://github.com/tacaswell/tacaswell.github.io"&gt;source&lt;/a&gt; and built
artifacts for this site are hosted on GitHub (via &lt;a href="https://pages.github.com"&gt;github pages&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;It is possible to have a public gh-pages site with a private repository backing
it, however I have opted to have both public.  This has the upsides that I can
&lt;a href="https://github.com/tacaswell/tacaswell.github.io/pulls?q=is%3Apr+is%3Aclosed"&gt;get PRs from
others&lt;/a&gt;
and that it is easier for other people to adapt this set up for their own use.
A slight downside is that the history of my edits is visible, including for
draft posts.  I expect this to only be an issue if I write about any sensitive
topics where I do not want to make my full writing process public (I&amp;rsquo;m all for
openness and working in public, but even I have limits).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Framework&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;This site is written within the &lt;a href="http://getpelican.com"&gt;Pelican&lt;/a&gt; framework.&lt;/p&gt;
&lt;p&gt;I did not do exhaustive research to pick Pelican (but it does well in a google
search for &amp;ldquo;python static site generator&amp;rdquo;), however it is in Python (hopefully
I won&amp;rsquo;t have to dig into the guts, but nice to know I can if I have/want to),
generates static html (needed for gh-pages hosting), and supports both markdown
and rst out-of-the-box.&lt;/p&gt;
&lt;p&gt;The other framework I considered was
&lt;a href="https://www.sphinx-doc.org/en/master/"&gt;Sphinx&lt;/a&gt;.  I work with Sphinx almost
every day for writing documentation, so it is a tool I know.  However, I wanted
both wanted to try a new tool and to use tool more tuned to blog
out-of-the-box.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Theme&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The theme is base on &lt;a href="https://github.com/jody-frankowski/blue-penguin"&gt;Blue
Penguin&lt;/a&gt; which is licensed
Public Domain.  Knowing that I was going to use GHA to build and publish the
site, the theme is simply &lt;a href="https://github.com/tacaswell/tacaswell.github.io/tree/main/themes/blue-penguin"&gt;checked
into&lt;/a&gt;
the source.  I have modified a number of things, in particular the styling
around code snippets, the base colors, and fonts (with considerable help from
my wife).&lt;/p&gt;
&lt;p&gt;If anyone else wants to use these modifications, I would be willing to split it
off into its own repo (and use git submodules), but doing that up front seems
like premature optimization.&lt;/p&gt;
&lt;p&gt;The theme is selected via the &lt;code&gt;PELICANOPTS=-t $(BASEDIR)/themes/blue-penguin&lt;/code&gt;
line in the
&lt;a href="https://github.com/tacaswell/tacaswell.github.io/blob/3e2507fdb3812f3c74cf3076a4e037a07e1c9b7f/Makefile#L10"&gt;Makefile&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Build Pipeline&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To publish the built artifacts, I use a &lt;a href="https://github.com/tacaswell/tacaswell.github.io/blob/main/.github/workflows/publish.yml"&gt;GHA
workflow&lt;/a&gt;
and the amazingly awesome &lt;a href="https://github.com/peaceiris/actions-gh-pages"&gt;gh-pages action&lt;/a&gt; from
&lt;a href="https://github.com/peaceiris"&gt;peaciris&lt;/a&gt;.&lt;/p&gt;</content><category term="Navel Gazing"></category><category term="hosting"></category></entry><entry><title>No magic, only engineering</title><link href="https://tacaswell.github.io/no-magic-only-engineering.html" rel="alternate"></link><published>2022-05-25T21:00:00-04:00</published><updated>2022-05-25T21:00:00-04:00</updated><author><name>Thomas A Caswell</name></author><id>tag:tacaswell.github.io,2022-05-25:/no-magic-only-engineering.html</id><summary type="html">&lt;p&gt;Computers are not magic, but there is some very slick engineering out there.&lt;/p&gt;</summary><content type="html">&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Any sufficiently advanced technology is indistinguishable from magic.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;Arthur C Clark&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In the context of this well known Arthur C Clark quote, it is common to various
aspects of software called &amp;ldquo;magic&amp;rdquo;. Slack has a sign-in workflow that they call
&lt;a href="https://www.waveguide.io/examples/entry/passwordless-login/"&gt;&amp;ldquo;magic link&amp;rdquo;&lt;/a&gt;
and I will colloquially refer to command line methods as
&lt;a href="https://tacaswell.github.io/think-like-git.html"&gt;&amp;ldquo;incantations&lt;/a&gt;.  However, &lt;a href="https://blog.nelhage.com/post/computers-can-be-understood/"&gt;computers can be
understood&lt;/a&gt;.  This
quote should be re-framed more optimistic way as:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;All &amp;lsquo;magic&amp;rsquo; is just good engineering&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This framing acknowledges the hard work that goes into making computers &amp;ldquo;just
work&amp;rdquo;.  The next time you use an computer and it is perfect, smooth experience
that exactly solves your problem remember there was a team of people who worked
very hard to make that happen.  There is work at every level, from designing
then interaction, to implementing the layers involved, to making sure the
services at every layer of the stack are running to designing and fabricating
the hardware.  If any layer of this (massive) stack does not work just right,
your experience will fail.&lt;/p&gt;
&lt;p&gt;I find this an empowering point of view.  Magic is mystical, arcane, something
secret that is closely held, something that you have to be born with, something
super natural.  Once something is deemed &amp;ldquo;magic&amp;rdquo; it is out of the ken of mere
mortals; it must be accepted as-is, there is no point in even trying.&lt;/p&gt;
&lt;p&gt;On the other hand science and engineering exist to be understood.  They are
systematic frameworks to understand the physical world and bend it to our will
respectively.  Understanding any given system (natural or engineered) may not
be easy and may take more time and energy than you want to spend, but it is
always possible in principle.  The statement is never &amp;ldquo;I can not understand
this&amp;rdquo;, it is always &amp;ldquo;I do not understand this &lt;em&gt;yet&lt;/em&gt;&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;The tools and methods of science and engineering are open to anyone who has the
time, resources, and inclination to use them; anyone who says differently
(&lt;a href="https://youtu.be/KS_f6O8mWsk"&gt;like those who deny life is pain&lt;/a&gt;) is selling
something.  However, while this position is well and good in theory, in reality
there are massive structural inequalities in who actually participates in STEM
broadly and open source development specifically.  It is incumbent on those of
us who work in STEM fields to ensure equitable access and opportunity to all.
Just like a good science challenge this is not going to be easy, but it must be
&amp;ldquo;We have not fixed this &lt;em&gt;yet&lt;/em&gt;&amp;rdquo;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Reference&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://lab.cccb.org/en/arthur-c-clarke-any-sufficiently-advanced-technology-is-indistinguishable-from-magic/"&gt;Art responding to the Arthur C Clark
  quote&lt;/a&gt;
  I am (obviously) not the first person to re-imagine and re-frame this quote.&lt;/li&gt;
&lt;li&gt;FSF &lt;a href="https://fsfe.org/freesoftware/#freedoms"&gt;Four Freedoms&lt;/a&gt; of open
  software.  Proprietary systems can be reverse-engineered, but understanding a
  system is far easier if you can read the source&lt;/li&gt;
&lt;/ul&gt;</content><category term="Software Development"></category><category term="software"></category></entry><entry><title>Think Like Git</title><link href="https://tacaswell.github.io/think-like-git.html" rel="alternate"></link><published>2022-05-24T01:00:00-04:00</published><updated>2022-05-24T22:35:00-04:00</updated><author><name>Thomas A Caswell</name></author><id>tag:tacaswell.github.io,2022-05-24:/think-like-git.html</id><summary type="html">&lt;p&gt;This article is for people who already know how to use &lt;code&gt;git&lt;/code&gt; day-to-day, but
want a deeper understand of the &lt;em&gt;why&lt;/em&gt; of &lt;code&gt;git&lt;/code&gt; to do a better job reasoning
about what should or should not be possible rather than just memorizing
incantations.&lt;/p&gt;</summary><content type="html">&lt;p&gt;While this text is going to (mostly) refer to the &lt;code&gt;git&lt;/code&gt; CLI because it is the
lowest common denominator (everyone who uses &lt;code&gt;git&lt;/code&gt; has access to the CLI), there
are many richer graphical user interfaces available (likely built into your
IDE).  There is nothing wrong with using a GUI for working with &lt;code&gt;git&lt;/code&gt; nor is
the CLI &amp;ldquo;morally superior&amp;rdquo; &amp;ndash; anyone who says otherwise is engaging in
gatekeeping nonsense.  I personally use &lt;a href="https://magit.vc/"&gt;magit&lt;/a&gt; and
&lt;a href="https://git-scm.com/docs/gitk/"&gt;gitk&lt;/a&gt; in my day-to-day work.  &lt;a href="https://xkcd.com/378/"&gt;Real
programers&lt;/a&gt; use tools that make them effective, if a GUI
makes your life easier use it.&lt;/p&gt;
&lt;p&gt;For each of the CLI interfaces I&amp;rsquo;m highlighting I am only covering the
functionality relevant to the point I&amp;rsquo;m making.  Many of these CLIs can do more
(and sometimes wildly different) things, see the links back to the
documentation for the full details.&lt;/p&gt;
&lt;p&gt;This article is focused on the version tracking aspect of &lt;code&gt;git&lt;/code&gt;.  I will only
touch in passing on the fact that &lt;code&gt;git&lt;/code&gt; uses &lt;a href="https://git-scm.com/book/en/v2/Git-Internals-Git-Objects"&gt;content based
addressing&lt;/a&gt; and how
it actually encodes the state of the repository at each commit.  These details
are interesting in their own right and critical to the implementation of &lt;code&gt;git&lt;/code&gt;
being efficient (both time and space wise), but are out of scope for this
article.&lt;/p&gt;
&lt;p&gt;Another article in a similar vein to this, but starting from a user story and
building up is &lt;a href="https://tom.preston-werner.com/2009/05/19/the-git-parable.html"&gt;the Git Parable
&lt;/a&gt;.  When I read
this essay years ago it made &lt;code&gt;git&lt;/code&gt; &amp;ldquo;click&amp;rdquo; for me.  If you have not read it, I
suggest you go read it instead of this!&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Table of Contents&lt;/strong&gt;&lt;/p&gt;
&lt;div class="toc"&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#gits-view-of-the-world"&gt;git&amp;rsquo;s view of the world&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#what-does-it-mean-to-be-distributed-but-centralized"&gt;What does it mean to be distributed (but centralized)?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#get-a-graph-to-work-with"&gt;Get a graph to work with&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#label-a-commit"&gt;Label a commit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#compare-source-between-nodes"&gt;Compare source between nodes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#look-at-the-whole-tree"&gt;Look at the whole tree&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#look-at-a-node"&gt;Look at a node&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#adding-nodes"&gt;Adding nodes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#discard-changes"&gt;discard changes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#change-or-move-nodes"&gt;change or move nodes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#sharing-with-your-friends"&gt;Sharing with your friends&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#checking-out-more-than-one-commit"&gt;checking out more than one commit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#git-config"&gt;git config&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#other-things-you-might-want-to-do"&gt;Other things you might want to do&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#other-resources"&gt;Other resources&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#acknowledgments"&gt;Acknowledgments&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 id="gits-view-of-the-world"&gt;git&amp;rsquo;s view of the world&lt;/h2&gt;
&lt;p&gt;At the core, &lt;code&gt;git&lt;/code&gt; keeps track of many (many) copies of your code, creating a
snapshot whenever you commit.  Along with the code, &lt;code&gt;git&lt;/code&gt; attaches to each a
block of text, information about who and when the code was written and
committed, and what commits are the &amp;ldquo;parents&amp;rdquo; to from a &lt;strong&gt;commit&lt;/strong&gt;.  The hash
of all of this serves both as a globally unique name for the commit and to
validate the commit.&lt;/p&gt;
&lt;p&gt;Because each commit knows its parent(s), the commits form a &lt;a href="https://en.wikipedia.org/wiki/Directed_acyclic_graph"&gt;directed acyclic
graph&lt;/a&gt; (DAG).  The code
snap-shots and metadata are the nodes, the parents relationships define the
edges, and because you can only go backwards in history (commits do not know
who their children are) it is directed.  DAG&amp;rsquo;s are a relatively common data
structure in programming (and if you need to work with them in Python checkout
&lt;a href="http://networkx.org/documentation/stable/"&gt;networkx&lt;/a&gt;).  By identifying a DAG
as the core data structure of &lt;code&gt;git&lt;/code&gt;&amp;rsquo;s view of history we can start to develop
intuition of what operations will be easy on &lt;code&gt;git&lt;/code&gt; history (if they would be
easy to express via operations on a DAG).  Using this intuition, we can
(hopefully) start to guess how &lt;code&gt;git&lt;/code&gt; would probably implement the functionality
we need to actually get our work done!&lt;/p&gt;
&lt;p&gt;Because the hash includes information about the parents the tree of commits
forms a variation on a &lt;a href="https://en.wikipedia.org/wiki/Merkle_tree"&gt;Merkle
Tree&lt;/a&gt;.  Using these hashes you can
validate that a &lt;code&gt;git&lt;/code&gt; repository is self consistent and that the source you
have checked out is indeed the source that was checked in.  If you and a
collaborator both have a clone of a shared project then they can send you just
the hash of a commit and you can be sure that you have both an identical
working tree and identical history.&lt;/p&gt;
&lt;p&gt;Given such a graph, what operations would we want to do to it?  For example we
want to&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;get a repository to work with (&lt;code&gt;git clone&lt;/code&gt;, &lt;code&gt;git init&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;give commits human readable names (&lt;code&gt;git tag&lt;/code&gt;, &lt;code&gt;git branch&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;compare source between commits (&lt;code&gt;git diff&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;look at the whole graph of commits (&lt;code&gt;gitk&lt;/code&gt;, &lt;code&gt;git log&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;look at a commit (both the code content and meta-data) (&lt;code&gt;gitk&lt;/code&gt;, &lt;code&gt;git switch&lt;/code&gt;, &lt;code&gt;git checkout&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;add commits (&lt;code&gt;git stage&lt;/code&gt;, &lt;code&gt;git add&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;discard changes (both local changes and whole commits) (&lt;code&gt;git reset&lt;/code&gt;, &lt;code&gt;git restore&lt;/code&gt;, &lt;code&gt;git clean&lt;/code&gt;, &lt;code&gt;git checkout&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;change/move commits around the graph (&lt;code&gt;git rebase&lt;/code&gt;, &lt;code&gt;git cherry-pick&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;share your code (and history) with your friends (&lt;code&gt;git push&lt;/code&gt;, &lt;code&gt;git fetch&lt;/code&gt;, &lt;code&gt;git remote&lt;/code&gt;, &lt;code&gt;git merge&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;have more than one commit checked out at a time (&lt;code&gt;git worktree&lt;/code&gt;)&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id="what-does-it-mean-to-be-distributed-but-centralized"&gt;What does it mean to be distributed (but centralized)?&lt;/h2&gt;
&lt;p&gt;From a technical stand point no clone of a &lt;code&gt;git&lt;/code&gt; repository is more special
than any other.  Each contains a self consistent section of the history of the
repository and they can all share that information with each other.  From a
certain point of view, there is only one global history which consists of every
commit any developer on any computer has ever created and any given computer
only ever has a sub-graph of the full history.&lt;/p&gt;
&lt;p&gt;While technically pure, fully distributed collaboration is deeply impractical.
Almost every project has socially picked a central repository to be considered
the &amp;ldquo;canonical&amp;rdquo; repository.  For example for Matplotlib
&lt;a href="https://github.com/matplotlib/matplotlib"&gt;matplotlib/matplotlib&lt;/a&gt; is &lt;em&gt;the&lt;/em&gt; ground
truth repository.  At the end of the day what &lt;em&gt;is&lt;/em&gt; Matplotlib the library is
that git history, full stop.  Because of the special social role that
repository holds only people with commit rights are able to push to that
repository and we have a agreed on social process for deciding who gets that
access and what code gets merged.  When people talk about a project having a
&amp;ldquo;hard fork&amp;rdquo; or a &amp;ldquo;hostile fork&amp;rdquo; they are referring to a community that has
split about which repository is &amp;ldquo;the one&amp;rdquo; and who has the ability to push to
it.&lt;/p&gt;
&lt;p&gt;Similarly, while every commit has a (gloablly) unique name &amp;ndash; its hash &amp;ndash; they
are effectively unusable.  The branch and tag names that we use are for the
humans and any meaning we attach to the names is purely social.  Within the
canonical repository there is a particular branch which is identified as &lt;em&gt;the&lt;/em&gt;
branch for new development along and optionally a handful of other &amp;ldquo;official&amp;rdquo;
branches for maintaining bug-fix series. The exact details of the names, the
life cycles and the development workflow will vary from team-to-team.  For
example on Matplotlib we have a &lt;code&gt;main&lt;/code&gt; branch for new development, the &lt;code&gt;vX.Y.x&lt;/code&gt;
branches which are the maintenance branches for each &lt;code&gt;vX.Y.0&lt;/code&gt; minor release,
and &lt;code&gt;vX.Y-doc&lt;/code&gt; for the version specific documentation.  To &lt;code&gt;git&lt;/code&gt; these names
are meaningless, but socially they are critical.&lt;/p&gt;
&lt;p&gt;In the standard fork-based development workflow that many open source software
projects use the commits move from less visible but loosely controlled parts of
the global graphs to more public and controlled parts.  For example anyone can
create commits on their local clone at will!  However no one else can (easily)
see them and those commits are inaccessible to almost everyone else who has
part of the total graph.  A developer can then choose to publish their commits
to a public location (for example I push all of my work on Matplotlib to
&lt;a href="https://github.cm/tacaswell/matplotlib"&gt;tacaswell/matplotlib&lt;/a&gt; first).  Once
the commits are public anyone can see them but only a handful of people are
likely to actually access them.  To get the code into the canonical repository,
and hence used by everyone, the user can request that the committers to the
canonical repository &amp;ldquo;pull&amp;rdquo; or &amp;ldquo;merge&amp;rdquo; their branch into the default branch.
If this &amp;ldquo;pull request&amp;rdquo; is accepted and merged to the default branch then that
code (and commit history) is forever part of the project&amp;rsquo;s history.&lt;/p&gt;
&lt;h2 id="get-a-graph-to-work-with"&gt;Get a graph to work with&lt;/h2&gt;
&lt;p&gt;The most common way to get a copy of a project history is not to start &lt;em&gt;ab initio&lt;/em&gt;,
but to get a copy of a preexisting history.  Any given project only starts
once, but over time will receive many more commits (this repository already has
20+ commits, Matplotlib has over 43k, the kernel has &lt;a href="https://www.linuxfoundation.org/blog/the-one-millionth-commit-the-search-for-the-lucky-linux-kernel-contributor/"&gt;over 1
million&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;To get a local copy of a repository so you can start working on it you use the
&lt;code&gt;git clone&lt;/code&gt; &lt;a href="https://git-scm.com/docs/git-clone"&gt;sub-command&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;clone&lt;span class="w"&gt; &lt;/span&gt;url_to_remote&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# will create a new directory in the CWD&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;By default &lt;code&gt;git&lt;/code&gt; will fetch everything from the remote repository (there are
ways &lt;a href="https://github.blog/2020-12-21-get-up-to-speed-with-partial-clone-and-shallow-clone/"&gt;to reduces this for big
repositories&lt;/a&gt;).
If you clone from the canonical repository then you have the complete
up-to-date official history of the project on your computer!&lt;/p&gt;
&lt;p&gt;If you need to create a new repository use the &lt;code&gt;git init&lt;/code&gt;
&lt;a href="https://git-scm.com/docs/git-init"&gt;sub-command&lt;/a&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;init
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;However, I have probably only ever used &lt;code&gt;git init&lt;/code&gt; a few dozen times in my
career, where as I use &lt;code&gt;git clone&lt;/code&gt; a few dozen times a week.&lt;/p&gt;
&lt;h2 id="label-a-commit"&gt;Label a commit&lt;/h2&gt;
&lt;p&gt;From the hash we have a globally unique identifier for each commit, however
these hashes look something like: &lt;code&gt;6f8bc7c6f192f664a7ab2e4ff200d050bb2edc8f&lt;/code&gt;.
While unique and well-suited for a computer, it is neither memorable nor does
it roll off the tongue.  This is partly ameliorated because anyplace that the
&lt;code&gt;git&lt;/code&gt; interface takes a SHA you can instead pass a prefix, e.g.  &lt;code&gt;6f8bc7&lt;/code&gt; for
the SHA above.  However the number of characters needed ensure the that the
prefix is actually unique &lt;a href="https://blog.cuviper.com/2013/11/10/how-short-can-git-abbreviate/"&gt;depends on the size of the
repository&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To give a human-friendly name to a commit git offers two flavors of labels:
&lt;strong&gt;branches&lt;/strong&gt; and &lt;strong&gt;tags&lt;/strong&gt;.  The conceptual difference is that a &lt;strong&gt;branch&lt;/strong&gt; is
expected to move between commits over time and &lt;strong&gt;tags&lt;/strong&gt; are fixed to a
particular commit for all time.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Branches&lt;/strong&gt; point to a fixed &lt;em&gt;concept&lt;/em&gt;.  As discussed above, most repositories
have a socially designated &amp;ldquo;canonical branch&amp;rdquo; that is the point of truth for
the development effort.  The exact name does not matter, but common names
include &amp;ldquo;main&amp;rdquo;, &amp;ldquo;trunk&amp;rdquo;, or &amp;ldquo;devel&amp;rdquo;.  It is also conventional to do new
development on a &amp;ldquo;development&amp;rdquo; branch, named anything but the canonical branch
name.  This enables you to keep multiple independent work directions in flight
at a time and easily discard any work turns out to be less of a good idea than
you thought.&lt;/p&gt;
&lt;p&gt;To list, create, and delete branches use the &lt;code&gt;git branch&lt;/code&gt;
&lt;a href="https://git-scm.com/docs/git-branch"&gt;sub-command&lt;/a&gt;.  The most important
incantations are:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;branch&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;# list local branches&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;branch&lt;span class="w"&gt; &lt;/span&gt;-c&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;name&amp;gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# create a branch&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;branch&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;name&amp;gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# delete a branch, if safe&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;branch&lt;span class="w"&gt; &lt;/span&gt;-D&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;name&amp;gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# delete a branch over git&amp;#39;s concerns&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In &lt;code&gt;git&lt;/code&gt; branches are cheap to make, when in doubt, make a new branch!&lt;/p&gt;
&lt;p&gt;In contrast &lt;strong&gt;tags&lt;/strong&gt; label a specific commit and never move.  This is used most
often for identifying released versions of software (e.g. v1.5.2).  To work with &lt;strong&gt;tags&lt;/strong&gt;
use the &lt;code&gt;git tag&lt;/code&gt; &lt;a href="https://git-scm.com/docs/git-tag"&gt;sub-command&lt;/a&gt;.  The most important incantations
are:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;tag&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="c1"&gt;# list tags&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;tag&lt;span class="w"&gt; &lt;/span&gt;-a&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# create a new tag&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You should always create &amp;ldquo;annotated&amp;rdquo; tags.  If the commit is important enough
to get a permanent name, it is important enough get an explanation of why you
gave it a name.&lt;/p&gt;
&lt;p&gt;In &lt;code&gt;git&lt;/code&gt; jargon these are &amp;ldquo;refs&amp;rdquo;.  See &lt;a href="https://git-scm.com/book/en/v2/Git-Internals-Git-References"&gt;the
docs&lt;/a&gt; if you want
even more details about how &lt;code&gt;git&lt;/code&gt; encodes these.&lt;/p&gt;
&lt;h2 id="compare-source-between-nodes"&gt;Compare source between nodes&lt;/h2&gt;
&lt;p&gt;There is a &amp;ldquo;dual space&amp;rdquo; relationship between the code state at each commit and
the differences between the commits.  If you have one you can always compute
the other. On first glance the natural way to track the changes of source over
time is to track the differences (this is in fact how many earlier version
control systems worked!).  However git (and mercurial) instead track the full
state of the of the source at each commit which solves a number of performance
problems and enables some additional operations.&lt;/p&gt;
&lt;p&gt;Because the diffs between subsequent commits are derived, it is just as easy to
compute the diff between any two commits!  Using the &lt;code&gt;git diff&lt;/code&gt;
&lt;a href="https://git-scm.com/docs/git-diff"&gt;sub-command&lt;/a&gt;.  To get the difference between two
commits :&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;diff&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;before&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;after&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;which will give you a patch that if applied to the &lt;code&gt;&amp;lt;before&amp;gt;&lt;/code&gt; commit will land
you at the &lt;code&gt;&amp;lt;after&amp;gt;&lt;/code&gt; commit.  If you want to get a patch that will undo a
change swap the order of the commits.&lt;/p&gt;
&lt;p&gt;Calling &lt;code&gt;git diff&lt;/code&gt; without any arguments is very common command that will show
any uncommitted changes in your working tree.&lt;/p&gt;
&lt;h2 id="look-at-the-whole-tree"&gt;Look at the whole tree&lt;/h2&gt;
&lt;p&gt;It is useful to look at the whole graph.  There is the &lt;code&gt;git log&lt;/code&gt;
&lt;a href="https://git-scm.com/docs/git-log"&gt;sub-command&lt;/a&gt; which will show you text
versions of history, however this is an application where a GUI interface
really shines.  There is so much information available:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the commit message&lt;/li&gt;
&lt;li&gt;the author and committer&lt;/li&gt;
&lt;li&gt;dates&lt;/li&gt;
&lt;li&gt;the computed diffs&lt;/li&gt;
&lt;li&gt;the connectivity between the commits&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;that it is difficult to see it all and navigate it in a pure text interface.&lt;/p&gt;
&lt;p&gt;My preferred tool for exploring the full history is
&lt;a href="https://git-scm.com/docs/gitk/"&gt;gitk&lt;/a&gt; which is typically installed with git.
It is a bit ugly, but it works!  In addition to visualizing the tree it also
has a user interface for searching both the commit messages and the code
changes and for limiting the history to only particular files.&lt;/p&gt;
&lt;h2 id="look-at-a-node"&gt;Look at a node&lt;/h2&gt;
&lt;p&gt;When working with a git repository on your computer you almost always have one
of the commits materialized into a working tree (or more than one with the
&lt;code&gt;git worktree&lt;/code&gt; &lt;a href="https://git-scm.com/docs/git-worktree"&gt;sub-command&lt;/a&gt;).  The working
tree is, as the name suggests, where you actually do your work!  We will come
back to this in the next section.&lt;/p&gt;
&lt;p&gt;To checkout a particular &lt;strong&gt;commit&lt;/strong&gt; (or &lt;strong&gt;tag&lt;/strong&gt; or &lt;strong&gt;branch&lt;/strong&gt;) you can use the
&lt;code&gt;git checkout&lt;/code&gt; &lt;a href="https://git-scm.com/docs/git-checkout"&gt;sub-command&lt;/a&gt; as&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;checkout&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;commit&lt;span class="w"&gt; &lt;/span&gt;hash&amp;gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# checks out a particular commit&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;checkout&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;tag&lt;span class="w"&gt; &lt;/span&gt;name&amp;gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;# checks out a particular tag&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;checkout&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;branch&lt;span class="w"&gt; &lt;/span&gt;name&amp;gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# checks out a particular branch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In addition, there is also a new &lt;code&gt;git switch&lt;/code&gt;
&lt;a href="https://git-scm.com/docs/git-switch"&gt;sub-command&lt;/a&gt; that is specifically for
switching branches.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;switch&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;branch&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;which is more scoped (&lt;code&gt;git checkout&lt;/code&gt; has a number of other features) and
clearly named.&lt;/p&gt;
&lt;p&gt;If you want to see the history of what commits you have had checked out (as
opposed to the history the repository) you can use the &lt;code&gt;git reflog&lt;/code&gt;
&lt;a href="https://git-scm.com/docs/git-reflog"&gt;sub-command&lt;/a&gt;.  While not something to use
day-to-day, it can save your bacon in cases where you have accidentally lost
references to a commit.&lt;/p&gt;
&lt;h2 id="adding-nodes"&gt;Adding nodes&lt;/h2&gt;
&lt;p&gt;The most important, and likely most common, operation we do on the graph is to
add new commits!&lt;/p&gt;
&lt;p&gt;As mention above when you checkout a branch on your computer you have a working
tree that starts at the state of the commit you have checked out.  There is
special name that can be used as a commit &lt;code&gt;HEAD&lt;/code&gt; which means &amp;ldquo;the commit that
is currently checked out in your work tree&amp;rdquo;.  There is also the short hand
&lt;code&gt;HEAD^&lt;/code&gt; which means &amp;ldquo;the commit before the one checked out&amp;rdquo;, &lt;code&gt;HEAD^^&lt;/code&gt; which
means &amp;ldquo;the commit two before the one checked out&amp;rdquo;, and so on for repeated &lt;code&gt;^&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As you make changes there are two common commands &lt;code&gt;git status&lt;/code&gt;
&lt;a href="https://git-scm.com/docs/git-status"&gt;sub-command&lt;/a&gt; and &lt;code&gt;git diff&lt;/code&gt;
&lt;a href="https://git-scm.com/docs/git-diff"&gt;sub-command&lt;/a&gt;.  &lt;code&gt;git status&lt;/code&gt; will give you a
summary of what changes you have in the local tree, relative to &lt;code&gt;HEAD&lt;/code&gt; and what
changes are staged. &lt;code&gt;git diff&lt;/code&gt;, when called with no arguments will show the detailed
diff between the current working tree and &lt;code&gt;HEAD&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;As you work on your code, &lt;code&gt;git&lt;/code&gt; does not require you to commit all of your
changes at once, but to enable this committing is two a stage process.  The
first step is to use the &lt;code&gt;git add&lt;/code&gt;
&lt;a href="https://git-scm.com/docs/git-add"&gt;sub-command&lt;/a&gt; to stage changes&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;path/to/file&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# to stage all the changes in a file&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;# to commit by hunk&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once you have staged all of the changes you want, you create a new commit via the
&lt;code&gt;git commit&lt;/code&gt; &lt;a href="https://git-scm.com/docs/git-commit"&gt;sub-command&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;commit&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Short Message&amp;quot;&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;# commit with a short commit message&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;commit&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="c1"&gt;# open an editor to write a commit message&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Writing a commit message is one of the most important parts of using git.
While it is frequently possible to, only from the source, reconstruct the what
of a code change it can be impossible to reconstruct the &lt;em&gt;why&lt;/em&gt; of the change.
The commit message is a place that you can leave notes to your collaborators
explaining the motivations of the change.  Remember that your most frequent
collaborator is your future / past self!  For a comprehensive guide to writing
good commit messages see &lt;a href="https://cbea.ms/git-commit/"&gt;this article&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As &lt;code&gt;git&lt;/code&gt; encourages the creation of &lt;strong&gt;branches&lt;/strong&gt; for new development, when the
work is done (via the cycle above) we will need to merge this work back into
the canonical branch which is done via the &lt;code&gt;git merge&lt;/code&gt;
&lt;a href="https://git-scm.com/docs/git-merge"&gt;sub-command&lt;/a&gt;.  By default, this will
create a new commit on your current branch who has two parents (the tips of
each branch involved).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;merge&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;other&lt;span class="w"&gt; &lt;/span&gt;branch&amp;gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;# merge other branch into the current branch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you are using a code hosting platform (GitHub, GitLab, BitBucket, &amp;hellip;) this
command will typically be done through a the web UI&amp;rsquo;s &amp;ldquo;merge&amp;rdquo; button.&lt;/p&gt;
&lt;h2 id="discard-changes"&gt;discard changes&lt;/h2&gt;
&lt;p&gt;Not all changes are a good idea, sometimes you need to go back.&lt;/p&gt;
&lt;p&gt;If you have not yet committed your changes then they can be discarded using the
&lt;code&gt;git checkout&lt;/code&gt; &lt;a href="https://git-scm.com/docs/git-checkout"&gt;sub-command&lt;/a&gt; (yes the
same one we used to change branches)&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;checkout&lt;span class="w"&gt; &lt;/span&gt;path/to/file&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# discard local changes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;There is also the new &lt;code&gt;git restore&lt;/code&gt; &lt;a href="https://git-scm.com/docs/git-restore"&gt;sub-command&lt;/a&gt;
which is more tightly scoped to discarding local file changes&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;restore&lt;span class="w"&gt; &lt;/span&gt;path/to/file
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you have files in your working directory that &lt;code&gt;git&lt;/code&gt; is not currently tracking you
can use the &lt;code&gt;git clean&lt;/code&gt; &lt;a href="https://git-scm.com/docs/git-clean"&gt;sub-command&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;clean&lt;span class="w"&gt; &lt;/span&gt;-xfd&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# purge any untracked files (including ignored files)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you need to discard &lt;strong&gt;commits&lt;/strong&gt; you can use the &lt;code&gt;git reset&lt;/code&gt;
&lt;a href="https://git-scm.com/docs/git-reset"&gt;sub-command&lt;/a&gt;.  By default &lt;code&gt;git reset&lt;/code&gt; will
change the currently checked out commit but not change your working tree (so you keep
all of the code changes).&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;reset&lt;span class="w"&gt; &lt;/span&gt;HEAD^&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;# move the branch back one, keep working tree the same&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;reset&lt;span class="w"&gt; &lt;/span&gt;HEAD^^&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;# move the branch back two, keep working tree the same&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;reset&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;a&lt;span class="w"&gt; &lt;/span&gt;SHA1&amp;gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;# move the branch a commit, keep working tree the same&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This can be very useful if you like the changes you made, but not the commits
or commit messages.&lt;/p&gt;
&lt;p&gt;Alternatively if you want to discard the commits and the changes you can use
the &lt;code&gt;--hard&lt;/code&gt; flag:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;reset&lt;span class="w"&gt; &lt;/span&gt;--hard&lt;span class="w"&gt; &lt;/span&gt;HEAD^&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;# move the branch back one, discard all changes&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;reset&lt;span class="w"&gt; &lt;/span&gt;--hard&lt;span class="w"&gt; &lt;/span&gt;HEAD^^&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# move the branch back two, discard all changes&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;reset&lt;span class="w"&gt; &lt;/span&gt;--hard&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;a&lt;span class="w"&gt; &lt;/span&gt;SHA1&amp;gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# move the branch a commit, discard all changes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Be aware that these can be a destructive commands!  If you move a branch back
there maybe commits that are inaccessible (remember commits only know their
parents).  This is where the &lt;code&gt;git reflog&lt;/code&gt;
&lt;a href="https://git-scm.com/docs/git-reflog"&gt;sub-command&lt;/a&gt; can help recover the lost
commits.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;git&lt;/code&gt; commands may create objects behind the scenes that ultimately become
inaccessible.  &lt;code&gt;git&lt;/code&gt; will on its own clean up, but you can manually trigger
this clean up via &lt;code&gt;git gc&lt;/code&gt; &lt;a href="https://git-scm.com/docs/git-gc"&gt;sub-command&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you have accidentally committed something sensitive, but not yet pushed, you
can use these tools to purge it.  If you have push the commit you will need
&lt;a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/removing-sensitive-data-from-a-repository"&gt;some higher test
tools&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="change-or-move-nodes"&gt;change or move nodes&lt;/h2&gt;
&lt;p&gt;Due to the way the hashes work in &lt;code&gt;git&lt;/code&gt; you can not truly &lt;em&gt;change&lt;/em&gt; a commit,
but you can modify and recommit it or make copies elsewhere in the graph.
Remember that if you have already shared the commits you are replacing you will
have to force-push them again (see below).  Be very careful about doing this to
any branch that many other people are using.&lt;/p&gt;
&lt;p&gt;If you have just created a commit and realized you need to add one more change
you can use the &lt;code&gt;--amend&lt;/code&gt; flag to &lt;code&gt;git commit&lt;/code&gt;
&lt;a href="https://git-scm.com/docs/git-commit"&gt;sub-command&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# hack&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;path/to/file&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;# stage the changes like normal&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;commit&lt;span class="w"&gt; &lt;/span&gt;--amend&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;# add the changes to the HEAD commit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This does not actually &lt;em&gt;change&lt;/em&gt; the old commit.  A commit is uniquely
identified by its hash and the hash includes the state of the code, thus
&amp;ldquo;amending&amp;rdquo; a commit creates a &lt;em&gt;new&lt;/em&gt; commit and then resets the current branch
to point to the new commit and orphans the old commit.&lt;/p&gt;
&lt;p&gt;If you want to move a range of commits from one place to another you can use
the &lt;code&gt;git rebase&lt;/code&gt; &lt;a href="https://git-scm.com/docs/git-rebase"&gt;sub-command&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;rebase&lt;span class="w"&gt; &lt;/span&gt;target_branch&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;# rebase the current branch onto target_branch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;which will attempt to &amp;ldquo;replay&amp;rdquo; the changes in each of the commits on your
current branch on top of &lt;code&gt;target_branch&lt;/code&gt;.  If there are conflicts that &lt;code&gt;git&lt;/code&gt;
can not automatically resolve it will pause for you to manually resolve the
conflicts and stage the changes to continue or abort the whole rebase&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;rebase&lt;span class="w"&gt; &lt;/span&gt;--continue&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;#  continue with your manual resolution&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;rebase&lt;span class="w"&gt; &lt;/span&gt;--abort&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;#  abort and go back to where you started&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you want to re-order, drop or combine commits you can use:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;rebase&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt;                &lt;/span&gt;&lt;span class="c1"&gt;# interactively rebase, squash and re-order&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;which will open an editor with instructions.  This can be particularly useful
if you want commit early and often as you work, but when you are done re-order
and re-arrange the changes into a smaller number of better organized commits to
tell a better story.&lt;/p&gt;
&lt;p&gt;Common reasons to be asked to rebase (and squash) a branch is if your
development branch has grown merge conflicts and the project prefers rebasing
over merging the default branch back into the development branches or if your
commit history has too many &amp;ldquo;noise&amp;rdquo; commits (small typo fixes, reversions of
work, committing and then deleting files).&lt;/p&gt;
&lt;p&gt;To move a commit from one branch to another use the &lt;code&gt;git cherry-pick&lt;/code&gt;
&lt;a href="https://git-scm.com/docs/git-cherry-pick"&gt;sub-command&lt;/a&gt; which is conceptually
similar to &lt;code&gt;git rebase&lt;/code&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;cherry-pick&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;commit&amp;gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;# pick the commit on to the current branch&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;cherry-pick&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;commit&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# pick a merge commit onto the current branch&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;cherry-pick&lt;span class="w"&gt; &lt;/span&gt;--continue&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# continue if you have to manually resolve conflicts&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;cherry-pick&lt;span class="w"&gt; &lt;/span&gt;--skip&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;# drop a redundant commit&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;cherry-pick&lt;span class="w"&gt; &lt;/span&gt;--abort&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;# give up and go back to where you started&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In all of these cases, &lt;a href="https://git-scm.com/docs/git-reflog"&gt;sub-command&lt;/a&gt; can
be useful if things do not go as you expect!&lt;/p&gt;
&lt;h2 id="sharing-with-your-friends"&gt;Sharing with your friends&lt;/h2&gt;
&lt;p&gt;So far we have not talked much about any of the collaborative or distributed
nature of git.  Except for &lt;code&gt;git clone&lt;/code&gt;, every command so far can be done only
with information than &lt;code&gt;git&lt;/code&gt; has on your computer and can be done without a
network connection.  This lets you work in your own private enclave, either
temporarily, because you are working on a laptop on commuter rail or are not
yet ready to share your work, or permanently if you just prefer to work alone.&lt;/p&gt;
&lt;p&gt;While version control is useful if you are working alone (your most frequent
collaborator is your future / past self and version control can &lt;a href="https://tacaswell.github.io/how-i-learned-to-love-vcs.html"&gt;save you from
typos&lt;/a&gt;), it really shines when you are working
with other people.  To share code with others we need to a notion of a shared
history.  Given that under the hood git is a graph of nodes uniquely named by
their content &amp;ldquo;all&amp;rdquo; we have to do is be able to share information about the
commits, branches, and tags between the different computers!&lt;/p&gt;
&lt;p&gt;By default after an initial &lt;code&gt;git clone&lt;/code&gt; there is one &amp;ldquo;remote&amp;rdquo; pointing to where
ever you cloned from by default named &lt;code&gt;origin&lt;/code&gt;.  To modify an existing remote
or add a new remote use the &lt;code&gt;git remote&lt;/code&gt;
&lt;a href="https://git-scm.com/docs/git-remote"&gt;sub-command&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;remote&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;name&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;url&amp;gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;# add a new remote&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;remote&lt;span class="w"&gt; &lt;/span&gt;rm&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;name&amp;gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="c1"&gt;# delete a remote&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;remote&lt;span class="w"&gt; &lt;/span&gt;rename&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;old&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;new&amp;gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;# rename a remote from old -&amp;gt; new&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once you have one or more remotes updated the first thing we want to is be able
to get new commits from the remotes via &lt;code&gt;git fetch&lt;/code&gt;
&lt;a href="https://git-scm.com/docs/git-fetch"&gt;sub-command&lt;/a&gt; or &lt;code&gt;git remote&lt;/code&gt;
&lt;a href="https://git-scm.com/docs/git-remote"&gt;sub-command&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;fetch&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;name&amp;gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;# fetch just one remote&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;fetch&lt;span class="w"&gt; &lt;/span&gt;--all&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;# fetch all of the&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;remote&lt;span class="w"&gt; &lt;/span&gt;update&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="c1"&gt;# update all the remotes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;git pull&lt;/code&gt; &lt;a href="https://git-scm.com/docs/git-pull"&gt;sub-command&lt;/a&gt; combines a
fetch and a merge into one command.  While this seems convenient, it will
frequently generate unexpected merge commits that take longer to clean up than
being explicit about fetching and merging separately.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;merge&lt;span class="w"&gt; &lt;/span&gt;--ff-only&lt;span class="w"&gt; &lt;/span&gt;remote/branch&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="c1"&gt;# merge remote branch into the local branch&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;--ff-only&lt;/code&gt; flag fails unless the history can be &amp;ldquo;fast forwarded&amp;rdquo; meaning
that only the remote branch has new commits.&lt;/p&gt;
&lt;p&gt;To share your work with others you need to put the commits someplace other
people can see it.  The exact details of this depend on the workflow of the
project and team, but if using a hosting platform this is done via the &lt;code&gt;git
push&lt;/code&gt; &lt;a href="https://git-scm.com/docs/git-push"&gt;sub-command&lt;/a&gt;.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;push&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;remote&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;branch_name&amp;gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="c1"&gt;# push the branch_name to remote&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Given that in a typical workflow you are likely to be pushing to the same
branch on the same remote many times &lt;code&gt;git&lt;/code&gt; has streamlined ways of keeping track
of the association between your local branch and a &lt;a href="https://git-scm.com/book/en/v2/Git-Branching-Remote-Branches"&gt;remote
branch&lt;/a&gt; on a
(presumably) more public location.  By telling git about this association we
save both typing and the chance of mistakes due to typos.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;branch&lt;span class="w"&gt; &lt;/span&gt;--set-upstream-to&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;remote&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# set an &amp;quot;upstream&amp;quot;&lt;/span&gt;
git&lt;span class="w"&gt; &lt;/span&gt;push&lt;span class="w"&gt;                              &lt;/span&gt;&lt;span class="c1"&gt;# &amp;quot;do the right thing&amp;quot; with upstream set&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you try to push commits to a remote branch that has commits that are not on
your local branch git will reject the push.  The course of action depends on
why you are missing commits.  If there are new commits on the remote branch
that you have not fetched before, then you should either merge the remote
branch into your local branch before pushing or rebase your local branch on the
remote branch and push again.&lt;/p&gt;
&lt;p&gt;Because git can not tell the difference new commits on the remote and old
commits on the remote because you have re-written history locally, either via
&lt;code&gt;git commit --ammend&lt;/code&gt; or &lt;code&gt;git rebase&lt;/code&gt;, then you have to do something a bit ....
dangerous.  &lt;code&gt;git&lt;/code&gt; detecting that if the remote branch were to be updated to
where the local branch it would make some commits inaccessible and protecting
you from yourself.  However, if you are sure we can tell &lt;code&gt;git&lt;/code&gt; to trust our
judgment and do it anyway:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;push&lt;span class="w"&gt; &lt;/span&gt;--force-with-lease
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Be very careful about doing this to branches that other people are relying on
and have checked out.  Other people will have the same problem you just had,
but in reverse.  &lt;code&gt;git&lt;/code&gt; can not tell that the re-written commits are &amp;ldquo;right&amp;rdquo; and
the history on the other users computer are &amp;ldquo;wrong&amp;rdquo;.  They will be presented
with the same options you just had and may re-force-push your changes out of
existences.  We recently had to &lt;a href="https://discourse.matplotlib.org/t/default-branch-renamed-with-minor-edit-to-history/22367"&gt;re-write the history on the default Matplotlib
branch&lt;/a&gt;
and it required a fair amount of planning and work to manage.&lt;/p&gt;
&lt;h2 id="checking-out-more-than-one-commit"&gt;checking out more than one commit&lt;/h2&gt;
&lt;p&gt;When you checkout a commit &lt;code&gt;git&lt;/code&gt; materializes the code into the directory where
the repository is cloned and your local directory is made to match the tree of
the commit.  Thus, it is logically impossible to have more than one commit
checked out at once.  However, it can be extremely useful to have more than one
commit checked out at once if you are working on a project with multiple &amp;ldquo;live&amp;rdquo;
branches.  One way around this is to simply clone the repository N times,
however because each repository is unaware of the other, you will have N
complete copies of the repository and each will have to synchronized with their
remotes independently, etc.  To make this efficient you can use the &lt;code&gt;git
worktree&lt;/code&gt; &lt;a href="https://git-scm.com/docs/git-worktree"&gt;sub-command&lt;/a&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;git&lt;span class="w"&gt; &lt;/span&gt;worktree&lt;span class="w"&gt; &lt;/span&gt;add&lt;span class="w"&gt; &lt;/span&gt;../somepath&lt;span class="w"&gt; &lt;/span&gt;branch_name
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This will share all of the &lt;code&gt;git&lt;/code&gt; resources and configuration with the main
&lt;code&gt;git&lt;/code&gt; worktree.  One surprising limitation of the worktrees is that you can
only have a given branch checked out in at most one worktree at a time.&lt;/p&gt;
&lt;h2 id="git-config"&gt;git config&lt;/h2&gt;
&lt;p&gt;There are many (many) knobs to configure the default behavior.  I suggest using
starting with these settings:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[transfer]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# actually verify the hashes&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;fsckobjects&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;[fetch]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# actually verify the hashes&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;fsckobjects&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# automatically drop branches that are deleted on the remotes&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;prune&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# fetch remotes in parallel&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;parallel&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;[receive]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# actually verify the hashes&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;fsckObjects&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;[pull]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# requires opting-into creating a merge commit locally.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# Given a platform based workflow, this prevents unintentional merge&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# commits that need to be un-wound&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;ff&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;only&lt;/span&gt;
&lt;span class="k"&gt;[merge]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# same as above&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;ff&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;only&lt;/span&gt;
&lt;span class="k"&gt;[color]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# colours are always fun&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;ui&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;auto&lt;/span&gt;
&lt;span class="k"&gt;[init]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# get ahead of the master -&amp;gt; main change&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;defaultBranch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;main&lt;/span&gt;
&lt;span class="k"&gt;[feature]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;manyFiles&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;true&lt;/span&gt;
&lt;span class="k"&gt;[alias]&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# this gives `git credit` as an alternative to `git blame`, just&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# puts you in a more positive mind set while using it.&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="na"&gt;credit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;blame&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h2 id="other-things-you-might-want-to-do"&gt;Other things you might want to do&lt;/h2&gt;
&lt;p&gt;There are obviously many things that &lt;code&gt;git&lt;/code&gt; can do that are not covered here.
Some things that I have had to do from time-to-time but did not make the cut
for this article include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;track the history of a line of code back in time (&lt;code&gt;gitk&lt;/code&gt;, &lt;code&gt;git blame&lt;/code&gt; + UI tooling, &lt;code&gt;git log&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;find the commit that broke something (&lt;code&gt;git bisect&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;merge un-related git histories into one (&lt;code&gt;git merge --allow-unrelated-histories&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;extract the history of a sub-directory into its own repository (&lt;code&gt;git filter-branch&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;purge a particular file (or change) from the history (&lt;code&gt;git filter-branch&lt;/code&gt; or
  &lt;a href="https://rtyley.github.io/bfg-repo-cleaner/"&gt;BFG repo-cleaner&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;fast searching (&lt;code&gt;git grep&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;ask &lt;code&gt;git&lt;/code&gt; to clean up after itself (&lt;code&gt;git gc&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="other-resources"&gt;Other resources&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ohshitgit.com/"&gt;recovering from git mistakes&lt;/a&gt; (&lt;a href="https://dangitgit.com/en"&gt;worksafe
  version&lt;/a&gt;): A humorous (and vulgar) guide to
  recovering when things go wrong.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://jvns.ca/blog/2018/10/27/new-zine--oh-shit--git-/"&gt;Julia Evans on git&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tom.preston-werner.com/2009/05/19/the-git-parable.html"&gt;the Git
  Parable&lt;/a&gt;: A
  just-so story that takes you from making backups by hand to agreeing with
  some of the more mystifying choices git makes.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://devblogs.microsoft.com/search?query=git&amp;amp;blog=%2Foldnewthing%2F"&gt;Anything Raymond
  Chen&lt;/a&gt;
  has written about git.  Some of these are just mind bending, like &lt;a href="https://devblogs.microsoft.com/oldnewthing/20190510-00/?p=102488"&gt;Mundane
  git commit-tree trick, Part 5: Squashing without git
  rebase&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Git internals &lt;a href="https://git-scm.com/book/en/v2/Git-Internals-Plumbing-and-Porcelain"&gt;straight from the horse&amp;rsquo;s
  mouth&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.blog/2020-12-17-commits-are-snapshots-not-diffs/"&gt;Commits are snapshots not diffs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="acknowledgments"&gt;Acknowledgments&lt;/h2&gt;
&lt;p&gt;Thank you to James Powell, Alex Held, Dora Caswell and the other beta-readers
who read (or listened to) early drafts of this post and provided valuable
feedback.  Thank you to Elliott Sales de Andrade for pointing out &lt;code&gt;git restore&lt;/code&gt;.&lt;/p&gt;</content><category term="Software Development"></category><category term="software"></category><category term="git"></category></entry><entry><title>Why I am fanatical about version control</title><link href="https://tacaswell.github.io/how-i-learned-to-love-vcs.html" rel="alternate"></link><published>2022-05-09T23:00:00-04:00</published><updated>2022-05-25T00:55:00-04:00</updated><author><name>Thomas A Caswell</name></author><id>tag:tacaswell.github.io,2022-05-09:/how-i-learned-to-love-vcs.html</id><summary type="html">&lt;p&gt;A short horror story that could have been prevented by git.&lt;/p&gt;</summary><content type="html">&lt;p&gt;So, there I was.  The year was 2007 and I was in the process of wrapping up the
research I had done as an undergraduate.  One of my tasks before heading off to
grad school was to archive all of the code I had written over the last two or
so years to &lt;a href="https://en.wikipedia.org/wiki/DVD%C2%B1R"&gt;DVD-R&lt;/a&gt; for the lab
archive.&lt;/p&gt;
&lt;p&gt;My &lt;a href="https://www.gnu.org/software/emacs/"&gt;editor&lt;/a&gt; writes temporary backup copies
while editing to the filename with a &lt;code&gt;~&lt;/code&gt; appended.  Thus, for every source file
&lt;code&gt;foo.m&lt;/code&gt; I had been working on there was a paired &lt;code&gt;foo.m~&lt;/code&gt; in the directory.  At
the time I was working in MATLAB and as was the convention had all off my
source in one directory.  This was the code that I used to generate the figures
in my senior thesis and &amp;ndash; more critically &amp;ndash; the figures of &lt;a href="https://www.sciencedirect.com/science/article/abs/pii/S0304399108003264"&gt;a paper we had in
preparation&lt;/a&gt; which
would require further revision.  Not wanting to archive transitory and
duplicate files I happily typed&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;all/of/my-source
rm&lt;span class="w"&gt; &lt;/span&gt;*&lt;span class="w"&gt; &lt;/span&gt;~
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;which very efficiently deleted all of the code I had written over the last two
years (&amp;ldquo;Computers: making mistakes faster than you possibly imagined!&amp;rdquo;).&lt;/p&gt;
&lt;p&gt;I did want any reasonable person would do and spent the next five minutes lying
on the floor trying to stave off a panic attack.&lt;/p&gt;
&lt;p&gt;In this particular case I was got stupendously lucky.  I had every file open in
an editor and was able to go through and systematically add a space and re-save
all of them.  From then on, everything I have written that looks like text that
I suspect I may want to keep is very quickly committed into a version control
system and distributed to at least two computers.&lt;/p&gt;</content><category term="Software Development"></category><category term="software"></category><category term="git"></category></entry></feed>