<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Enrico Campidoglio</title>
    <description>The blog of Enrico Campidoglio</description>
    <link>https://megakemp.com</link>
    <atom:link href="https://megakemp.com/feed.xml" rel="self" type="application/rss+xml" />
    
      <item>
        <title>Git Tips and Tricks</title>
        <description>&lt;p&gt;&lt;em&gt;Git is more than just a tool—it’s a Swiss Army knife packed with hidden gems! In my new &lt;a href=&quot;https://www.pluralsight.com/courses/git-tips-tricks&quot;&gt;Git Tips and Tricks&lt;/a&gt; course at &lt;a href=&quot;https://www.pluralsight.com/authors/enrico-campidoglio&quot;&gt;Pluralsight&lt;/a&gt;, I’ll show you how to unlock Git’s full potential.&lt;/em&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;In 2016, I released &lt;a href=&quot;https://www.pluralsight.com/authors/enrico-campidoglio&quot;&gt;my first Pluralsight course&lt;/a&gt; on Git. Since then, Git has evolved—and so have I. That’s why I’m thrilled to introduce my brand-new course &lt;a href=&quot;https://www.pluralsight.com/courses/git-tips-tricks&quot;&gt;Git Tips and Tricks&lt;/a&gt;, showcasing the latest features and techniques of modern Git that can supercharge your workflow.&lt;/p&gt;

&lt;p&gt;Whether you’re navigating &lt;a href=&quot;/2014/08/14/the-importance-of-a-good-looking-history/&quot;&gt;complex histories&lt;/a&gt; or &lt;a href=&quot;/2016/08/25/git-undo/&quot;&gt;correcting mistakes&lt;/a&gt;, this course has everything you need to level up your Git game. I’m really proud of how it turned out, and if Git is part of your daily life, I think you’re going to love it!&lt;/p&gt;

&lt;iframe width=&quot;640&quot; height=&quot;360&quot; src=&quot;https://www.youtube.com/embed/kyPvIorNU70?si=-62Q9_JC1Tyt4ByH&amp;amp;controls=0&quot; title=&quot;Git Tips and Tricks&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share&quot; referrerpolicy=&quot;strict-origin-when-cross-origin&quot; allowfullscreen=&quot;&quot;&gt;&lt;/iframe&gt;
</description>
        <pubDate>Tue, 08 Oct 2024 00:00:00 +0000</pubDate>
        <link>https://megakemp.com/2024/10/08/git-tips-tricks-pluralsight/</link>
        <guid isPermaLink="true">https://megakemp.com/2024/10/08/git-tips-tricks-pluralsight/</guid>
      </item>
    
      <item>
        <title>The Case for Pull Rebase</title>
        <description>&lt;p&gt;&lt;em&gt;The standard &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull&lt;/code&gt; command doesn’t play well with the Trunk-based development workflow. Fortunately, there’s a somewhat obscure way to make things right.&lt;/em&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;I’m going to make a bold generalization here and say that most development teams would rather work on a single &lt;em&gt;shared&lt;/em&gt; branch.&lt;/p&gt;

&lt;p&gt;I’m putting the emphasis on &lt;em&gt;shared&lt;/em&gt; because, while there may well be other kinds of branches being worked on at any given time (feature branches and Pull Request branches come to mind) there’s still only one &lt;em&gt;main branch&lt;/em&gt; everyone commits to. The other branches are often focused on one specific task, so, naturally, they exist for a limited period of time.&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;When I say &lt;em&gt;single shared&lt;/em&gt; branch, I also mean a &lt;a href=&quot;https://git-scm.com/book/it/v2/Git-Branching-Branching-Workflows#_long_running_branches&quot;&gt;long-running branch&lt;/a&gt;, one that spans over the entire lifetime of the project.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Trunk-Based Development&quot; src=&quot;https://megakemp.com/assets/the-case-for-pull-rebase/trunk.png&quot; class=&quot;screenshot-noshadow-caption&quot; /&gt;
&lt;span class=&quot;caption&quot;&gt;Everyone commits their work on a single shared branch, often called &lt;code&gt;Trunk&lt;/code&gt;.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This style of collaboration is called &lt;a href=&quot;https://paulhammant.com/2013/04/05/what-is-trunk-based-development/&quot;&gt;Trunk-Based Development&lt;/a&gt; or &lt;a href=&quot;https://gitversion.readthedocs.io/en/latest/reference/mainline-development/&quot;&gt;Mainline development&lt;/a&gt; and is, in my experience, the most common workflow you see around. That’s no coincidence: it’s also the oldest style of development collaboration known to mankind (dating all the way back to &lt;a href=&quot;https://en.m.wikipedia.org/wiki/Source_Code_Control_System&quot;&gt;the dawn of version control systems&lt;/a&gt;) and one most programmers feel comfortable with. After all, there’s ever only &lt;em&gt;one version&lt;/em&gt; of the code to worry about.&lt;/p&gt;

&lt;p&gt;As much as I love Git’s &lt;a href=&quot;https://megakemp.com/2017/04/19/what-is-in-a-git-branch/&quot;&gt;beautiful branching model&lt;/a&gt;, there’s no denying that sticking with the Mainline development workflow for as long as possible is often the smart thing to do in a project. In fact, that’s what the vast majority of open source projects do.&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Having a single long-running shared branch isn’t the problem here; the default behaviour of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull&lt;/code&gt; command is. Here’s why.&lt;/p&gt;

&lt;h2 id=&quot;anatomy-of-a-git-pull&quot;&gt;Anatomy of a Git Pull&lt;/h2&gt;

&lt;p&gt;If you aren’t familiar with Git’s inner workings, it might come as a surprise to know that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull&lt;/code&gt; isn’t actually a core command &lt;em&gt;per se&lt;/em&gt;,&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; but rather a combination of two other commands: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git fetch&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git merge&lt;/code&gt;; the former downloads any missing commits from a remote repository, while the latter &lt;em&gt;merges&lt;/em&gt; them into your current branch.&lt;sup id=&quot;fnref:4&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:4&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;Imagine you have a repository whose history looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Initial repo&quot; src=&quot;https://megakemp.com/assets/the-case-for-pull-rebase/repo.png&quot; class=&quot;screenshot-noshadow-caption&quot; /&gt;
&lt;span class=&quot;caption&quot;&gt;A simple repo.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Now, let’s say that you make a new commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C&lt;/code&gt; on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt;. Meanwhile, someone else on your team commits &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D&lt;/code&gt; on their own version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt;; now, here’s the catch: they manage to push their commit to the project’s central shared repository &lt;em&gt;before&lt;/em&gt; you.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Repo with remote&quot; src=&quot;https://megakemp.com/assets/the-case-for-pull-rebase/repo-with-remote.png&quot; class=&quot;screenshot-noshadow-caption&quot; /&gt;
&lt;span class=&quot;caption&quot;&gt;You commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C&lt;/code&gt;, someone else pushes &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D&lt;/code&gt;.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Unaware of that, you try to push your brand new commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C&lt;/code&gt; but are bluntly denied — Git lets you know that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;B&lt;/code&gt; no longer is the latest commit in the remote &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; branch:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;! [rejected] master -&amp;gt; master (non-fast-forward)
error: failed to push some refs to &apos;&amp;lt;remote-url&amp;gt;&apos;
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: &apos;git pull ...&apos;) before pushing again.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You shrug and run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull&lt;/code&gt; to get the latest commits. Now, keep in mind that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull&lt;/code&gt; is actually &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git fetch&lt;/code&gt; followed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git merge&lt;/code&gt;, so here’s what you end up with:&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Regular pull&quot; src=&quot;https://megakemp.com/assets/the-case-for-pull-rebase/pull-merge.png&quot; class=&quot;screenshot-noshadow-caption&quot; /&gt;
&lt;span class=&quot;caption&quot;&gt;The result of a regular pull.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Git fetched the new commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D&lt;/code&gt; from the remote repository, updated your local reference to the remote &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; branch &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;origin/master&lt;/code&gt;&lt;sup id=&quot;fnref:5&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:5&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt; and &lt;em&gt;merged&lt;/em&gt; that into your local &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt;, thus creating the merge commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;You’re now finally ready to push your beloved commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C&lt;/code&gt;, along with commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;merge-clutter&quot;&gt;Merge Clutter&lt;/h2&gt;

&lt;p&gt;At this point, you might think &lt;em&gt;so what, this is just business as usual&lt;/em&gt;, and you’d be right — after all, this is what happens when you invoke the standard &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pull&lt;/code&gt; command without any fancy options.&lt;/p&gt;

&lt;p&gt;However, consider the effect this has on your repo over time:&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Merge clutter&quot; src=&quot;https://megakemp.com/assets/the-case-for-pull-rebase/merge-clutter.png&quot; class=&quot;screenshot-noshadow-caption&quot; /&gt;
&lt;span class=&quot;caption&quot;&gt;Cluttered history.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This is how history looks like in a project who uses Git together with the Trunk-based development workflow (which, as we established, is pretty common). You see all those merge commits cluttering the mainline? The only reason they exist is because someone on the team happened to push their commits before someone else.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;In other words, when everyone commits to a single shared branch, the standard &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull&lt;/code&gt; command is going to clutter your history with a bunch of merge commits, simply due to the asynchronous nature of collaboration.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A merge commit should represent a &lt;em&gt;significative event&lt;/em&gt;, namely the point in time in which two different lines of history came together: a topic branch merged into a long-running branch (like a pull request), or a long-running branch merged into another (like a release) just to give you an example. The merge commits created by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull&lt;/code&gt;, on the other hand, don’t represent anything — they are an artificial side-effect.&lt;/p&gt;

&lt;h2 id=&quot;pull-rebase&quot;&gt;Pull Rebase&lt;/h2&gt;

&lt;p&gt;Fortunately, it doesn’t have to be that way. Here’s a different approach.&lt;/p&gt;

&lt;p&gt;We said that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull&lt;/code&gt; is actually two separate operations: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git fetch&lt;/code&gt; followed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git merge&lt;/code&gt;. Well, it turns out that if we pass the &lt;a href=&quot;https://git-scm.com/docs/git-pull#Documentation/git-pull.txt--r&quot;&gt;-r (–rebase)&lt;/a&gt; option to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull&lt;/code&gt;, we can replace that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git merge&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rebase&lt;/code&gt;. I know, a fine example of Git’s syntax at its best, right?&lt;/p&gt;

&lt;p&gt;Let’s go back to our previous example right before we did &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Initial repo&quot; src=&quot;https://megakemp.com/assets/the-case-for-pull-rebase/repo-with-remote.png&quot; class=&quot;screenshot-noshadow-caption&quot; /&gt;
&lt;span class=&quot;caption&quot;&gt;Back to square one.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;This time, we do &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull -r&lt;/code&gt; instead and look at what happens:&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Pull rebase&quot; src=&quot;https://megakemp.com/assets/the-case-for-pull-rebase/pull-rebase.png&quot; class=&quot;screenshot-noshadow-caption&quot; /&gt;
&lt;span class=&quot;caption&quot;&gt;The result of a pull rebase.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Git still fetched commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D&lt;/code&gt; but instead of merging &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;origin/master&lt;/code&gt; into our local &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt;, it &lt;em&gt;rebased&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C&lt;/code&gt; on top of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;origin/master&lt;/code&gt;, thus giving us a linear history.&lt;/p&gt;

&lt;p&gt;Now, if everyone on the team was doing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull --rebase&lt;/code&gt; by default, we wouldn’t have any of those artificial merge commits. That’s a win in my book, but we are not done yet.&lt;/p&gt;

&lt;h2 id=&quot;keeping-the-true-merges&quot;&gt;Keeping The True Merges&lt;/h2&gt;

&lt;p&gt;There is one more scenario we need to consider: what if you have a local merge commit that you &lt;em&gt;do&lt;/em&gt; want to push to the remote — is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull -r&lt;/code&gt; going to keep it?&lt;/p&gt;

&lt;p&gt;Unfortunately, the answer is &lt;strong&gt;no&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Let’s start once again with our previous example, only this time we have a legitimate merge commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;N&lt;/code&gt; that we want to share with the world:&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Repo with remote&quot; src=&quot;https://megakemp.com/assets/the-case-for-pull-rebase/repo-with-local-merge.png&quot; class=&quot;screenshot-noshadow-caption&quot; /&gt;
&lt;span class=&quot;caption&quot;&gt;A locally merged pull request branch containing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;PR&lt;/code&gt; commit.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Just for the sake of the argument, let’s see what would happen if we were to run the plain &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull&lt;/code&gt; first:&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Double merge&quot; src=&quot;https://megakemp.com/assets/the-case-for-pull-rebase/double-merge.png&quot; class=&quot;screenshot-noshadow-caption&quot; /&gt;
&lt;span class=&quot;caption&quot;&gt;One merge too many.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Double-merge! 😱 Fortunately, we know better now, so let’s run &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull -r&lt;/code&gt; instead:&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Lost local merge&quot; src=&quot;https://megakemp.com/assets/the-case-for-pull-rebase/lost-local-merge.png&quot; class=&quot;screenshot-noshadow-caption&quot; /&gt;
&lt;span class=&quot;caption&quot;&gt;Our merge commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;N&lt;/code&gt; is gone after a pull rebase.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;Wait — where did &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;N&lt;/code&gt; go? The answer is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rebase&lt;/code&gt; &lt;em&gt;removed it&lt;/em&gt; because, well, that’s what &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rebase&lt;/code&gt; does by default. Luckily for us, there is an option to keep the merge commits during a rebase: the &lt;a href=&quot;https://git-scm.com/docs/git-rebase#Documentation/git-rebase.txt--p&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--preserve-merges&lt;/code&gt;&lt;/a&gt; parameter.&lt;sup id=&quot;fnref:6&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:6&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;In the context of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull&lt;/code&gt;, this translates to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull --rebase=preserve&lt;/code&gt;. So, let’s run that instead:&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Rebased local merge&quot; src=&quot;https://megakemp.com/assets/the-case-for-pull-rebase/rebased-local-merge.png&quot; class=&quot;screenshot-noshadow-caption&quot; /&gt;
&lt;span class=&quot;caption&quot;&gt;Rebased merge.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;That’s more like it: our merge commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;N&lt;/code&gt; was &lt;em&gt;rebased&lt;/em&gt; on top of the remote &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;origin/master&lt;/code&gt; branch.&lt;sup id=&quot;fnref:7&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:7&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;7&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;h2 id=&quot;the-new-default&quot;&gt;The New Default&lt;/h2&gt;

&lt;p&gt;You’d be forgiven for not remembering to invoke &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pull&lt;/code&gt; with the right combination of arguments at any given time, so let’s make it our new default, shall we? The way you tell Git to always do a &lt;em&gt;pull rebase&lt;/em&gt; instead of a &lt;em&gt;pull merge&lt;/em&gt; (while still keeping any local merge commits) is by setting the &lt;a href=&quot;https://git-scm.com/docs/git-config#Documentation/git-config.txt-pullrebase&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;pull.rebase&lt;/code&gt;&lt;/a&gt; configuration option:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git config --global pull.rebase preserve
git config --global pull.rebase merges   # if you&apos;re on Git 2.18 or later
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Of course, you can omit the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--global&lt;/code&gt; option if, for some reason, you only want this to apply to your current repository.&lt;/p&gt;

&lt;h2 id=&quot;in-conclusion&quot;&gt;In Conclusion&lt;/h2&gt;

&lt;p&gt;The combination of using a &lt;a href=&quot;https://paulhammant.com/2013/04/05/what-is-trunk-based-development/&quot;&gt;Trunk-based development workflow&lt;/a&gt; with the regular &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull&lt;/code&gt; command leads to a history cluttered with merge commits that you don’t want. Fortunately, by simply replacing the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;merge&lt;/code&gt; part of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rebase&lt;/code&gt;, you can enjoy a straightforward single-branch workflow without sacrificing the cleanness of your history.&lt;/p&gt;

&lt;div class=&quot;note&quot;&gt;
&lt;p&gt;
&lt;i class=&quot;fa fa-play-circle-o fa-2x pull-left pull-left-three-lines&quot;&gt;&lt;/i&gt;
If you&apos;re interested in learning other techniques like the one described in this article, you should check out my &lt;a href=&quot;https://www.pluralsight.com/authors/enrico-campidoglio&quot;&gt;Pluralsight&lt;/a&gt; course &lt;a href=&quot;https://www.pluralsight.com/courses/git-tips-tricks&quot;&gt;Git Tips and Tricks&lt;/a&gt;.
&lt;/p&gt;
&lt;/div&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;In Git’s parlance, these are often called &lt;a href=&quot;https://git-scm.com/book/it/v2/Git-Branching-Branching-Workflows#r_topic_branch&quot;&gt;topic branches&lt;/a&gt;. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;With a twist: external (and sometimes also internal) contributors can’t commit directly to the main branch, but instead have to submit their code a dedicated Pull Request branch. This workflow has become known as the &lt;a href=&quot;https://guides.github.com/introduction/flow/&quot;&gt;GitHub Flow&lt;/a&gt;. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;In fact, like many other commands in Git, it used to be a &lt;a href=&quot;https://github.com/git/git/blob/master/builtin/pull.c#L4&quot;&gt;shell script&lt;/a&gt;. &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:4&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Where by &lt;em&gt;current&lt;/em&gt;, I mean the branch that reflects your working copy. In technical terms, that would be the branch &lt;em&gt;referenced&lt;/em&gt; by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD&lt;/code&gt;. &lt;a href=&quot;#fnref:4&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:5&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Git calls them &lt;a href=&quot;https://git-scm.com/book/en/v1/Git-Branching-Remote-Branches#Tracking-Branches&quot;&gt;&lt;em&gt;tracking branches&lt;/em&gt;&lt;/a&gt; but you can think of them as &lt;em&gt;bookmarks&lt;/em&gt; that keep track of where a branch is on a remote repository. &lt;a href=&quot;#fnref:5&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:6&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;There’s a interesting story behind the origin of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--preserve-merges&lt;/code&gt; option. If you have the time, I suggest you read it. It’s all told inside of &lt;a href=&quot;https://github.com/git/git/commit/8f6aed71d27f33096449d28c4711d3b68159632e&quot;&gt;a commit message&lt;/a&gt;. &lt;a href=&quot;#fnref:6&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:7&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;A short note: the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--preserve-merges&lt;/code&gt; option has recently been replaced by a more robust implementation in the form of the &lt;a href=&quot;https://git-scm.com/docs/git-rebase#Documentation/git-rebase.txt--r&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--rebase-merges&lt;/code&gt;&lt;/a&gt; option. If you’re using Git 2.18 (Q2 2018) or later, you should use that instead by saying &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull --rebase=merges&lt;/code&gt;. &lt;a href=&quot;#fnref:7&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Wed, 20 Mar 2019 00:00:00 +0000</pubDate>
        <link>https://megakemp.com/2019/03/20/the-case-for-pull-rebase/</link>
        <guid isPermaLink="true">https://megakemp.com/2019/03/20/the-case-for-pull-rebase/</guid>
      </item>
    
      <item>
        <title>There Is Cake at Pluralsight</title>
        <description>&lt;p&gt;&lt;em&gt;I’m excited to announce that my &lt;a href=&quot;https://www.pluralsight.com/courses/cake-applications-deploying-building&quot;&gt;new Pluralsight course&lt;/a&gt; is out — and yes, there will be Cake.&lt;/em&gt;&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;not-just-another-make&quot;&gt;Not Just Another Make&lt;/h2&gt;

&lt;p&gt;Kidding aside, I didn’t make a Pluralsight course about baking; it’s about a Make-inspired build tool that uses C# &lt;em&gt;called&lt;/em&gt; &lt;a href=&quot;https://cakebuild.net&quot;&gt;Cake&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://www.pluralsight.com/courses/cake-applications-deploying-building&quot;&gt;
    &lt;img alt=&quot;Cake at Pluralsight&quot; src=&quot;https://megakemp.com/assets/cake-at-pluralsight/cake-ps-banner.png&quot; class=&quot;screenshot-noshadow-fullwidth&quot; /&gt;
 &lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you’ve never heard of it, let me tell you a story.&lt;/p&gt;

&lt;p&gt;When I first came across the &lt;a href=&quot;https://github.com/cake-build/cake&quot;&gt;Cake project&lt;/a&gt; it was the fall of 2014, almost exactly three years ago. &lt;a href=&quot;https://twitter.com/firstdrafthell&quot;&gt;Patrik Svensson&lt;/a&gt; — a colleague of mine at &lt;a href=&quot;https://tretton37.com&quot;&gt;tretton37&lt;/a&gt; at the time — had been working on it for some time, and had reached a point where things were starting to shape up. So I took a quick look at the code and I remember being impressed by how well it was designed!&lt;/p&gt;

&lt;p&gt;As for the tool itself, however, I remained skeptical and here’s why. Back then, the software industry had just gone through a sort of &lt;em&gt;Make renaissance&lt;/em&gt; — a period of time during which we saw a large number of build tools, all inspired by the venerable &lt;a href=&quot;https://en.wikipedia.org/wiki/Make_(software)&quot;&gt;Make&lt;/a&gt;, appear on the open source scene.&lt;/p&gt;

&lt;p&gt;Each tool was characterized by the particular &lt;em&gt;programming language&lt;/em&gt; it would use for its &lt;a href=&quot;https://en.wikipedia.org/wiki/Domain-specific_language&quot;&gt;DSL&lt;/a&gt;; there was &lt;a href=&quot;https://github.com/ruby/rake&quot;&gt;Rake&lt;/a&gt; with Ruby, &lt;a href=&quot;https://github.com/psake/psake&quot;&gt;Psake&lt;/a&gt; with PowerShell, &lt;a href=&quot;https://fake.build&quot;&gt;Fake&lt;/a&gt; with F# and &lt;a href=&quot;https://gradle.org&quot;&gt;Gradle&lt;/a&gt; with Groovy, just to name a few. On top of that, you had all the JavaScript ones like &lt;a href=&quot;https://gruntjs.com&quot;&gt;Grunt&lt;/a&gt; and &lt;a href=&quot;https://gulpjs.com&quot;&gt;Gulp&lt;/a&gt;. All these tools were part of the &lt;em&gt;Make-renaissance&lt;/em&gt;. Frankly, I thought we had seen them all and yet there I was, looking at &lt;a href=&quot;https://cakebuild.net&quot;&gt;Cake&lt;/a&gt; — the one with the C# DSL. As much as I appreciated Cake’s high standard and thoughtful design, I had trouble justifying its &lt;em&gt;raison d’être&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Build Tools&quot; src=&quot;https://megakemp.com/assets/cake-at-pluralsight/build-tools.png&quot; class=&quot;screenshot-noshadow-caption&quot; /&gt;
&lt;span class=&quot;caption&quot;&gt;Rake, Psake, Fake or Gradle? You must choose, but choose wisely.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;To be fair, none of the tools that came from the &lt;em&gt;Make-renaissance&lt;/em&gt; was a particularly good fit for a .NET project.&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; But that had never stopped me from writing my build scripts. Before Cake, my tool of choice was Psake, for no reason other than that PowerShell is so well integrated with the Windows ecosystem.&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt; Believe me, when you’re automating any sort of deployment process, &lt;em&gt;integration&lt;/em&gt; is what you’re after.&lt;/p&gt;

&lt;p&gt;Psake was good in that sense, but it was never &lt;em&gt;great&lt;/em&gt;. You still had to manually make sure that every tool you invoked from your build script was present on the target machine (things like compilers, test runners and package managers). On top of that, you had the PowerShell syntax which — let’s face it — isn’t particularly fun to read and much less to write.&lt;/p&gt;

&lt;p&gt;One day, I decided it was time to check on Cake to see how it was doing. And let me tell you, it was doing &lt;em&gt;really&lt;/em&gt; well; the &lt;a href=&quot;https://github.com/orgs/cake-build/people&quot;&gt;core team&lt;/a&gt; had expanded and the project was thriving with frequent &lt;a href=&quot;https://github.com/cake-build/cake/releases&quot;&gt;releases&lt;/a&gt; and a growing &lt;a href=&quot;https://github.com/cake-build/cake/graphs/contributors&quot;&gt;community&lt;/a&gt;. Although I found the C#-based DSL to be absolutely &lt;em&gt;delightful&lt;/em&gt;, it wasn’t until I saw &lt;a href=&quot;https://www.nuget.org/profiles/cake-contrib&quot;&gt;this&lt;/a&gt; that I got really &lt;em&gt;excited&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Cake Addins on NuGet.org&quot; src=&quot;https://megakemp.com/assets/cake-at-pluralsight/cake-addins.png&quot; class=&quot;screenshot-noshadow-caption&quot; /&gt;
&lt;span class=&quot;caption&quot;&gt;These are only few of the many &lt;a href=&quot;https://www.nuget.org/profiles/cake-contrib&quot; target=&quot;_blank&quot;&gt;Cake addins&lt;/a&gt; available on the NuGet Gallery.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;See that list? Those are only a fraction of the third-party tools and libraries that you can interact with &lt;em&gt;directly&lt;/em&gt; from a Cake script — as if they were part of the DSL itself!&lt;/p&gt;

&lt;h2 id=&quot;how-cake-works&quot;&gt;How Cake Works&lt;/h2&gt;

&lt;p&gt;Let me give you a quick example. If you wanted to run all the tests in your project as part of your build process, you could do that with Cake by saying:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nf&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Run-Tests&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Does&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;NUnit3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;src/**/bin/Release/*Tests.dll&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NUnit3&lt;/code&gt; is an &lt;a href=&quot;https://cakebuild.net/docs/fundamentals/aliases&quot;&gt;&lt;em&gt;alias&lt;/em&gt;&lt;/a&gt; — a C# method that’s part of the Cake DSL.&lt;sup id=&quot;fnref:4&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:4&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt; When you invoke it, Cake will automatically resolve the path to the &lt;em&gt;NUnit 3 console runner’s executable&lt;/em&gt; and convert your method call into this:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;nunit3-console.exe &lt;span class=&quot;s2&quot;&gt;&quot;./src/UnitTests/bin/Release/MyProject.UnitTests.dll&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;See how the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;src/**/bin/Release/*Tests.dll&quot;&lt;/code&gt; &lt;em&gt;glob pattern&lt;/em&gt; was expanded into an actual path to a DLL file? Yeah, Cake did that.&lt;/p&gt;

&lt;p&gt;But how do you make sure that the NUnit 3 Console Runner is actually present on the target machine? Easy — you tell Cake to download the &lt;a href=&quot;https://www.nuget.org/packages/NUnit.Console&quot;&gt;NUnit.Console&lt;/a&gt; package from the NuGet Gallery &lt;em&gt;before&lt;/em&gt; it runs the script by adding a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;#tool&lt;/code&gt; &lt;a href=&quot;https://cakebuild.net/docs/fundamentals/preprocessor-directives&quot;&gt;&lt;em&gt;preprocessor directive&lt;/em&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-csharp highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;err&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;tool&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;nuget&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:?&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;NUnit&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Console&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;3.7&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;0&lt;/span&gt;

&lt;span class=&quot;nf&quot;&gt;Task&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;Run-Tests&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;Does&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;=&amp;gt;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nf&quot;&gt;NUnit3&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;src/**/bin/Release/*Tests.dll&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s it. Cake will download any tools and libraries you like as &lt;em&gt;NuGet packages&lt;/em&gt;, unpack their contents and store them in a local directory that it manages itself. Oh — and it will also take care of &lt;a href=&quot;https://cakebuild.net/docs/tools/tool-resolution&quot;&gt;resolving the paths&lt;/a&gt; for you.&lt;/p&gt;

&lt;p&gt;You see why I’m all fired up about Cake?&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;The Cake Logo&quot; src=&quot;https://megakemp.com/assets/cake-at-pluralsight/cake-logo.png&quot; class=&quot;screenshot-noshadow-caption&quot; /&gt;
&lt;span class=&quot;caption&quot;&gt;The official Cake logo.&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;pluralsight&quot;&gt;Pluralsight&lt;/h2&gt;

&lt;p&gt;After having used Cake for about a year in all my .NET projects, it occurred to me that not enough people knew about it. So, I drafted a proposal for a Cake course and sent it to my editor at &lt;a href=&quot;https://www.pluralsight.com&quot;&gt;Pluralsight&lt;/a&gt;. A couple of emails went back and forth, and soon I was working on &lt;a href=&quot;https://www.pluralsight.com/courses/cake-applications-deploying-building&quot;&gt;&lt;em&gt;Building and Deploying Applications with Cake&lt;/em&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This time I was particularly excited, because that would become the &lt;em&gt;first&lt;/em&gt; Cake course to ever appear on Pluralsight. I felt no pressure whatsoever.&lt;sup id=&quot;fnref:5&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:5&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;The First Slide of Building and Deploying Applications with Cake&quot; src=&quot;https://megakemp.com/assets/cake-at-pluralsight/course-title.png&quot; class=&quot;screenshot-noshadow-caption&quot; /&gt;
&lt;span class=&quot;caption&quot;&gt;The very first slide in the course. I still wish the title would fit in one row.&lt;/span&gt;&lt;/p&gt;

&lt;h2 id=&quot;building-and-deploying-applications-with-cake&quot;&gt;Building and Deploying Applications with Cake&lt;/h2&gt;

&lt;p&gt;While Cake sports an elegant design fueled by some very smart ideas, there isn’t really that much theory to go through. So, I decided to make a &lt;em&gt;practical course&lt;/em&gt; that teaches you how to use Cake in a real-world .NET application.&lt;/p&gt;

&lt;p&gt;Also, since Cake is cross-platform, I thought it would be a good idea to demonstrate it both on Windows, using the .NET Framework, as well as on &lt;a href=&quot;https://www.microsoft.com/net/core/platform&quot;&gt;.NET Core&lt;/a&gt; running on macOS.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Overview of the Demo Application Used in the Course&quot; src=&quot;https://megakemp.com/assets/cake-at-pluralsight/demo-application.png&quot; class=&quot;screenshot-noshadow-caption&quot; /&gt;
&lt;span class=&quot;caption&quot;&gt;Overview of the demo application used in the course.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;The course is about creating a complete &lt;em&gt;build and deployment pipeline&lt;/em&gt; for that application — from source code to software running in the cloud — all using Cake. Along the way, you’ll get to know Cake’s features and how to use them to overcome the challenges of automating a build and deploy process, both on .NET and on .NET Core.&lt;/p&gt;

&lt;p&gt;Here are some of the topics covered in the course:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;Compiling&lt;/strong&gt; an ASP.NET web application on Windows and an ASP.NET Core one on macOS.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Testing&lt;/strong&gt; with xUnit.net while measuring code coverage.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Versioning&lt;/strong&gt; by generating a semantic version number.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Packaging&lt;/strong&gt; as a NuGet and Web Deploy package on Windows, and as a Zip archive on macOS.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Deploying&lt;/strong&gt; to an Azure Web App using Octopus Deploy, Web Deploy and the Kudu REST API.&lt;/li&gt;
  &lt;li&gt;Doing &lt;strong&gt;Continuous Integration&lt;/strong&gt; with TeamCity, Visual Studio Team Services and Travis CI.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;My goal was to come up with as many scenarios as possible, throw them at Cake and see if it made my life easier or more difficult. The result? Not only was I able to complete many common tasks (like running the tests or packaging the application) in a matter of minutes, but the final build script came out remarkably short and — most importantly — &lt;em&gt;readable&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://cakebuild.net&quot;&gt;Cake&lt;/a&gt; is a great build automation tool — especially if you’re a C# developer — and I really think it shows in the course. I’m very happy with how this course turned out, and I hope you’ll enjoy &lt;a href=&quot;https://www.pluralsight.com/courses/cake-applications-deploying-building&quot;&gt;watching it&lt;/a&gt; as much as I did baking it. 🙂&lt;/p&gt;

&lt;div class=&quot;note&quot;&gt;
    &lt;div style=&quot;display: inline-block; margin: 1em 0.3em 0 1em&quot;&gt;&lt;i class=&quot;fa fa-play-circle-o fa-2x&quot;&gt;&lt;/i&gt;&lt;/div&gt;
    &lt;div style=&quot;display: inline-block; vertical-align: middle; margin: -0.9em 0 0 0&quot;&gt;
        &lt;a href=&quot;http://bit.ly/ps-cake-build-deploy&quot;&gt;Building and Deploying Applications with Cake&lt;/a&gt;
    &lt;/div&gt;
&lt;/div&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Just not the &lt;em&gt;kind&lt;/em&gt; of cake you’re thinking about. OK, that was a bad &lt;a href=&quot;https://theportalwiki.com/wiki/Cake&quot;&gt;Portal joke&lt;/a&gt;. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;With the possible exception of &lt;a href=&quot;https://fake.build&quot;&gt;Fake&lt;/a&gt;, but — then again — how many .NET developers do you know who feel comfortable writing a build script in F#? My guess is not so many. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;IIS, Azure, Active Directory and SQL Server — to give you an idea — can all be controlled &lt;em&gt;entirely&lt;/em&gt; from PowerShell. &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:4&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Cake comes with many &lt;a href=&quot;https://cakebuild.net/dsl&quot;&gt;built-in&lt;/a&gt; aliases, but you can add even more with external &lt;a href=&quot;https://cakebuild.net/addins&quot;&gt;addins&lt;/a&gt;. &lt;a href=&quot;#fnref:4&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:5&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;OK, not really. 😬 &lt;a href=&quot;#fnref:5&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Fri, 20 Oct 2017 00:00:00 +0000</pubDate>
        <link>https://megakemp.com/2017/10/20/cake-at-pluralsight/</link>
        <guid isPermaLink="true">https://megakemp.com/2017/10/20/cake-at-pluralsight/</guid>
      </item>
    
      <item>
        <title>The Invisible Commits (Part 1)</title>
        <description>&lt;p&gt;&lt;em&gt;Your repository has more commits than what meets the eye. They hide somewhere in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.git&lt;/code&gt; directory—where you can’t see them—but they’re there. I call them the invisible commits. Knowing where to find them can mean the difference between recovering your work and losing it to the sands of time.&lt;/em&gt;&lt;/p&gt;

&lt;hr /&gt;

&lt;p&gt;One of the things you’ll often hear enthusiasts like me say is &lt;em&gt;“with Git, you can’t lose your work”&lt;/em&gt;. If you wanted to challenge me on that statement, you’d be right—after all, there are no absolutes in computer science.&lt;/p&gt;

&lt;p&gt;That’s why I always follow up with an asterisk:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;…as long as you’ve committed it.&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If that sounds vague to you, don’t worry—explaining what I mean by that is the very topic of this article.&lt;/p&gt;

&lt;h3 id=&quot;resilience-by-design&quot;&gt;Resilience by Design&lt;/h3&gt;

&lt;p&gt;The fact that Git is &lt;em&gt;resilient&lt;/em&gt; is no coincidence—it was a deliberate design choice made by Linus Torvalds. Here’s what he wrote in response to a &lt;a href=&quot;https://marc.info/?l=git&amp;amp;m=118143549107708&quot;&gt;question about data corruption back in 2007&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;That was one of the design goals for git (i.e. the “you know you can trust the data” thing relies on very strong protection at all levels, even in the presence of disk/memory/cpu corruption).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;em&gt;“At all levels”&lt;/em&gt;—he said—implying that Git has built-in safeguards not only against hardware failure, but also &lt;em&gt;human error&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;That’s why experienced Git users will often tell you to calm down in the face of what seems like a disaster. They’re right—in the vast majority of cases you can, in fact, recover commits that you thought were lost. The key—as with many things in Git—is to know where to find them.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Keep Calm and Use Git&quot; class=&quot;screenshot-noshadow-caption&quot; src=&quot;https://megakemp.com/assets/the-invisible-commits-part-one/keep-calm-use-git.png&quot; /&gt;
&lt;span class=&quot;caption&quot;&gt;Solid advice in tough situations.&lt;/span&gt;&lt;/p&gt;

&lt;p&gt;In this article series, I’ll talk about what I like to call the &lt;em&gt;invisible commits&lt;/em&gt;; commits that you don’t see, but are there as an insurance policy, just in case you ever need to have them back.&lt;/p&gt;

&lt;p&gt;Let’s start with the easy one: the &lt;a href=&quot;https://git-scm.com/docs/git-reflog&quot;&gt;reflog&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id=&quot;the-reflog&quot;&gt;The Reflog&lt;/h3&gt;

&lt;p&gt;I’ve talked about the mighty &lt;em&gt;reflog&lt;/em&gt; in &lt;a href=&quot;https://megakemp.com/2016/08/25/git-undo/&quot;&gt;more than one occasion&lt;/a&gt;. Simply put, the reflog is a journal which records the values of the branch and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD&lt;/code&gt; &lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Internals-Git-References&quot;&gt;references&lt;/a&gt; over time. This journal is &lt;em&gt;local&lt;/em&gt; to a repository, meaning it can’t be shared by pushing it to remote repositories.&lt;/p&gt;

&lt;p&gt;Every time you create a commit, your current &lt;em&gt;branch reference&lt;/em&gt; is modified to point to that commit; by the same token, every time you switch to a different branch (for example by using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git checkout&lt;/code&gt;) the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD&lt;/code&gt; reference is modified to point to that branch.&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;When that happens, the &lt;em&gt;previous&lt;/em&gt; and the &lt;em&gt;current&lt;/em&gt; value of the reference gets recorded in the reflog belonging to that reference. Go ahead, take a look at a branch’s reflog by saying:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git reflog &amp;lt;branchname&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Or for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git reflog
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;What you get back is something like this:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;20da2b6 HEAD@&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;0&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;: commit &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;amend&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;: WIP: reinventing the wheel
176ec0a HEAD@&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;1&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;: rebase finished: returning to refs/heads/develop
176ec0a HEAD@&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;2&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;: rebase: WIP: reinventing the wheel
2b60b60 HEAD@&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;3&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;: rebase: checkout master
2b60b60 HEAD@&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;4&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;: cherry-pick: Reticulates the splines
e7db79d HEAD@&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;5&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;: checkout: moving from develop to master
93ced10 HEAD@&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;6&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;: commit: Does some refactoring
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s a list where each entry contains a few pieces of information:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The &lt;em&gt;SHA-1 hash&lt;/em&gt; of the commit referenced by the entry.&lt;/li&gt;
  &lt;li&gt;The &lt;em&gt;name&lt;/em&gt; of the entry itself in the form &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reference@{position}&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;The name of the &lt;em&gt;operation&lt;/em&gt; that caused the reference to change, for example a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;commit&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;checkout&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rebase&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;A &lt;em&gt;description&lt;/em&gt; associated to the entry; this could be the commit message if it was &lt;em&gt;commit&lt;/em&gt; operation or the source and destination branch in case of a &lt;em&gt;checkout&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The reason why this is important in the context of data recovery, is that you can &lt;em&gt;reference&lt;/em&gt; reflog entries as you would regular commits.&lt;/p&gt;

&lt;h3 id=&quot;recovering-commits-from-the-reflog&quot;&gt;Recovering Commits from the Reflog&lt;/h3&gt;

&lt;p&gt;That’s enough theory. Let’s talk about this works in practice. Imagine you have history that looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Initial history&quot; class=&quot;screenshot-noshadow&quot; src=&quot;https://megakemp.com/assets/the-invisible-commits-part-one/commit.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;There’s a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; branch with four commits. Now, assuming you haven’t modified history in any way, the reflog that belongs to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; branch (shown in &lt;span style=&quot;color:#0388A6&quot;&gt;blue&lt;/span&gt;) is also going to have four entries—one for each commit—with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@{0}&lt;/code&gt; being the &lt;em&gt;most recent&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Now, let’s imagine that, in the heat of the moment, you accidentally removed the last two commits in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; branch with:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git reset &lt;span class=&quot;nt&quot;&gt;--hard&lt;/span&gt; master~2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt=&quot;Accidental Reset&quot; class=&quot;screenshot-noshadow&quot; src=&quot;https://megakemp.com/assets/the-invisible-commits-part-one/reset.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Now &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;E&lt;/code&gt; are no longer &lt;em&gt;reachable&lt;/em&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; so running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log&lt;/code&gt; won’t show them. They’re by all accounts &lt;em&gt;gone&lt;/em&gt;, but what if you want to get them back? Where do you find them?&lt;/p&gt;

&lt;p&gt;Well, the &lt;em&gt;reflog&lt;/em&gt; is still pointing to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;E&lt;/code&gt;, you just can’t see it. What used to be entry &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@{0}&lt;/code&gt; became &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@{1}&lt;/code&gt; and a &lt;em&gt;new&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@{0}&lt;/code&gt; entry was created to point to the same commit as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt;, that is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;B&lt;/code&gt;. Of course, all other entries also shifted by one.&lt;/p&gt;

&lt;p&gt;So, if you want to restore the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; branch to the same commit it referenced &lt;em&gt;before you modified it&lt;/em&gt;, you can simply reset it to the &lt;em&gt;previous reflog entry&lt;/em&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@{1}&lt;/code&gt; which still points to commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git reset &lt;span class=&quot;nt&quot;&gt;--hard&lt;/span&gt; @&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;1&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;&lt;img alt=&quot;Restore&quot; class=&quot;screenshot-noshadow&quot; src=&quot;https://megakemp.com/assets/the-invisible-commits-part-one/restore.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The important thing to remember is this:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@{0}&lt;/code&gt; entry in the reflog always points to the same commit as the branch itself. Previous entries follow with increments by one like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@{1}&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@{2}&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@{3}&lt;/code&gt; and so on; in other words, the &lt;em&gt;higher&lt;/em&gt; the index, the &lt;em&gt;older&lt;/em&gt; the entry.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Of course, you can also use the reflog to recover commits that happened way earlier.&lt;/p&gt;

&lt;p&gt;For example, let’s say that you want to restore an older commit &lt;em&gt;after&lt;/em&gt; you have added a whole bunch of new commits on top of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt;. Of course, you can’t use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git reset&lt;/code&gt; because that would remove the new commits.&lt;/p&gt;

&lt;p&gt;What you do in that case is &lt;em&gt;apply&lt;/em&gt; the older commit on top of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git cherry-pick&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git cherry-pick @&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;90&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And voilà—the commit referenced by the reflog entry with index &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;90&lt;/code&gt; is back in your &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; branch.&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;h3 id=&quot;searching-the-reflog&quot;&gt;Searching the Reflog&lt;/h3&gt;

&lt;p&gt;The last example implies that you can find the commit you’re looking for by simply scrolling through the reflog. Of course, that’s not always the case.&lt;/p&gt;

&lt;p&gt;So, what do you do when you want to recover an &lt;em&gt;invisible commit&lt;/em&gt; from the reflog, but you don’t know where it is?&lt;/p&gt;

&lt;p&gt;The answer is, you search for it using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log&lt;/code&gt;. Here’s an example:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git log &lt;span class=&quot;nt&quot;&gt;--grep&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;Some commit message&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--walk-reflogs&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--oneline&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Let’s unpack this command:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--grep&lt;/code&gt; allows you to find commits whose &lt;em&gt;message&lt;/em&gt; matches a pattern (which can be a regular expression).&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--walk-reflogs&lt;/code&gt; tells the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;log&lt;/code&gt; command to search through the commits referenced by the &lt;em&gt;reflog&lt;/em&gt; instead of the ones referenced by a particular branch.&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--oneline&lt;/code&gt; prints out the commit SHA-1, the reflog reference and the commit message in &lt;em&gt;a single line&lt;/em&gt; for a more compact output (if you like it, of course).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s the kind of search I usually do, but it’s certainly not the only one.&lt;/p&gt;

&lt;p&gt;For example, you can also look for commits that happened within a specific &lt;em&gt;time range&lt;/em&gt;:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git log &lt;span class=&quot;nt&quot;&gt;--walk-reflogs&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--since&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2 days ago&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--before&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;yesterday&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--oneline&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Here, we’re specifying the times with the natural formats supported by Linus Torvalds’ amazing &lt;a href=&quot;https://github.com/git/git/blob/660fb3dfa8f3e42b287ee7e27a36ecd2420b89c3/date.c&quot;&gt;approxidate&lt;/a&gt; implementation.&lt;sup id=&quot;fnref:4&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:4&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;While we’re talking about dates, note that you can also use &lt;em&gt;times&lt;/em&gt; instead of &lt;em&gt;indexes&lt;/em&gt; when referencing a specific reflog entry. For instance, you can limit your search to just the entries from a particular point in time:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git log &lt;span class=&quot;nt&quot;&gt;--walk-reflogs&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--oneline&lt;/span&gt; master@&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;2 days ago&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will print out the &lt;em&gt;timestamps&lt;/em&gt; when the reflog entry were created instead of their index, which sometimes is more helpful:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;20da2b6 master@&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;Mon Oct 16 11:20:58 2017 +0200&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;: commit &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;amend&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;: WIP: reinventing the wheel
176ec0a master@&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;Mon Oct 16 10:37:51 2017 +0200&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;: rebase finished: returning to refs/heads/develop
176ec0a master@&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;Mon Oct 16 10:37:14 2017 +0200&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;: rebase: WIP: reinventing the wheel
2b60b60 master@&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;Mon Oct 16 10:37:8 2017 +0200&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;: rebase: checkout master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;things-you-wont-find-in-the-reflog&quot;&gt;Things You Won’t Find in the Reflog&lt;/h3&gt;

&lt;p&gt;By now, it should be clear that the reflog should your first destination when you’re looking for commits to restore. However, be aware that things won’t stay there forever.&lt;/p&gt;

&lt;p&gt;Reflog entries have, in fact, &lt;em&gt;expiration dates&lt;/em&gt;. By default, they’re set to expire after &lt;em&gt;90 days&lt;/em&gt;, but you can change that to any number of days by setting the &lt;a href=&quot;https://git-scm.com/docs/git-reflog#git-reflog---expirelttimegt&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gc.reflogExpire&lt;/code&gt;&lt;/a&gt; option:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git config &lt;span class=&quot;nt&quot;&gt;--global&lt;/span&gt; gc.reflogExpire 120
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;After that, the entries are &lt;em&gt;deleted from the reflog&lt;/em&gt;. 😱&lt;/p&gt;

&lt;p&gt;Note that this setting is only valid for entries whose commits are &lt;em&gt;still reachable&lt;/em&gt; from a branch; this means that entries whose commits are &lt;em&gt;unreachable&lt;/em&gt; from a branch or a tag have a different expire date; the default value for that is &lt;em&gt;30 days&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;This makes sense if you think about it; unreachable commits are more likely to be &lt;em&gt;junk&lt;/em&gt; left behind by various history modifications, and can therefore be cleaned out more often.&lt;/p&gt;

&lt;p&gt;However, if you do want to keep them around longer, just in case, you can do so by setting the &lt;a href=&quot;https://git-scm.com/docs/git-reflog#git-reflog---expire-unreachablelttimegt&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gc.reflogExpireUnreachable&lt;/code&gt;&lt;/a&gt; option:&lt;/p&gt;

&lt;div class=&quot;language-sh highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git config &lt;span class=&quot;nt&quot;&gt;--global&lt;/span&gt; gc.reflogExpireUnreachable 60
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Just because Git removes an entry from the reflog, it doesn’t mean that the commit itself is also gone. In fact, the commit &lt;em&gt;will still be around&lt;/em&gt; until the next &lt;a href=&quot;https://git-scm.com/docs/git-gc&quot;&gt;garbage collection&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;So, when the reflog is no longer an option, we have to find another way to retrieve our &lt;em&gt;invisible commits&lt;/em&gt;. We’ll see how in the next article.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Followed by a second asterisk that says “&lt;em&gt;and less than a certain amount of time has passed&lt;/em&gt;”. More on this &lt;a href=&quot;https://megakemp.com/2017/10/19/the-invisible-commits-part-one/#things-you-wont-find-in-the-reflog/&quot;&gt;later&lt;/a&gt;. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;There are also other situations that would cause the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD&lt;/code&gt; reference to change, like, for example, a &lt;em&gt;rebase&lt;/em&gt;. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Of course, you can also reference commits from other branches’ reflogs; if the commit you’re looking for was in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;develop&lt;/code&gt;, for example, you could just say &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git cherry-pick develop@{90}&lt;/code&gt; to bring it into your current branch. &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:4&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Which, I discovered, has since been extracted into &lt;a href=&quot;https://github.com/thatguystone/approxidate&quot;&gt;its own library&lt;/a&gt;. &lt;a href=&quot;#fnref:4&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Thu, 19 Oct 2017 00:00:00 +0000</pubDate>
        <link>https://megakemp.com/2017/10/19/the-invisible-commits-part-one/</link>
        <guid isPermaLink="true">https://megakemp.com/2017/10/19/the-invisible-commits-part-one/</guid>
      </item>
    
      <item>
        <title>The Next Step</title>
        <description>&lt;p&gt;Today, I start my new job as a &lt;em&gt;freelance teacher and mentor&lt;/em&gt;. It took me a while to get there, but I’m excited to finally start this new chapter in my career.&lt;/p&gt;

&lt;p&gt;If you’d like to hear the background story, read on. If, instead, you’re more interested in knowing what’s next, here’s what &lt;a href=&quot;#whats-next&quot;&gt;I have in store&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;background-story&quot;&gt;Background Story&lt;/h2&gt;

&lt;p&gt;Sharing information has always been a passion of mine. In high-school, I remember taking every opportunity to tell my friends the latest facts about one of my favorite subjects.&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; Normally, I would get about five minutes before someone would change the subject, and that was OK. But every once in a while, I managed to capture someone’s attention. I could see it in their eyes that they wanted to know more. I remember thinking how that was a precious moment — a rare opportunity to share with someone something I knew very well — and I had to treat that chance with respect or there would be no others.&lt;/p&gt;

&lt;h3 id=&quot;teaching&quot;&gt;Teaching&lt;/h3&gt;

&lt;p&gt;Fast-forward ten years. I’m in a classroom in front of twenty students. I had just accepted an assignment in a continuing education school in Malmö and those twenty people were waiting for me to teach them Linux. It was frightening but I enjoyed every bit of that experience! By the end of the semester, I knew what I wanted to do.&lt;/p&gt;

&lt;p&gt;But teaching wasn’t my main occupation. I was a consultant and my time was spent developing software for my clients. Don’t get me wrong — I &lt;em&gt;loved my job&lt;/em&gt; and still do. Occasionally, I would be lucky enough to teach an internal course at a client for a few days, which was grand. But those assignments were few and far between. Nevertheless, I loved teaching and the feedback I got motivated me to hold on to it.&lt;/p&gt;

&lt;h3 id=&quot;speaking&quot;&gt;Speaking&lt;/h3&gt;

&lt;p&gt;In 2011, I started doing talks at conferences and user group meetings. In the beginning, I would only speak at local events in the Malmö and Copenhagen area but, soon enough, I expanded to international conferences around Europe. I had found another outlet for doing what I love, which was great, but it still wasn’t part of my day job. My spare time was all I could give it.&lt;/p&gt;

&lt;h3 id=&quot;tretton37&quot;&gt;tretton37&lt;/h3&gt;

&lt;p&gt;In 2012, I found a young but ambitious consulting company that valued &lt;em&gt;knowledge sharing&lt;/em&gt; as much as I did: &lt;a href=&quot;https://tretton37.com&quot;&gt;tretton37&lt;/a&gt;. I joined them and had the privilege to represent those values at numerous conferences and user group events (including twice at their very own and highly praised &lt;a href=&quot;https://leetspeak.se&quot;&gt;Leetspeak&lt;/a&gt;). I had a great time! But as with all good things, there was a downside: although speaking &lt;em&gt;was&lt;/em&gt; part of my job description, it still only accounted for a small portion of my time. That didn’t bother me too much in the beginning but, as time went on, I wished I could do more.&lt;/p&gt;

&lt;p&gt;&lt;img alt=&quot;Speaking at a Foo Café meetup in Malmö, March 2013&quot; src=&quot;https://megakemp.com/assets/the-next-step/speaking.jpg&quot; class=&quot;screenshot-caption&quot; /&gt;
&lt;span class=&quot;caption&quot;&gt;Me, speaking at a &lt;a href=&quot;http://foocafe.org&quot; target=&quot;_blank&quot;&gt;Foo Café&lt;/a&gt; meetup in Malmö sponsored by tretton37 in March 2013.&lt;/span&gt;&lt;/p&gt;

&lt;h3 id=&quot;pluralsight&quot;&gt;Pluralsight&lt;/h3&gt;

&lt;p&gt;A couple of years ago, a dear friend of mine offered me the opportunity to start making online courses for &lt;a href=&quot;https://www.pluralsight.com&quot;&gt;Pluralsight&lt;/a&gt; as a side gig. This was right up my alley so, naturally, I jumped at the chance! After a few months, I published my &lt;a href=&quot;https://www.pluralsight.com/courses/git-advanced-tips-tricks&quot;&gt;first course&lt;/a&gt; on one of my favorite subjects: &lt;a href=&quot;/git&quot;&gt;Git&lt;/a&gt;. It was a lot of work (and I mean &lt;em&gt;a lot&lt;/em&gt;) but I enjoyed it and wanted to do more. Unfortunately, once again, this wasn’t my main job, so I could only work on it in the evenings and weekends.&lt;/p&gt;

&lt;p&gt;That’s when reality finally caught up with me.&lt;/p&gt;

&lt;h3 id=&quot;standing-at-a-crossroads&quot;&gt;Standing at a Crossroads&lt;/h3&gt;

&lt;p&gt;When you’re following your passion, it’s easy to become laser-focused and forget about the other important aspects of life. I have a wife and two young daughters. It has always been my top priority to be there for them, regardless of my current workload; however, in reality, I sometimes failed to live up to that.&lt;/p&gt;

&lt;p&gt;Eventually, I realized that pursuing two careers is unsustainable — willingness be damned. I had to make a choice: I could either keep working as a full-time consultant or I could dedicate myself to what I &lt;em&gt;really&lt;/em&gt; love: teaching.&lt;/p&gt;

&lt;p&gt;Needless to say, I chose the latter.&lt;/p&gt;

&lt;p&gt;I am grateful for my time at tretton37 — they’re a talented group of people with a &lt;a href=&quot;https://tretton37.com/knowledge-sharing&quot;&gt;great culture&lt;/a&gt; and I wish them all the best for the future. As for myself, I’m going to pursue my dream of helping others improve the way they develop software by &lt;a href=&quot;/services&quot;&gt;teaching and mentoring&lt;/a&gt;.&lt;/p&gt;

&lt;hr /&gt;

&lt;h2 id=&quot;whats-next&quot;&gt;What’s Next&lt;/h2&gt;

&lt;p&gt;Basically, I’m going to be working on the same things I did before in my spare time, only now they &lt;em&gt;are&lt;/em&gt; my day job.&lt;/p&gt;

&lt;p&gt;I’ll continue to make courses for Pluralsight.&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt; I’ll also be doing &lt;a href=&quot;/services/#training&quot;&gt;on-site training&lt;/a&gt; with presentations and &lt;a href=&quot;/workshops&quot;&gt;workshops&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In addition to that, I’ll be offering a new consulting service that combines education with productivity: I call it &lt;a href=&quot;/services/#mentoring&quot;&gt;&lt;em&gt;teaching by doing&lt;/em&gt;&lt;/a&gt;. You can read more about that in my &lt;a href=&quot;/services/#mentoring&quot;&gt;services page&lt;/a&gt;, if you’re interested.&lt;/p&gt;

&lt;p&gt;That’s all for now. If you’ve made it this far, thank you for reading. Exciting times are ahead and I can’t wait to get started.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Back then, it would have been either PC hardware, radioactivity, the NBA or all of the above. 😳 &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;In fact, I have a &lt;a href=&quot;https://megakemp.com/2017/10/20/cake-at-pluralsight/&quot;&gt;&lt;em&gt;new course&lt;/em&gt;&lt;/a&gt; coming out in just a few short weeks, so watch out for that. 😊 &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Wed, 13 Sep 2017 00:00:00 +0000</pubDate>
        <link>https://megakemp.com/2017/09/13/the-next-step/</link>
        <guid isPermaLink="true">https://megakemp.com/2017/09/13/the-next-step/</guid>
      </item>
    
      <item>
        <title>What&apos;s in a Branch</title>
        <description>&lt;h3 id=&quot;graphs-and-references&quot;&gt;Graphs and References&lt;/h3&gt;

&lt;p&gt;Before I tell you all about querying the state of your branches, let’s back up for a second and remind ourselves of how Git views history.&lt;/p&gt;

&lt;p&gt;Consider this graph:&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;screenshot-noshadow&quot; alt=&quot;Directed acyclic graph&quot; src=&quot;https://megakemp.com/assets/what-is-in-a-git-branch/graph.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;What you’re seeing here is a &lt;a href=&quot;https://en.wikipedia.org/wiki/Directed_acyclic_graph&quot;&gt;&lt;em&gt;directed acyclic graph&lt;/em&gt;&lt;/a&gt;: a fancy name used to describe a group of nodes (&lt;em&gt;graph&lt;/em&gt;) where the edges point to a certain direction (&lt;em&gt;directed&lt;/em&gt;) and never loop back on themselves (&lt;em&gt;acyclic&lt;/em&gt;).&lt;/p&gt;

&lt;p&gt;Why is it relevant? Because this is how Git represents history.&lt;/p&gt;

&lt;p&gt;In Git’s parlance, each node represents a &lt;em&gt;commit&lt;/em&gt; and each commit has exactly one edge that connects it to its &lt;em&gt;parent&lt;/em&gt;. In other words, the directed acyclic graph of a Git history can only go in one direction: &lt;em&gt;backwards&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;So far, so good. Now let’s add one more piece of information to the mix:&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;screenshot-noshadow&quot; alt=&quot;Branch&quot; src=&quot;https://megakemp.com/assets/what-is-in-a-git-branch/branch.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;See that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; label? That’s a &lt;em&gt;branch&lt;/em&gt;. Branches are simply &lt;a href=&quot;https://git-scm.com/docs/gitglossary#gitglossary-aiddefrefaref&quot;&gt;&lt;em&gt;references&lt;/em&gt;&lt;/a&gt; that point to specific commits. In fact, a branch is a &lt;em&gt;41 bytes&lt;/em&gt; text file that contains the ID of the commit it references. Don’t believe me? Try running this command in the root of your repository:&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; .git/refs/heads/master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;You’ll get back something like this:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;514e6c9c96d27ab9eb776644c7c3cdadce61979f
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That 41 characters string is the SHA-1 hash of the &lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Internals-Git-Objects&quot;&gt;&lt;em&gt;commit object&lt;/em&gt;&lt;/a&gt; that’s currently referenced by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; branch. Go ahead, verify it with:&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git show 514e6c9
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Hopefully, you’ll believe me now. So, let’s boil it all down to a single sentence to make it easier to remember:&lt;/p&gt;

&lt;div class=&quot;note&quot;&gt;
&lt;p&gt;
&lt;i class=&quot;fa fa-code-fork fa-2x pull-left&quot;&gt;&lt;/i&gt;
In Git, a branch is a &lt;a href=&quot;https://git-scm.com/docs/gitglossary#gitglossary-aiddefrefaref&quot;&gt;&lt;em&gt;reference&lt;/em&gt;&lt;/a&gt; to the latest commit in a sequence; the history of a branch is reconstructed starting from that latest commit going backwards, following the chain of parents.
&lt;/p&gt;
&lt;/div&gt;

&lt;h3 id=&quot;reachability&quot;&gt;Reachability&lt;/h3&gt;

&lt;p&gt;Now that we have a good mental model for thinking about history, we can talk about the concept of &lt;em&gt;reachability&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Imagine we have a history that looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;screenshot-noshadow&quot; alt=&quot;Fork&quot; src=&quot;https://megakemp.com/assets/what-is-in-a-git-branch/fork.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here, we have two branches named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;feature&lt;/code&gt; that diverge on commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;B&lt;/code&gt;. We can immediately observe two things at first glance:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;feature&lt;/code&gt; branch contains commits &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;E&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D&lt;/code&gt; which are &lt;em&gt;not&lt;/em&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; has commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C&lt;/code&gt; that’s &lt;em&gt;not&lt;/em&gt; in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;feature&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Sure, it’s easy enough to tell when your history is this small—and you have a pretty graph to look at—but it might not be as obvious once you deal with more than two branches and a large number of commits.&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;But don’t despair: everything becomes much clearer once you start thinking in terms of commits and what is &lt;em&gt;reachable&lt;/em&gt; from which branch. Let me explain:&lt;/p&gt;

&lt;div class=&quot;note&quot;&gt;
&lt;p&gt;
&lt;i class=&quot;fa fa-hand-o-right fa-2x pull-left&quot;&gt;&lt;/i&gt;
A commit &lt;code&gt;A&lt;/code&gt; is said to be &lt;em&gt;reachable&lt;/em&gt; from another commit &lt;code&gt;B&lt;/code&gt; if there exists a &lt;em&gt;contiguous&lt;/em&gt; path of commits that lead from &lt;code&gt;B&lt;/code&gt; to &lt;code&gt;A&lt;/code&gt;.
&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;In other words, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A&lt;/code&gt; is &lt;em&gt;reachable&lt;/em&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;B&lt;/code&gt; if you can start from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;B&lt;/code&gt; and arrive at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;A&lt;/code&gt; just by following the chain of parents.&lt;/p&gt;

&lt;p&gt;Easy, right? Now, combine this concept with the notion that branches are just &lt;em&gt;references&lt;/em&gt; to commits and you have all the pieces you need to solve the puzzle!&lt;/p&gt;

&lt;p&gt;Reachability is a powerful concept because it allows us to take our initial question:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Which commits are in a branch?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;and turn it into:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Which commits are reachable from a branch and not from another?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Git has a way to express this: it’s called the &lt;a href=&quot;https://www.git-scm.com/book/id/v2/Git-Tools-Revision-Selection#_double_dot&quot;&gt;&lt;em&gt;double dot&lt;/em&gt;&lt;/a&gt; notation. Consider this command:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git log &lt;span class=&quot;nt&quot;&gt;--oneline&lt;/span&gt; master..feature
9b571c2 E
fa77581 D
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This literally means: show me the commits that are &lt;em&gt;not reachable&lt;/em&gt; from the first reference in the range (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt;) but that &lt;em&gt;are reachable&lt;/em&gt; from the second reference (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;feature&lt;/code&gt;). The results is commits &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;E&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;screenshot-noshadow&quot; alt=&quot;Reachable from feature&quot; src=&quot;https://megakemp.com/assets/what-is-in-a-git-branch/unmerged-right.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Observe what happens when we switch places between the two branch references:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git log &lt;span class=&quot;nt&quot;&gt;--oneline&lt;/span&gt; feature..master
2eec656 C
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s right, we get commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C&lt;/code&gt;, that is the commit &lt;em&gt;not reachable&lt;/em&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;feature&lt;/code&gt; but &lt;em&gt;reachable&lt;/em&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;screenshot-noshadow&quot; alt=&quot;Reachable from master&quot; src=&quot;https://megakemp.com/assets/what-is-in-a-git-branch/unmerged-left.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;This expression is so useful that I even made an &lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases&quot;&gt;alias&lt;/a&gt; for it:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git config &lt;span class=&quot;nt&quot;&gt;--global&lt;/span&gt; alias.new &lt;span class=&quot;s2&quot;&gt;&quot;log master..HEAD&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Now, every time I want to know which commits are in my &lt;em&gt;current&lt;/em&gt; branch (referenced by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD&lt;/code&gt;) that I haven’t yet merged into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt;, I simply say:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git new
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;what-was-merged&quot;&gt;What Was Merged?&lt;/h3&gt;

&lt;p&gt;If your workflow involves a lot of merge commits (like &lt;a href=&quot;http://nvie.com/posts/a-successful-git-branching-model&quot;&gt;GitFlow&lt;/a&gt;), one of the questions that will pop up a lot is:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Which commits were brought into a branch by a specific merge?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To answer that, let’s consider our two sample branches; this time, we’re going to merge feature &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;feature&lt;/code&gt; into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;screenshot-noshadow&quot; alt=&quot;Merged feature into master&quot; src=&quot;https://megakemp.com/assets/what-is-in-a-git-branch/merged-before.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Let’s play a bit of &lt;a href=&quot;https://en.wikipedia.org/wiki/Jeopardy!&quot;&gt;Jeopardy&lt;/a&gt;&lt;sup id=&quot;fnref:4&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:4&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;: if the answer is commits &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;E&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D&lt;/code&gt;, what’s the Git command? Remember, we don’t have a pretty graph to look at; all we have is the console and the concept of &lt;em&gt;reachability&lt;/em&gt; that we talked about before. Give it some thought. Can you guess it?&lt;/p&gt;

&lt;p&gt;Let me give you a hint. Another way of phrasing the question we’re looking for is:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Which commits were &lt;em&gt;not reachable&lt;/em&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; &lt;em&gt;before&lt;/em&gt; the merge commit but are &lt;em&gt;reachable&lt;/em&gt; now?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Considering that the &lt;em&gt;first parent&lt;/em&gt; of a merge commit is always the &lt;em&gt;destination&lt;/em&gt; branch—that is the branch that was &lt;em&gt;merged to&lt;/em&gt;—one way to express that would be:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git log &lt;span class=&quot;nt&quot;&gt;--oneline&lt;/span&gt; M^..M
cad1c97 M
9b571c2 E
fa77581 D
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This is saying: show me the commits that are &lt;em&gt;not reachable&lt;/em&gt; from the first parent of the merge commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M&lt;/code&gt; (that is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C&lt;/code&gt;) but that &lt;em&gt;are reachable&lt;/em&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img class=&quot;screenshot-noshadow&quot; alt=&quot;What was merged into master&quot; src=&quot;https://megakemp.com/assets/what-is-in-a-git-branch/merged-after.png&quot; /&gt;&lt;/p&gt;

&lt;p&gt;As you would expect, we get back &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M&lt;/code&gt; itself followed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;E&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;D&lt;/code&gt;, that is the commits merged into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; 🎉&lt;/p&gt;

&lt;p&gt;This expression is so common that it even has a shorter—albeit more unreadable—version &lt;a href=&quot;https://github.com/git/git/blob/master/Documentation/RelNotes/2.11.0.txt#L106-L110&quot;&gt;as of Git 2.11&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git log M^-1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Just when you thought Git commands couldn’t get any more cryptic, right? Anyway, this is the equivalent of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M^..M&lt;/code&gt; where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;^-1&lt;/code&gt; refers to the &lt;em&gt;first parent&lt;/em&gt; of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;M&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Of course, we don’t have to limit ourselves to just the list of commits. If we wanted, you could also get a patch containing &lt;em&gt;the collective changes&lt;/em&gt; that got merged into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; by saying:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git diff M^-1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Git’s syntax might be ridiculously opaque at times, but finding out what’s in a branch is easier than ever thanks to Git’s intuitive branching model.&lt;/p&gt;

&lt;div class=&quot;note&quot;&gt;
&lt;p&gt;
&lt;i class=&quot;fa fa-play-circle-o fa-2x pull-left pull-left-three-lines&quot;&gt;&lt;/i&gt;
Was this helpful? If you like, you can find even more ways to slice and dice the history of your Git repository in my &lt;a href=&quot;https://www.pluralsight.com/authors/enrico-campidoglio&quot;&gt;Pluralsight&lt;/a&gt; course &lt;a href=&quot;https://www.pluralsight.com/courses/git-tips-tricks&quot;&gt;Git Tips and Tricks&lt;/a&gt;.
&lt;/p&gt;
&lt;/div&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;If you’re on Windows and don’t use Bash, you can replace that with: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;notepad .git\refs\heads\master&lt;/code&gt;. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;You don’t have to use the entire SHA-1 hash here; just enough for Git to tell which object it belongs to. For most repositories, the first &lt;em&gt;7 characters&lt;/em&gt; are enough to uniquely identify an object. Git calls this the &lt;em&gt;abbreviated&lt;/em&gt; hash. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Actually, it doesn’t take much before this happens: imagine a typical &lt;a href=&quot;http://nvie.com/posts/a-successful-git-branching-model&quot;&gt;GitFlow&lt;/a&gt; scenario where you have multiple &lt;em&gt;feature&lt;/em&gt; and &lt;em&gt;bugfix&lt;/em&gt; branches running in parallel and you need to tell which commits are available in &lt;em&gt;develop&lt;/em&gt; and which aren’t. 😰 &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:4&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;I’ll tell you the answer and you’ll have to guess the question. &lt;a href=&quot;#fnref:4&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Wed, 19 Apr 2017 00:00:00 +0000</pubDate>
        <link>https://megakemp.com/2017/04/19/what-is-in-a-git-branch/</link>
        <guid isPermaLink="true">https://megakemp.com/2017/04/19/what-is-in-a-git-branch/</guid>
      </item>
    
      <item>
        <title>Git Undo</title>
        <description>&lt;p&gt;Tell me if you recognize this scenario: you’re in the middle of &lt;a href=&quot;/2014/08/14/the-importance-of-a-good-looking-history&quot;&gt;rewriting your local commits&lt;/a&gt; when you suddenly realize that you have gone too far and, after one too many rebases, you are left with a history that looks nothing like the way you wanted. No? Well, I certainly do. And when that happens, I wish I could just &lt;kbd&gt;CTRL&lt;/kbd&gt;+&lt;kbd&gt;Z&lt;/kbd&gt; my way back to where I started. Of course, it’s never that simple — not even in &lt;a href=&quot;https://vimeo.com/171317261&quot;&gt;a GUI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;It was in one of those moments of despair that I finally decided to set out to create my own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git undo&lt;/code&gt; command. Here’s what I came up with and how I got there.&lt;/p&gt;

&lt;h3 id=&quot;the-reflog&quot;&gt;The Reflog&lt;/h3&gt;

&lt;p&gt;My story of undoing things in Git starts with the reflog. &lt;em&gt;What’s the reflog&lt;/em&gt;, you might ask. Well, I’m here to tell you: every time a &lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Internals-Git-References&quot;&gt;&lt;em&gt;branch reference&lt;/em&gt;&lt;/a&gt; moves&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt; Git records its previous value in a sort of local journal. This journal is the called the &lt;em&gt;reference log&lt;/em&gt; — or &lt;a href=&quot;https://git-scm.com/docs/git-reflog&quot;&gt;reflog&lt;/a&gt; for short.&lt;/p&gt;

&lt;p&gt;In a repository there is a reflog for &lt;em&gt;each branch&lt;/em&gt; as well as a separate one for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD&lt;/code&gt; reference.&lt;/p&gt;

&lt;p&gt;Getting the list of entries in a branch’s reflog is as easy as saying &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git reflog&lt;/code&gt; followed by the name of the branch:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git reflog master
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;shows the reflog entries for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; branch:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://megakemp.com/assets/git-undo/git-reflog-master.png&quot;&gt;
&lt;img src=&quot;https://megakemp.com/assets/git-undo/git-reflog-master.png&quot; alt=&quot;Output of git-reflog for the master branch&quot; title=&quot;Output of git-reflog for the master branch&quot; class=&quot;screenshot&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you instead wanted to look at &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD&lt;/code&gt;’s own reflog, you would simply omit the argument and say:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git reflog
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;which yields the same output, only for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD&lt;/code&gt; reference:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://megakemp.com/assets/git-undo/git-reflog-head.png&quot;&gt;
&lt;img src=&quot;https://megakemp.com/assets/git-undo/git-reflog-head.png&quot; alt=&quot;Output of git-reflog for the HEAD reference&quot; title=&quot;Output of git-reflog for the HEAD reference&quot; class=&quot;screenshot&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What isn’t immediately obvious is that the entries in the reflog are stored in &lt;em&gt;reverse chronological order&lt;/em&gt; with the most recent one on top.&lt;/p&gt;

&lt;p&gt;What &lt;em&gt;is&lt;/em&gt; obvious, on the other hand, is that each entry has its own &lt;em&gt;index&lt;/em&gt;. This turns out to be &lt;em&gt;extremely&lt;/em&gt; useful, because we can use that index to directly reference the commit associated to a certain reflog entry. But more on that later. For now, suffice it to say that in order to reference a reflog entry, we have to use the syntax:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;reference@{index}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;where the two parts separated by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@&lt;/code&gt; sign are:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;reference&lt;/code&gt; which can either be the name of a branch or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD&lt;/code&gt;&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;index&lt;/code&gt; which is the entry’s position in the reflog&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, let’s say that we wanted to look at the commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD&lt;/code&gt; was referencing &lt;em&gt;two positions ago&lt;/em&gt;. To do that, we could use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git show&lt;/code&gt; command followed by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD@{2}&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git show HEAD@{2}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If we, instead, wanted to look at the commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; was referencing just &lt;em&gt;before the latest one&lt;/em&gt; we would say:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git show master@{1}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;the-undo-alias&quot;&gt;The Undo Alias&lt;/h3&gt;

&lt;p&gt;Here’s my point: the &lt;a href=&quot;https://git-scm.com/docs/git-reflog&quot;&gt;reflog&lt;/a&gt; keeps track of the history of commits referenced by a branch, just like a web browser keeps track of the history of URLs we visit.&lt;/p&gt;

&lt;div class=&quot;note&quot;&gt;
&lt;p&gt;
&lt;i class=&quot;fa fa-bullhorn fa-2x pull-left&quot;&gt;&lt;/i&gt;
This means that the commit referenced by &lt;code&gt;@{1}&lt;/code&gt; is &lt;em&gt;always&lt;/em&gt; the commit that was referenced &lt;em&gt;just before the current one&lt;/em&gt;.
&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;If we were to combine the reflog with the &lt;a href=&quot;https://git-scm.com/docs/git-reset&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git reset&lt;/code&gt;&lt;/a&gt; command like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git reset --hard master@{1}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;we would suddenly have a way to move &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD&lt;/code&gt;, the &lt;em&gt;index&lt;/em&gt; and the &lt;em&gt;working directory&lt;/em&gt; to the previous commit referenced by a branch. This is essentially the same as &lt;a href=&quot;http://stackoverflow.com/q/1313788/26396&quot;&gt;&lt;em&gt;pressing the back button&lt;/em&gt;&lt;/a&gt; in our web browser!&lt;/p&gt;

&lt;p&gt;At this point, we have everything we need to implement our own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git undo&lt;/code&gt; command, which we do in the form of an &lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases&quot;&gt;alias&lt;/a&gt;. Here it is:&lt;/p&gt;

&lt;div class=&quot;language-shell highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git config &lt;span class=&quot;nt&quot;&gt;--global&lt;/span&gt; alias.undo &lt;span class=&quot;s1&quot;&gt;&apos;!f() { \
    git reset --hard $(git rev-parse --abbrev-ref HEAD)@{${1-1}}; \
}; f&apos;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;I realize it’s quite a mouthful so let’s break it down piece by piece:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;!f() { ... } f&lt;/code&gt;&lt;br /&gt;
Here, we’re defining the alias as a &lt;em&gt;shell function&lt;/em&gt; named &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;f&lt;/code&gt; which is then invoked immediately.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$(git rev-parse --abbrev-ref HEAD)@{...}&lt;/code&gt;&lt;br /&gt;
We use the &lt;a href=&quot;https://git-scm.com/docs/git-rev-parse&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git rev-parse&lt;/code&gt;&lt;/a&gt; command followed by the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--abbrev-ref&lt;/code&gt; option to get the name of the current branch, which we then concatenate with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@{...}&lt;/code&gt; to form the reference to a previous position in the reflog (e.g. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master@{1}&lt;/code&gt;).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;${1-1}&lt;/code&gt;&lt;br /&gt;
We specify the position in the reflog as the first parameter &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$1&lt;/code&gt; with a default value of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;1&lt;/code&gt;. This is the whole reason why we defined the alias as a shell function: to be able to provide a default value for the parameter using the standard &lt;a href=&quot;http://www.gnu.org/software/bash/manual/bashref.html#Shell-Parameter-Expansion&quot;&gt;Bash syntax&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The beauty of using an optional parameter like this, is that it allows us to undo any number of operations. At the same time, if we don’t specify anything, it’s going to undo the just latest one.&lt;/p&gt;

&lt;h3 id=&quot;trying-it-out&quot;&gt;Trying It Out&lt;/h3&gt;

&lt;p&gt;Let’s say that we have a history that looks like this:&lt;sup id=&quot;fnref:3&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:3&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://megakemp.com/assets/git-undo/git-lg-before.png&quot;&gt;
&lt;img src=&quot;https://megakemp.com/assets/git-undo/git-lg-before.png&quot; alt=&quot;History before the rewrite&quot; title=&quot;History before the rewrite&quot; class=&quot;screenshot&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We have two branches — &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;feature&lt;/code&gt; — that have diverged at commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;C&lt;/code&gt;. For the sake of our example, let’s also assume that we wanted to remove the latest commit in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; — that is commit &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;F&lt;/code&gt; — and then merge the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;feature&lt;/code&gt; branch:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git reset --hard HEAD^
git merge feature
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;At this point, we would end up with a history looking like this:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://megakemp.com/assets/git-undo/git-lg-after.png&quot;&gt;
&lt;img src=&quot;https://megakemp.com/assets/git-undo/git-lg-after.png&quot; alt=&quot;History after the rewrite&quot; title=&quot;History after the rewrite&quot; class=&quot;screenshot&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As you can see, everything went fine — but we’re still not happy. For some reason, we want to go back to the way history was before. In practice, this means we need to undo our latest &lt;em&gt;two&lt;/em&gt; operations: the &lt;em&gt;merge&lt;/em&gt; and the &lt;em&gt;reset&lt;/em&gt;. Time to whip out that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;undo&lt;/code&gt; alias:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git undo 2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This moves &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD&lt;/code&gt; to the commit referenced by &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master@{2}&lt;/code&gt; — that is the commit the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master&lt;/code&gt; branch was pointing to &lt;em&gt;2 reflog entries ago&lt;/em&gt;. Let’s go ahead and check our history again:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://megakemp.com/assets/git-undo/git-lg-restored.png&quot;&gt;
&lt;img src=&quot;https://megakemp.com/assets/git-undo/git-lg-restored.png&quot; alt=&quot;History restored with the undo alias&quot; title=&quot;History restored with the undo alias&quot; class=&quot;screenshot&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And everything is back the way it was. \o/&lt;/p&gt;

&lt;p&gt;But what if wanted to &lt;em&gt;undo the undo&lt;/em&gt;? Easy. Since &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git undo&lt;/code&gt; itself creates an entry in the reflog, it’s enough to say:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;git undo
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;which, without argument, is the equivalent of saying &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git undo 1&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;note&quot;&gt;
&lt;p&gt;
&lt;i class=&quot;fa fa-play-circle-o fa-2x pull-left pull-left-three-lines&quot;&gt;&lt;/i&gt;
Did you find this useful? If you&apos;re interested in learning other techniques like the one described in this article, I wrote down a few more in my &lt;a href=&quot;https://www.pluralsight.com/authors/enrico-campidoglio&quot;&gt;Pluralsight&lt;/a&gt; course &lt;a href=&quot;https://www.pluralsight.com/courses/git-tips-tricks&quot;&gt;Git Tips and Tricks&lt;/a&gt;.
&lt;/p&gt;
&lt;/div&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;That is, it’s &lt;em&gt;modified&lt;/em&gt; to point to a different commit than it did before. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;You can also use &lt;em&gt;dates&lt;/em&gt; here. Try for example &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;master@{yesterday}&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;HEAD@{2.days.ago}&lt;/code&gt; — pretty amazing, don’t you think? &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:3&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;I like my history succinct and colorful. For this reason, I never use the plain &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log&lt;/code&gt;; instead, I define an alias called &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lg&lt;/code&gt; where I use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--pretty&lt;/code&gt; option to &lt;a href=&quot;https://git-scm.com/docs/pretty-formats&quot;&gt;customize its output&lt;/a&gt;. If you want to know more, I wrote about this a while ago when talking about the &lt;a href=&quot;/2014/08/14/the-importance-of-a-good-looking-history&quot;&gt;importance of a good-looking history&lt;/a&gt;. &lt;a href=&quot;#fnref:3&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Thu, 25 Aug 2016 00:00:00 +0000</pubDate>
        <link>https://megakemp.com/2016/08/25/git-undo/</link>
        <guid isPermaLink="true">https://megakemp.com/2016/08/25/git-undo/</guid>
      </item>
    
      <item>
        <title>On Being a Good .NET Developer</title>
        <description>&lt;p&gt;While reading &lt;a href=&quot;https://twitter.com/RobAshton&quot;&gt;Rob Ashton&lt;/a&gt;’s thought-provoking piece titled “&lt;a href=&quot;http://codeofrob.com/entries/why-you-cant-be-a-good-.net-developer.html&quot;&gt;&lt;em&gt;Why you can’t be a good .NET developer&lt;/em&gt;&lt;/a&gt;” over my morning cappuccino the other day, for the first few paragraphs I found myself nodding in agreement.&lt;/p&gt;

&lt;p&gt;Having been a consultant for the past fifteen years, I’ve certainly come across more than a few teams where the “&lt;em&gt;lowest common denominator&lt;/em&gt;” was without a doubt the driving force behind every decision. This isn’t in any way unique to .NET, though. I have seen the exact same thing happen in other platforms as well: Java, JavaScript and — to some degree — even C, C++&lt;sup id=&quot;fnref:1&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:1&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;

&lt;p&gt;What they all have in common is a &lt;em&gt;humongous&lt;/em&gt; active user base.&lt;/p&gt;

&lt;p&gt;You see, it’s simply a matter of statistics: the more popular the platform&lt;sup id=&quot;fnref:2&quot; role=&quot;doc-noteref&quot;&gt;&lt;a href=&quot;#fn:2&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;, the higher the number of beginners. The two variables are directly proportional to each other — some might argue even exponential. If you’re looking for a concrete example, consider the amount of novice JavaScript developers brought in by the popularity of &lt;a href=&quot;https://jquery.com&quot;&gt;jQuery&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The problem is not that .NET has an &lt;em&gt;unusually&lt;/em&gt; high number of “&lt;em&gt;lowest common denominators&lt;/em&gt;”. That number is simply &lt;em&gt;higher&lt;/em&gt; compared to platforms with a narrower, mostly self-selected, audience.&lt;/p&gt;

&lt;p&gt;The problem — and this is where I disagree with the underlying message in that article — is failing a platform based on the number of inexperienced programmers who work with it.&lt;/p&gt;

&lt;p&gt;I also don’t think that fleeing is the right way to handle the situation. I don’t know about you, but I like to apply the &lt;a href=&quot;http://programmer.97things.oreilly.com/wiki/index.php/The_Boy_Scout_Rule&quot;&gt;Boy Scout Rule&lt;/a&gt; in more than just code; when I join a team, I want to leave it in better shape than I found it. This means that if I join a team who is dominated by inexperienced programmers, I don’t see it as an excuse to hold back on quality. Quite the opposite, I feel compelled to introduce the team to new ways of doing things, new perspectives. Note that I don’t &lt;em&gt;force&lt;/em&gt; anything on anyone; instead, I try to lead by example.&lt;/p&gt;

&lt;p&gt;For instance, if I see that the team is stuck using TFS, I will still use Git on my machine and add a bridge like &lt;a href=&quot;https://github.com/git-tfs/git-tfs&quot;&gt;git-tfs&lt;/a&gt; to collaborate. Sooner or later, without mistake, someone is going to wonder why I do that. Driven by curiosity, they’ll ask me to explain how Git is better than TFS and I’ll be more than happy to tell them all about it. After a while, that same person — or someone else on the team — is going to start using Git on their own machine and, soon enough, the entire team will be sitting in a console firing Git commands like there’s no tomorrow, wondering why they hadn’t learned it earlier.&lt;/p&gt;

&lt;p&gt;I never compromise on excellence. It’s just that with some teams, the way to get there is longer than with others.&lt;/p&gt;

&lt;p&gt;To me the solution isn’t to run away from beginners. It’s to inspire and mentor them so that they won’t stay beginners forever and instead go on to do the same for other people. That applies as much to .NET as it does to any other platform or language.&lt;/p&gt;

&lt;p&gt;If you aren’t the type of person who has the time or the interest to raise the lowest common denominator, that’s perfectly fine. I do believe you’re better off moving somewhere else where your ambitions aren’t being held back by inexperienced team members. As for myself, I’ll stay behind — teaching.&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:1&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;C and C++ have a steep learning curve which forces programmers to move past the beginner stage far more quickly than with other languages in order to get anything done. So, while C and C++ are immensely widespread, the number of novices who work with them tends to stay relatively low. &lt;a href=&quot;#fnref:1&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:2&quot; role=&quot;doc-endnote&quot;&gt;
      &lt;p&gt;Just to be clear, by “platform” I mean a programming language together with its ecosystem of libraries, frameworks and tools. &lt;a href=&quot;#fnref:2&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Mon, 20 Jun 2016 00:00:00 +0000</pubDate>
        <link>https://megakemp.com/2016/06/20/on-being-a-good-dotnet-developer/</link>
        <guid isPermaLink="true">https://megakemp.com/2016/06/20/on-being-a-good-dotnet-developer/</guid>
      </item>
    
      <item>
        <title>The importance of a good-looking history</title>
        <description>&lt;blockquote&gt;
  &lt;p&gt;“Study the past if you would define the future.” ~Confucius&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Since the dawn of civilization, common sense has taught us that the way forward starts by knowing how we got here in the first place. While this powerful principle applies to practically all aspects of life, it’s especially true when developing software.&lt;/p&gt;

&lt;p&gt;For us programmers, the rear mirror through which we look at the history of a code base before we go on to shape its future is &lt;a href=&quot;https://en.wikipedia.org/wiki/Version_control&quot;&gt;version control&lt;/a&gt;. Among all the information captured by a version control tool, the most critical ones are the &lt;em&gt;commit messages&lt;/em&gt;.&lt;/p&gt;

&lt;h3 id=&quot;gits-view-of-history&quot;&gt;Git’s view of history&lt;/h3&gt;

&lt;p&gt;When we’re trying to understand how a piece of software has evolved over time, the first thing we tend to do is look at the trails of messages left by the programmers who came before us. Those sentences hold the key to understanding the choices that molded the software into what it is today.&lt;/p&gt;

&lt;div class=&quot;note&quot;&gt;
&lt;p&gt;
&lt;i class=&quot;fa fa-bullhorn fa-2x pull-left&quot;&gt;&lt;/i&gt;
In other words, what you write in these messages is &lt;strong&gt;crucial&lt;/strong&gt; and you should put extra effort in making them as &lt;strong&gt;loud&lt;/strong&gt; and &lt;strong&gt;clear&lt;/strong&gt; as possible.
&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;This is true regardless of what version control system you happen to be using. However, it is especially true for &lt;a href=&quot;http://git-scm.com&quot;&gt;Git&lt;/a&gt;. Why? Because Git simply holds the history of your code to a &lt;em&gt;higher standard&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;As Linus Torvalds explained in his excellent &lt;a href=&quot;http://youtu.be/4XpnKHJAok8&quot;&gt;Teck Talk at Google back in 2007&lt;/a&gt;, Git evolved out of the need to manage the development of the Linux kernel, a humongous open source project with a &lt;a href=&quot;https://github.com/torvalds/linux/commit/1da177e4c3f41524e886b7f1b8a0c1fc7321cac2&quot;&gt;20 year history&lt;/a&gt; and hundreds of contributors from all around the world.&lt;/p&gt;

&lt;p&gt;If source code history has ever played a more critical role in a software project, the Linux kernel is where it’s at.&lt;/p&gt;

&lt;p&gt;Torvalds’ attention to history is also reflected in the features he built into his own distributed version control tool. To put it in &lt;a href=&quot;http://www.mail-archive.com/dri-devel@lists.sourceforge.net/msg39091.html&quot;&gt;his own words&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I want clean history, but that really means (a) clean and (b) history.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Regarding the “&lt;em&gt;clean&lt;/em&gt;” part, he goes on to elaborate:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Keep your own history readable.&lt;/p&gt;

  &lt;p&gt;Some people do this by just working things out in their head first, and not making mistakes. But that’s very rare, and for the rest of us, we use “git rebase” etc. while we work on our problems.&lt;/p&gt;

  &lt;p&gt;Don’t expose your crap.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;When it comes to “&lt;em&gt;history&lt;/em&gt;”, he says:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;People can (and probably should) rebase their &lt;em&gt;private&lt;/em&gt; trees (their own
work). That’s a &lt;em&gt;cleanup&lt;/em&gt;. But never other people’s code. That’s a “destroy
history”&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You see, Git grants you all the tools you need to &lt;a href=&quot;http://git-scm.com/book/en/Git-Tools-Rewriting-History&quot;&gt;go back in time and rewrite your own commits&lt;/a&gt; (for example by changing their &lt;em&gt;order&lt;/em&gt;, &lt;em&gt;contents&lt;/em&gt; and &lt;em&gt;messages&lt;/em&gt;) because having a clear history of the code &lt;em&gt;matters&lt;/em&gt;. It matters to the sanity of whoever is working on it; present or future.&lt;/p&gt;

&lt;h3 id=&quot;a-legacy-of-e-mails&quot;&gt;A legacy of e-mails&lt;/h3&gt;

&lt;p&gt;Having talked about the importance of keeping your history clean, let’s take the concept one step further.&lt;/p&gt;

&lt;div class=&quot;note&quot;&gt;
&lt;p&gt;
&lt;i class=&quot;fa fa-pencil-square-o fa-2x pull-left&quot;&gt;&lt;/i&gt;
When you use Git, you should not only pay attention to the contents of your commit messages, but also how they&apos;re &lt;strong&gt;formatted&lt;/strong&gt;.
&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;There’s a reason for that. As Torvalds himself stated in &lt;a href=&quot;http://youtu.be/4XpnKHJAok8?t=2m49s&quot;&gt;his Google talk&lt;/a&gt;, for a long period of time the history of the Linux kernel was captured in &lt;strong&gt;e-mail threads with patches attached&lt;/strong&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“For the first 10 years of kernel maintenance
we literally used tarballs and patches.” ~Linus Torvalds&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Even in the early days of Git, e-mail was still used as a way to send patches among collaborators of the Linux project.&lt;/p&gt;

&lt;p&gt;If you look closely, you’ll notice that the concept of e-mail is pretty pervasive throughout Git. Here’s some evidence off the top of my head:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Every user &lt;em&gt;has to have&lt;/em&gt; an e-mail address which is always part of the commit’s metadata&lt;/li&gt;
  &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git format-patch&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git am&lt;/code&gt; commands are specifically designed to convert commits into e-mails with patches as attachments&lt;/li&gt;
  &lt;li&gt;Both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git blame&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git shortlog&lt;/code&gt; have special options to display the committers’ e-mail addresses instead of their names&lt;/li&gt;
  &lt;li&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log&lt;/code&gt; command has &lt;a href=&quot;https://www.kernel.org/pub/software/scm/git/docs/git-log.html#_pretty_formats&quot;&gt;dedicated placeholders&lt;/a&gt; to indicate a commit message’s &lt;strong&gt;subject&lt;/strong&gt; and &lt;strong&gt;body&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The last one is particularly interesting. Git seems to assume that a commit message is divided in two parts:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;A short one-sentence summary&lt;/li&gt;
  &lt;li&gt;An optional longer description defined in its own paragraph separated by an empty line&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A “&lt;em&gt;well-formed&lt;/em&gt;” Git commit message would then look like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;A short summary, possibly under 50 characters.

A longer description of the change and the reasoning
behind it for the future generations to know.
Even better if it&apos;s wrapped at 80 characters so that
it will look good in the console.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;If you follow this simple convention, Git will reward you by going out of its way to show you your history in the prettiest way possible. And that’s a &lt;em&gt;good thing&lt;/em&gt;.&lt;/p&gt;

&lt;h3 id=&quot;formatting-matters&quot;&gt;Formatting matters&lt;/h3&gt;

&lt;p&gt;Once you fall into the habit of keeping your commit messages under 50 characters and relegate any longer description to a separate paragraph, you can start &lt;a href=&quot;http://en.wikipedia.org/wiki/Prettyprint&quot;&gt;pretty-printing&lt;/a&gt; your history in almost &lt;a href=&quot;https://www.kernel.org/pub/software/scm/git/docs/git-log.html#_pretty_formats&quot;&gt;any way you like&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;For example, you could choose to only display the commits’ summaries by using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%s&lt;/code&gt; placeholder in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--format&lt;/code&gt; option of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git log&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://megakemp.com/assets/the-importance-of-a-good-looking-history/prettyformat-simple_hires.png&quot;&gt;
&lt;img src=&quot;https://megakemp.com/assets/the-importance-of-a-good-looking-history/prettyformat-simple.png&quot; alt=&quot;Simple example of pretty-printing the commit history&quot; title=&quot;Simple example of pretty-printing the commit history&quot; class=&quot;screenshot&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or you could go crazy with all kinds of colors and indentation:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://megakemp.com/assets/the-importance-of-a-good-looking-history/prettyformat-advanced_hires.png&quot;&gt;
&lt;img src=&quot;https://megakemp.com/assets/the-importance-of-a-good-looking-history/prettyformat-advanced.png&quot; alt=&quot;Gorgeous-looking commit history&quot; title=&quot;Gorgeous-looking commit history&quot; class=&quot;screenshot&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The format string I used in this particular example can be broken down as:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
&lt;span class=&quot;s2&quot;&gt;&quot;%C(cyan)%s%Creset %C(dim white)(%ar)%Creset%n%w(72,4,4)%b&quot;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;where:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%C(cyan)&lt;/code&gt; colors the following text in cyan&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%s&lt;/code&gt; shows the commit summary&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%Creset&lt;/code&gt; restores the default color for the text&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%C(dim white)&lt;/code&gt; colors the following text in grey&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%ar&lt;/code&gt; shows the time of the commit relative to now&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%n&lt;/code&gt; adds a newline character&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%w(72,4,4)&lt;/code&gt; wraps the following text at 72 characters. Then, indents the first line as well as the remaining ones with 4 spaces&lt;/li&gt;
  &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%b&lt;/code&gt; shows the long description of the commit, if any&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com&quot;&gt;GitHub&lt;/a&gt; itself follows this convention when showing the commit history of a project. In fact, they will only show you the &lt;em&gt;summary&lt;/em&gt; of each commit by default. If there’s a longer &lt;em&gt;description&lt;/em&gt; available, they allow you to expand it with the press of a button.&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;https://megakemp.com/assets/the-importance-of-a-good-looking-history/github-commitmessage.png&quot; alt=&quot;Commit message formatting in the GitHub web UI&quot; title=&quot;Commit message formatting in the GitHub web UI&quot; class=&quot;screenshot-noshadow-caption&quot; /&gt;
    &lt;span class=&quot;caption&quot;&gt;Pretty-printed commit message on GitHub&lt;/span&gt;
&lt;/p&gt;

&lt;h3 id=&quot;enforcing-the-rule&quot;&gt;Enforcing the rule&lt;/h3&gt;

&lt;p&gt;Of course, this all works best if everyone on the project agrees to follow the convention.&lt;/p&gt;

&lt;div class=&quot;note oneline&quot;&gt;
&lt;p&gt;
But how do you ensure that the team sticks to the &lt;strong&gt;golden rule of pretty commits™&lt;/strong&gt;?
&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Well, you give your peers a gentle nudge at exactly the right moment: just when they’re about to make a commit. This is what Jeff Atwood calls &lt;a href=&quot;http://blog.codinghorror.com/the-just-in-time-theory/&quot;&gt;the “Just In Time” theory&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;You do it by showing them:&lt;/p&gt;

  &lt;ul&gt;
    &lt;li&gt;the minimum helpful reminder&lt;/li&gt;
    &lt;li&gt;at exactly the right time&lt;/li&gt;
  &lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;GitHub does this already, both on the Web:&lt;/p&gt;

&lt;p&gt;
    &lt;a href=&quot;https://megakemp.com/assets/the-importance-of-a-good-looking-history/github-commitwarning_hires.png&quot;&gt;
    &lt;img src=&quot;https://megakemp.com/assets/the-importance-of-a-good-looking-history/github-commitwarning.png&quot; alt=&quot;Commit message validation in the GitHub web UI&quot; title=&quot;Commit message validation in the GitHub web UI&quot; class=&quot;screenshot-noshadow-caption&quot; /&gt;
    &lt;/a&gt;
    &lt;span class=&quot;caption&quot;&gt;Commit message being validated in the GitHub web UI&lt;/span&gt;
&lt;/p&gt;

&lt;p&gt;and in its desktop clients:&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;https://megakemp.com/assets/the-importance-of-a-good-looking-history/githubformac-commitwarning.png&quot; alt=&quot;Commit message validation in GitHub for Mac&quot; title=&quot;Commit message validation in GitHub for Mac&quot; class=&quot;screenshot-caption&quot; /&gt;
    &lt;span class=&quot;caption&quot;&gt;Commit message being validated in GitHub for Mac...&lt;/span&gt;
&lt;/p&gt;

&lt;p&gt;
    &lt;img src=&quot;https://megakemp.com/assets/the-importance-of-a-good-looking-history/githubforwindows-commitwarning.png&quot; alt=&quot;Commit message validation in GitHub for Windows&quot; title=&quot;Commit message validation in GitHub for Windows&quot; class=&quot;screenshot-caption&quot; /&gt;
    &lt;span class=&quot;caption&quot;&gt;...and in GitHub for Windows&lt;/span&gt;
&lt;/p&gt;

&lt;p&gt;But what if you prefer to use Git from the command line, the way &lt;a href=&quot;/2013/01/22/grokking-git-by-seeing-it&quot;&gt;it should be&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;Easy. You write a shell script that gets triggered by &lt;a href=&quot;http://git-scm.com/book/en/Customizing-Git-Git-Hooks&quot;&gt;Git’s client side hooks&lt;/a&gt; every time you’re about to do a commit. In that script, you make sure the message is formatted according to the rules.&lt;/p&gt;

&lt;p&gt;Here’s &lt;a href=&quot;https://gist.github.com/ecampidoglio/e380abe1c2556d05d302&quot;&gt;my version of it&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;#!/bin/sh&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# A hook script that checks the length of the commit message.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;#&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# Called by &quot;git commit&quot; with one argument, the name of the file&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# that has the commit message. The hook should exit with non-zero&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# status after issuing an appropriate message if it wants to stop the&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;# commit. The hook is allowed to edit the commit message file.&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;DEFAULT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\0&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;33[0m&quot;&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;YELLOW&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\0&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;33[1;33m&quot;&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;printWarning &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt;&amp;amp;2 &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;YELLOW&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$message&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;${&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;DEFAULT&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;printNewline &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;captureUserInput &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;c&quot;&gt;# Assigns stdin to the keyboard&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;exec&lt;/span&gt; &amp;lt; /dev/tty
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;confirm &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;question&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;
    &lt;span class=&quot;nb&quot;&gt;read&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$question&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; [y/n]&quot;&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;$&apos;&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s1&quot;&gt;&apos;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; 1 &lt;span class=&quot;nt&quot;&gt;-r&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nv&quot;&gt;messageFilePath&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;message&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;cat&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$messageFilePath&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;firstLine&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$message&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; | &lt;span class=&quot;nb&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-n&lt;/span&gt; 1p&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nv&quot;&gt;firstLineLength&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;printf&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;${#&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;firstLine&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;nb&quot;&gt;test&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$firstLineLength&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-lt&lt;/span&gt; 51 &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    printWarning &lt;span class=&quot;s2&quot;&gt;&quot;Tip: the first line of the commit message shouldn&apos;t be longer than 50 characters and yours was &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$firstLineLength&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;.&quot;&lt;/span&gt;
    captureUserInput
    confirm &lt;span class=&quot;s2&quot;&gt;&quot;Do you want to modify the message in your editor or just commit it?&quot;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$REPLY&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~ ^[Yy]&lt;span class=&quot;nv&quot;&gt;$ &lt;/span&gt;&lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
        &lt;span class=&quot;nv&quot;&gt;$EDITOR&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$messageFilePath&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;fi

    &lt;/span&gt;printNewline
    &lt;span class=&quot;nb&quot;&gt;exit &lt;/span&gt;0
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In order to use it in your local repo, you’ll have to manually copy the script file into the &lt;strong&gt;.git\hooks&lt;/strong&gt; directory and call it &lt;strong&gt;commit-msg&lt;/strong&gt;. Finally, you’ll have grant execute rights to the file in order to make it runnable:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cp &lt;/span&gt;commit-msg somerepo/.git/hooks
&lt;span class=&quot;nb&quot;&gt;chmod&lt;/span&gt; +x somerepo/.git/hooks/commit-msg
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;From that point forward, every time you attempt to create a commit that doesn’t follow the rules you’ll get a chance to do the right thing:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://megakemp.com/assets/the-importance-of-a-good-looking-history/commit-msg-in-action_hires.png&quot;&gt;
&lt;img src=&quot;https://megakemp.com/assets/the-importance-of-a-good-looking-history/commit-msg-in-action.png&quot; alt=&quot;The commit-msg shell script in action&quot; title=&quot;The commit-msg shell script in action&quot; class=&quot;screenshot&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you choose to press &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;y&lt;/code&gt;, the commit message will open up in your default text editor from which you can rewrite it properly. Pressing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;n&lt;/code&gt;, on the other hand, will override the rule altogether and commit the message as it is.&lt;/p&gt;

&lt;p&gt;Not that you’d ever want to do that.&lt;/p&gt;

&lt;p&gt;&lt;a id=&quot;downloads&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;note downloads&quot;&gt;
&lt;ul&gt;
  &lt;li id=&quot;github&quot;&gt;&lt;a href=&quot;https://gist.github.com/ecampidoglio/e380abe1c2556d05d302&quot;&gt;Source code for &lt;strong&gt;commit-msg&lt;/strong&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;

&lt;div class=&quot;note&quot;&gt;
&lt;p&gt;
&lt;i class=&quot;fa fa-play-circle-o fa-2x pull-left pull-left-three-lines&quot;&gt;&lt;/i&gt;
If you&apos;re interested in learning other techniques like the one described in this article, you should check out my &lt;a href=&quot;https://www.pluralsight.com/authors/enrico-campidoglio&quot;&gt;Pluralsight&lt;/a&gt; course &lt;a href=&quot;https://www.pluralsight.com/courses/git-tips-tricks&quot;&gt;Git Tips and Tricks&lt;/a&gt;.
&lt;/p&gt;
&lt;/div&gt;
</description>
        <pubDate>Thu, 14 Aug 2014 00:00:00 +0000</pubDate>
        <link>https://megakemp.com/2014/08/14/the-importance-of-a-good-looking-history/</link>
        <guid isPermaLink="true">https://megakemp.com/2014/08/14/the-importance-of-a-good-looking-history/</guid>
      </item>
    
      <item>
        <title>Leveraging the cloud for fun and games</title>
        <description>&lt;p&gt;&lt;a href=&quot;https://twitter.com/tretton37/status/436790174014791680&quot;&gt;Friday night, February 21, 2014&lt;/a&gt;. That’s when the &lt;a href=&quot;http://tretton37.com&quot;&gt;tretton37&lt;/a&gt; Counter-Strike: Global Offensive &lt;a href=&quot;http://www.urbandictionary.com/define.php?term=fragfest&quot;&gt;fragfest&lt;/a&gt; was bound to start. Avid gamers looking to share virtual blood together, were eager to join in from our offices in Lund and Stockholm. A few more would play over the Internet.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://megakemp.com/assets/leveraging-the-cloud-for-fun-and-games/counter-strike-global-offensive-by-griddark.png&quot; alt=&quot;CS:GO icon by griddark&quot; title=&quot;CS:GO icon by griddark&quot; class=&quot;article&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The time and place were set. Pizzas were ordered. Everything was ready to go. Except for one thing:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;We didn’t have a dedicated Counter-Strike server to host the game on.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Finding a spare machine to dedicate for that one night wasn’t an easy task, given our requirements:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;The host should be reachable from the Internet&lt;/li&gt;
  &lt;li&gt;The machine should have enough hardware to handle a CS:GO game with 15+ players&lt;/li&gt;
  &lt;li&gt;The machine should be able to scale up as more players join the game&lt;/li&gt;
  &lt;li&gt;The whole thing should be a breeze to setup&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For days I pondered my options when, suddenly, it hit me:&lt;/p&gt;

&lt;div class=&quot;note&quot;&gt;
&lt;p&gt;
&lt;i class=&quot;fa fa-lightbulb-o fa-2x pull-left&quot;&gt;&lt;/i&gt;
Where&apos;s the place to find commodity hardware that&apos;s available &lt;em&gt;for rent&lt;/em&gt;, is &lt;em&gt;on the Internet&lt;/em&gt; and &lt;em&gt;can scale&lt;/em&gt; at will?
&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;The cloud&lt;/strong&gt;, of course! This realization fell on my head like the proverbial apple from the tree.&lt;/p&gt;

&lt;h3 id=&quot;step-1-getting-a-machine-in-the-cloud&quot;&gt;Step 1: Getting a machine in the cloud&lt;/h3&gt;

&lt;p&gt;Valve puts out their &lt;a href=&quot;https://developer.valvesoftware.com/wiki/Source_Dedicated_Server&quot;&gt;Source Dedicated Server&lt;/a&gt; software both for Windows and Linux. The Windows version has a GUI and is generally what you’d call “user friendly”. The Linux version, on the other hand, is &lt;em&gt;lean &amp;amp; mean&lt;/em&gt; and is managed entirely from the command line. Programmers being programmers, I decided to go for the Linux version.&lt;/p&gt;

&lt;p&gt;Now, having established that I needed a Linux box, the next question was: which of the available clouds was I going to entrust with our gaming night? Since &lt;a href=&quot;http://tretton37.com&quot;&gt;tretton37&lt;/a&gt; is mainly a Microsoft shop, it felt natural to go for &lt;a href=&quot;http://azure.microsoft.com&quot;&gt;Microsoft Azure&lt;/a&gt;. However, I wasn’t holding any high hopes that they would allow me to install Linux on one of their virtual machines.&lt;/p&gt;

&lt;p&gt;As it turned out, I had to &lt;a href=&quot;http://english.stackexchange.com/questions/150159/origin-of-eat-my-hat&quot;&gt;eat my hat&lt;/a&gt; on that one. Azure does, in fact, offer &lt;a href=&quot;http://azure.microsoft.com/en-us/documentation/articles/virtual-machines-linux-tutorial&quot;&gt;pre-installed Linux virtual machines&lt;/a&gt; ready to go. To me, this is proof that the cloud division at Microsoft totally gets how things are supposed to work in the 21st century. Kudos to them.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://megakemp.com/assets/leveraging-the-cloud-for-fun-and-games/azure-create-vm.png&quot;&gt;
&lt;img src=&quot;https://megakemp.com/assets/leveraging-the-cloud-for-fun-and-games/azure-create-vm.png&quot; alt=&quot;Creating a Linux VM on Azure&quot; title=&quot;Creating a Linux VM on Azure&quot; class=&quot;screenshot&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After literally 2 minutes, I had an &lt;a href=&quot;http://www.ubuntu.com/server&quot;&gt;Ubuntu Server&lt;/a&gt; machine with root access via SSH running in the cloud.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://megakemp.com/assets/leveraging-the-cloud-for-fun-and-games/azure-create-vm-progress.png&quot; alt=&quot;Creating a Linux VM on Azure&quot; title=&quot;Creating a Linux VM on Azure&quot; class=&quot;screenshot&quot; /&gt;&lt;/p&gt;

&lt;p&gt;If I hadn’t already eaten my hat, I would take it off for Azure.&lt;/p&gt;

&lt;h3 id=&quot;step-2-installing-the-steam-console-client&quot;&gt;Step 2: Installing the Steam Console Client&lt;/h3&gt;

&lt;p&gt;Hosting a CS:GO server implies setting up a so called &lt;a href=&quot;https://developer.valvesoftware.com/wiki/Source_Dedicated_Server&quot;&gt;Source Dedicated Server&lt;/a&gt;, also known as &lt;strong&gt;SRCDS&lt;/strong&gt;. That’s Valve’s server software used to run all their games that are based on the &lt;a href=&quot;http://source.valvesoftware.com&quot;&gt;Source Engine&lt;/a&gt;. The list includes Half Life 2, Team Fortress, Counter-Strike and so on.&lt;/p&gt;

&lt;p&gt;A SRCDS is easily installed through the Steam Console Client, or &lt;a href=&quot;https://developer.valvesoftware.com/wiki/SteamCMD&quot;&gt;SteamCMD&lt;/a&gt;. The easiest way to get it on Linux, is to download it and unpack it from a &lt;a href=&quot;http://www.computerhope.com/jargon/t/tarball.htm&quot;&gt;tarball&lt;/a&gt;. But first things first.&lt;/p&gt;

&lt;p&gt;It’s probably a good idea to run the Source server with a dedicated user account that doesn’t have root privileges. So I went ahead and created a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;steam&lt;/code&gt; user, switched to it and headed to its home directory:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;adduser steam
su steam
&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ~
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Next, I needed to install a few libraries that SteamCMD depends on, like the &lt;a href=&quot;http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html&quot;&gt;GNU C compiler and its friends&lt;/a&gt;. That’s where I hit the first roadblock.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;steamcmd: error while loading shared libraries: libstdc++.so.6: cannot open shared object file: No such file or directory&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Uh? A quick search on the Internet revealed that SteamCMD &lt;a href=&quot;https://developer.valvesoftware.com/wiki/SteamCMD#32-bit_libraries_on_64-bit_Linux_systems&quot;&gt;doesn’t like to run on a 64-bit OS&lt;/a&gt;. In fact:&lt;/p&gt;

&lt;div class=&quot;note oneline&quot;&gt;
&lt;p&gt;
SteamCMD is a 32-bit binary, so it needs &lt;em&gt;32-bit libraries&lt;/em&gt;.
&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;On the other hand:&lt;/p&gt;

&lt;div class=&quot;note oneline&quot;&gt;
&lt;p&gt;
The prepackaged Linux VMs available in Azure come in &lt;em&gt;64 bit only&lt;/em&gt;.
&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;Ouch. Luckily, the issue was easily solved by installing the right version of &lt;a href=&quot;http://gcc.gnu.org/onlinedocs/gccint/Libgcc.html&quot;&gt;Libgcc&lt;/a&gt;:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;apt-get &lt;span class=&quot;nb&quot;&gt;install &lt;/span&gt;lib32gcc1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Finally, I was ready to download the SteamCMD binaries and unpack them:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;wget http://media.steampowered.com/installer/steamcmd_linux.tar.gz
&lt;span class=&quot;nb&quot;&gt;tar &lt;/span&gt;xzvf steamcmd_linux.tar.gz
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The client itself was kicked off by a Bash script:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nb&quot;&gt;cd&lt;/span&gt; ./steamcmd
./steamcmd.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That brought down the necessary updates to the client tools and started an interactive prompt from where I could install any of Valve’s Source games servers.&lt;/p&gt;

&lt;p&gt;At this point, I could have continued down the same route and install the &lt;strong&gt;CS:GO Dedicated Server&lt;/strong&gt; (CSGO DS) by using SteamCMD.&lt;/p&gt;

&lt;p&gt;However, a few intricate problems would be waiting further down the road. So, I decided to back out and find a better solution.&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;Steam&amp;gt; quit
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;step-3-installing-the-csgo-dedicated-server&quot;&gt;Step 3: Installing the CS:GO Dedicated Server&lt;/h3&gt;

&lt;p&gt;Remember that thing about SteamCMD being a 32-bit binary and the Linux VM on Azure being only available in 64-bit?&lt;/p&gt;

&lt;p&gt;Well, that turned out to be a bigger issue than I thought. Even after having successfully installed the CS:GO server, getting it to run became a nightmare. The server was constantly complaining about the wrong version of some obscure libraries. Files and directories were missing. Everything was a mess.&lt;/p&gt;

&lt;p&gt;Salvation came in the form of a meticulously crafted script, designed to take care of those nitty-gritty details for me.&lt;/p&gt;

&lt;div class=&quot;note&quot;&gt;
&lt;p&gt;
&lt;i class=&quot;fa fa-gears fa-2x pull-left&quot;&gt;&lt;/i&gt;
Thanks to &lt;a href=&quot;https://twitter.com/dangibbsuk&quot;&gt;Daniel Gibbs&lt;/a&gt;&apos; hard work, I could use his fabulous &lt;a href=&quot;https://gameservermanagers.com/lgsm/csgoserver/&quot;&gt;&lt;strong&gt;csgoserver script&lt;/strong&gt;&lt;/a&gt; to install, configure and, above all, manage our CS:GO Dedicated Server without pain.
&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;You can find a detailed description how to use the &lt;strong&gt;csgoserver&lt;/strong&gt; &lt;a href=&quot;https://gameservermanagers.com/lgsm/csgoserver/&quot;&gt;up on his site&lt;/a&gt;, so I’m just gonna report how I configured it to suit our deathmatch needs.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;https://megakemp.com/assets/leveraging-the-cloud-for-fun-and-games/csds-shell.png&quot; alt=&quot;The status of the CS:GO Dedicated server as reported by csgoserver&quot; title=&quot;The status of the CS:GO Dedicated server as reported by csgoserver&quot; class=&quot;screenshot&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;step-4-configuration&quot;&gt;Step 4: Configuration&lt;/h3&gt;

&lt;p&gt;The CS:GO server can be configured in a few different ways and it’s all done in the &lt;strong&gt;&lt;a href=&quot;https://developer.valvesoftware.com/wiki/Counter-Strike:_Global_Offensive_Dedicated_Servers#server.cfg&quot;&gt;server.cfg&lt;/a&gt;&lt;/strong&gt; configuration file. In it, you can set up things like the &lt;a href=&quot;http://en.wikipedia.org/wiki/Counter-Strike:_Global_Offensive#Game_modes&quot;&gt;game mode&lt;/a&gt; (Arms Race, Classic, Competitive to name a few) the maximum number of players and so on.&lt;/p&gt;

&lt;p&gt;Here’s how I configured it for the tretton37 deathmatch:&lt;/p&gt;

&lt;div class=&quot;language-bash highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;sv_password &lt;span class=&quot;s2&quot;&gt;&quot;secret&quot;&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;# Requires a password to join the server&lt;/span&gt;
sv_cheats 0 &lt;span class=&quot;c&quot;&gt;# Disables hacks and cheat codes&lt;/span&gt;
sv_lan 0 &lt;span class=&quot;c&quot;&gt;# Disables LAN mode&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h3 id=&quot;step-5-gold-plating&quot;&gt;Step 5: Gold plating&lt;/h3&gt;

&lt;p&gt;The final touch was to provide an appropriate &lt;a href=&quot;http://css.gamebanana.com/tuts/5484#Motd&quot;&gt;Message of the Day (or MOTD)&lt;/a&gt; for the occasion. That would be the screen that greets the players as they join the game, setting the right tone.&lt;/p&gt;

&lt;p&gt;Once again, the whole thing was done by simply editing a text file. In this case, the file contained some HTML markup and a few stylesheets and was located in &lt;em&gt;/home/steam/csgo/motd.txt&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Here’s how it looked like in action:&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://megakemp.com/assets/leveraging-the-cloud-for-fun-and-games/motd_hires.jpg&quot;&gt;
&lt;img src=&quot;https://megakemp.com/assets/leveraging-the-cloud-for-fun-and-games/motd.jpg&quot; alt=&quot;The tretton37 Message of the Day in action&quot; title=&quot;The tretton37 Message of the Day in action&quot; class=&quot;screenshot-noshadow-fullwidth&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&quot;step-6-deathmatch&quot;&gt;Step 6: Deathmatch!&lt;/h3&gt;

&lt;p&gt;This article is primarily meant as a reference on how to configure a dedicated CS:GO server on a Linux box hosted on Microsoft Azure. Nonetheless, I figured it would be interesting to follow up with some information on how the server itself held up during &lt;a href=&quot;https://twitter.com/tretton37/status/436917080739573760&quot;&gt;that glorious game night&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://megakemp.com/assets/leveraging-the-cloud-for-fun-and-games/stats_hires.png&quot;&gt;
&lt;img src=&quot;https://megakemp.com/assets/leveraging-the-cloud-for-fun-and-games/stats.png&quot; alt=&quot;The CS:GO Dedicated server stats while running on Azure during game night&quot; title=&quot;The CS:GO Dedicated server stats while running on Azure during game night&quot; class=&quot;screenshot-noshadow-fullwidth&quot; /&gt;
&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here’s a few stats taken both from the &lt;a href=&quot;https://manage.windowsazure.com&quot;&gt;Azure Dashboard&lt;/a&gt; as well as from the operating system itself. Note that the server was running on a &lt;strong&gt;Large VM&lt;/strong&gt; sporting a &lt;em&gt;quad core 1.6 GHz CPU&lt;/em&gt; and &lt;em&gt;7 GB&lt;/em&gt; of RAM:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;Number of simultaneous players: &lt;strong&gt;16&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Average CPU load: &lt;strong&gt;15 %&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Memory usage: &lt;strong&gt;2.8 GB&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;Total outbound network traffic served: &lt;strong&gt;1.18 GB&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In retrospect, that configuration was probably a little overkill for the job. A &lt;strong&gt;Medium VM&lt;/strong&gt; with a &lt;em&gt;dual 1.6 GHz CPU&lt;/em&gt; and &lt;em&gt;3.5 GB&lt;/em&gt; of RAM would have probably sufficed. But hey, elastic scaling is exactly what the cloud is for.&lt;/p&gt;

&lt;h3 id=&quot;one-final-thought&quot;&gt;One final thought&lt;/h3&gt;

&lt;p&gt;Oddly enough, this experience opened up my eyes to the &lt;strong&gt;great potential of cloud computing&lt;/strong&gt;.&lt;/p&gt;

&lt;div class=&quot;note&quot;&gt;
&lt;p&gt;
The CS:GO server was only intended to run for the duration of the event, which would last for a few hours. During that short period of time, I needed it to be &lt;em&gt;as fast and responsive as possible&lt;/em&gt;. Hence, I went &lt;em&gt;all out&lt;/em&gt; on the hardware.
&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;As soon as the game night was over, I immediately shut down the virtual machine. The total cost for borrowing that awesome hardware for a few hours? Literally &lt;a href=&quot;http://azure.microsoft.com/en-us/pricing/details/virtual-machines/#linux&quot;&gt;peanuts&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Amazing.&lt;/p&gt;
</description>
        <pubDate>Wed, 25 Jun 2014 00:00:00 +0000</pubDate>
        <link>https://megakemp.com/2014/06/25/leveraging-the-cloud-for-fun-and-games/</link>
        <guid isPermaLink="true">https://megakemp.com/2014/06/25/leveraging-the-cloud-for-fun-and-games/</guid>
      </item>
    
  </channel>
</rss>
