<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Michael Sanford</title>
    <description>The latest articles on DEV Community by Michael Sanford (@msanford).</description>
    <link>https://dev.to/msanford</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F298788%2F1dbf9409-2067-4d1f-82c2-1680bba1b8f6.jpg</url>
      <title>DEV Community: Michael Sanford</title>
      <link>https://dev.to/msanford</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/msanford"/>
    <language>en</language>
    <item>
      <title>Recover from a disconnected remote `do-release-upgrade` session</title>
      <dc:creator>Michael Sanford</dc:creator>
      <pubDate>Tue, 17 May 2022 00:39:15 +0000</pubDate>
      <link>https://dev.to/msanford/recover-from-a-disconnected-remote-do-release-upgrade-session-40na</link>
      <guid>https://dev.to/msanford/recover-from-a-disconnected-remote-do-release-upgrade-session-40na</guid>
      <description>&lt;h1&gt;
  
  
  New Ubuntu Release
&lt;/h1&gt;

&lt;p&gt;You log in over ssh and see this MOTD banner; woohoo new release!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;481 updates can be applied immediately.
To see these additional updates run: apt list &lt;span class="nt"&gt;--upgradable&lt;/span&gt;

New release &lt;span class="s1"&gt;'22.04 LTS'&lt;/span&gt; available.
Run &lt;span class="s1"&gt;'do-release-upgrade'&lt;/span&gt; to upgrade to it.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So you &lt;code&gt;do-release-upgrade&lt;/code&gt; - it starts, spawns a new &lt;a href="https://linux.die.net/man/1/screen"&gt;screen&lt;/a&gt; session, you accept the scary warnings, and you're off.&lt;/p&gt;

&lt;p&gt;Then, the client machine from which you were doing the update crashes (BSOD, kernel panic, what have you) and your session is lost.&lt;/p&gt;

&lt;h1&gt;
  
  
  Easy Recovery
&lt;/h1&gt;

&lt;p&gt;Since &lt;code&gt;do-release-upgrade&lt;/code&gt; spawned a screen session, you can simply reattach to it.&lt;/p&gt;

&lt;p&gt;When you log in to your server and you will likely find a pts session open for root. This is the upgrader.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ubuntu@pi:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;who
&lt;/span&gt;ubuntu   pts/0        2022-05-16 22:36 &lt;span class="o"&gt;(&lt;/span&gt;192.168.0.x&lt;span class="o"&gt;)&lt;/span&gt;
root     pts/1        2022-05-16 22:38 &lt;span class="o"&gt;(&lt;/span&gt;192.168.0.x:S.0&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Switching to root, you see there is an attached screen session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ubuntu@pi:~&lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;su
root@pi:/home/ubuntu# screen &lt;span class="nt"&gt;-ls&lt;/span&gt;
There is a screen on:
        3915.ubuntu-release-upgrade-screen-window       &lt;span class="o"&gt;(&lt;/span&gt;05/16/22 22:38:22&lt;span class="o"&gt;)&lt;/span&gt;     &lt;span class="o"&gt;(&lt;/span&gt;Attached&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Simply &lt;code&gt;screen -d -r&lt;/code&gt; and you can take over the screen session and continue the update / follow its progress.&lt;/p&gt;

</description>
      <category>ubuntu</category>
      <category>linux</category>
      <category>ssh</category>
    </item>
    <item>
      <title>Temporarily Suspend BitLocker for firmware updates with reboot</title>
      <dc:creator>Michael Sanford</dc:creator>
      <pubDate>Mon, 09 May 2022 06:04:09 +0000</pubDate>
      <link>https://dev.to/msanford/temporarily-suspend-bitlocker-for-firmware-updates-with-reboot-45bb</link>
      <guid>https://dev.to/msanford/temporarily-suspend-bitlocker-for-firmware-updates-with-reboot-45bb</guid>
      <description>&lt;h2&gt;
  
  
  Intel ME / Firmware on my Razer Blade Advanced
&lt;/h2&gt;

&lt;p&gt;I recently discovered I was out of date with my Razer Blade Advanced Intel ME firmware.&lt;/p&gt;

&lt;p&gt;However, the Razer Updater complains that I must "temporarily disable Bitlocker". However, suspending BitLocker from the Manage BitLocker Control Panel does not quell the warning.&lt;/p&gt;

&lt;p&gt;That's because you need to &lt;em&gt;boot the computer with BitLocker suspended&lt;/em&gt; and the GUI control panel does not allow you to do this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--89I2Sv6z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bvlnkontollcb5b1tztd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--89I2Sv6z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bvlnkontollcb5b1tztd.png" alt="Image description" width="352" height="209"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  PowerShell to the rescue!
&lt;/h2&gt;

&lt;p&gt;In an Administrative PowerShell console, run the &lt;a href="https://docs.microsoft.com/en-us/powershell/module/bitlocker/suspend-bitlocker?view=windowsserver2022-ps"&gt;&lt;code&gt;Suspend-BitLocker&lt;/code&gt;&lt;/a&gt; commandlet specifying that you want to automatically re-enable BitLocker after the &lt;em&gt;second&lt;/em&gt; reboot:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;Suspend-BitLocker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-RebootCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-MountPoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which, if successful, will show you something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="n"&gt;C:\Windows\System32&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Suspend-BitLocker&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-RebootCount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-MountPoint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C&lt;/span&gt;&lt;span class="w"&gt;

   &lt;/span&gt;&lt;span class="n"&gt;ComputerName:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;BLADE&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="n"&gt;VolumeType&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;Mount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;CapacityGB&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;VolumeStatus&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nx"&gt;Encryption&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;KeyProtector&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="nx"&gt;AutoUnlock&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Protection&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;Percentage&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="nx"&gt;Enabled&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;Status&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="o"&gt;----------&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;-----&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;----------&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;------------&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="o"&gt;----------&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;------------&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="o"&gt;----------&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;----------&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;OperatingSystem&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;C:&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;460.71&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;FullyEncrypted&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="nx"&gt;100&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Tpm&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;RecoveryPassword&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="n"&gt;Off&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Next Steps
&lt;/h2&gt;

&lt;p&gt;Reboot your machine.&lt;/p&gt;

&lt;p&gt;Run your firmware updater.&lt;/p&gt;

&lt;p&gt;Reboot (firmware updater will probably do this for you).&lt;/p&gt;

&lt;p&gt;Voilà - updated Intel ME and BitLocker is automatically re-enabled.&lt;/p&gt;

</description>
      <category>uefi</category>
      <category>bitlocker</category>
      <category>secureboot</category>
      <category>tpm</category>
    </item>
    <item>
      <title>How to get Kali tools and Snap on a Chromebook</title>
      <dc:creator>Michael Sanford</dc:creator>
      <pubDate>Thu, 10 Mar 2022 15:34:24 +0000</pubDate>
      <link>https://dev.to/msanford/how-to-get-kali-tools-and-snap-on-a-chromebook-1kpi</link>
      <guid>https://dev.to/msanford/how-to-get-kali-tools-and-snap-on-a-chromebook-1kpi</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Google has shipped (let's call it reasonable) support for Linux inside a container - &lt;a href="https://support.google.com/chromebook/answer/9145439" rel="noopener noreferrer"&gt;official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I'll walk through how to set up Linux, add the &lt;a href="https://www.kali.org/docs/general-use/kali-linux-sources-list-repositories/" rel="noopener noreferrer"&gt;Kali aptitude repo&lt;/a&gt; as well as &lt;a href="https://snapcraft.io/store" rel="noopener noreferrer"&gt;Snap&lt;/a&gt;. This will get you up and running with your favourite tools.&lt;/p&gt;

&lt;p&gt;You will &lt;strong&gt;not&lt;/strong&gt; have a Kali desktop UI at the end of this tutorial, just access to the CLI tools, and Snap-based UI applications.&lt;/p&gt;

&lt;h1&gt;
  
  
  Enable Linux
&lt;/h1&gt;

&lt;h2&gt;
  
  
  Installing
&lt;/h2&gt;

&lt;p&gt;Hit Search and type "Terminal".&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70orqz1hyvcfj76cr4r5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F70orqz1hyvcfj76cr4r5.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This will bring up the "Set up linux development environment" wizard, which is also accessible through Settings.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnaavl7c1yh37beusaqv5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnaavl7c1yh37beusaqv5.png" alt="Image description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Choose a username.&lt;/p&gt;

&lt;p&gt;You can safely go with the recommended size of 10 GB, which can be easily resized later if you need more - or less - space.&lt;/p&gt;

&lt;p&gt;Hit Next and wait a couple of minutes.&lt;/p&gt;

&lt;p&gt;This will prepare a Debian Buster system in a virtualized container.&lt;/p&gt;

&lt;p&gt;It will then open the Terminal app. Right-click it and Pin it to your taskbar for easy access, which you'll need later.&lt;/p&gt;

&lt;h2&gt;
  
  
  Customising your System
&lt;/h2&gt;

&lt;p&gt;If you don't like the default hostname "penguin" you can change it. My Chromebook is silver in colour, and I'm French-speaking, so I decided to call mine "argent".&lt;/p&gt;

&lt;p&gt;Modify the &lt;code&gt;/etc/hostname&lt;/code&gt; file, replacing &lt;code&gt;penguin&lt;/code&gt; with your preferred hostname.&lt;/p&gt;

&lt;p&gt;Then, modify the first line of &lt;code&gt;/etc/hosts&lt;/code&gt; to match, and leave the rest as they are. In my case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;127.0.1.1       argent
127.0.0.1       localhost
::1             localhost ip6-localhost ip6-loopback
ff02::1         ip6-allnodes
ff02::2         ip6-allrouters
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, instead of rebooting, right-click the Terminal in the taskbar and choose &lt;code&gt;Shut down Linux&lt;/code&gt;. Then again to start it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;shutdown&lt;/code&gt; and &lt;code&gt;reboot&lt;/code&gt; do not work as expected in this Linux subsystem; don't use them.&lt;/p&gt;

&lt;h1&gt;
  
  
  Adding Kali Aptitude Repos
&lt;/h1&gt;

&lt;p&gt;Next, we'll add the &lt;a href="https://www.kali.org/docs/general-use/kali-linux-sources-list-repositories/" rel="noopener noreferrer"&gt;Kali apt repos&lt;/a&gt; and the public GPG key:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"deb http://http.kali.org/kali kali-rolling main contrib non-free"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/apt/sources.list.d/kali.list

wget &lt;span class="nt"&gt;-q&lt;/span&gt; &lt;span class="nt"&gt;-O&lt;/span&gt; - https://archive.kali.org/archive-key.asc | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; /etc/apt/trusted.gpg.d/kali-rolling-repo.asc
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;u&gt;Note&lt;/u&gt;: You may see references elsewhere to &lt;code&gt;apt-key add&lt;/code&gt;. This feature was deprecated yesterday, the above method is preferred.&lt;/p&gt;

&lt;p&gt;Update your local aptitude cache:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update

Get:1 http://kali.download/kali kali-rolling InRelease &lt;span class="o"&gt;[&lt;/span&gt;30.6 kB]
Get:2 http://kali.download/kali kali-rolling/main amd64 Packages &lt;span class="o"&gt;[&lt;/span&gt;18.0 MB]                  
Ign:3 https://storage.googleapis.com/cros-packages/99 bullseye InRelease
Hit:4 https://storage.googleapis.com/cros-packages/99 bullseye Release
Get:6 http://kali.download/kali kali-rolling/contrib amd64 Packages &lt;span class="o"&gt;[&lt;/span&gt;113 kB]
Get:7 http://kali.download/kali kali-rolling/non-free amd64 Packages &lt;span class="o"&gt;[&lt;/span&gt;194 kB]
Fetched 18.3 MB &lt;span class="k"&gt;in &lt;/span&gt;3s &lt;span class="o"&gt;(&lt;/span&gt;5,779 kB/s&lt;span class="o"&gt;)&lt;/span&gt;                       
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done

347 packages can be upgraded. Run &lt;span class="s1"&gt;'apt list --upgradable'&lt;/span&gt; to see them.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And update everything, clean and remove redundancies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt dist-upgrade &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt autoremove &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;sudo &lt;/span&gt;apt autoclean &lt;span class="nt"&gt;-y&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This took around 4 minutes on my N6000.&lt;/p&gt;

&lt;p&gt;Restart the Linux system by right-clicking Terminal and choosing &lt;code&gt;Shut down Linux&lt;/code&gt;. Click to start it again.&lt;/p&gt;

&lt;h1&gt;
  
  
  Snap
&lt;/h1&gt;

&lt;h2&gt;
  
  
  What is &lt;a href="https://snapcraft.io/" rel="noopener noreferrer"&gt;Snap&lt;/a&gt;?
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Snaps are app packages for desktop, cloud and IoT that are easy to install, secure, cross‐platform and dependency‐free. Snaps are discoverable and installable from the Snap Store.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can snap-in lots of great applications with a single command, like &lt;a href="https://snapcraft.io/publisher/jetbrains" rel="noopener noreferrer"&gt;JetBrains IDEs&lt;/a&gt;, &lt;a href="https://snapcraft.io/code" rel="noopener noreferrer"&gt;VS Code&lt;/a&gt;, &lt;a href="https://snapcraft.io/firefox" rel="noopener noreferrer"&gt;Firefox&lt;/a&gt;, &lt;a href="https://snapcraft.io/libreoffice" rel="noopener noreferrer"&gt;LibreOffice&lt;/a&gt;, and heck, even &lt;a href="https://snapcraft.io/powershell" rel="noopener noreferrer"&gt;PowerShell&lt;/a&gt;!&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing Snap
&lt;/h2&gt;

&lt;p&gt;You need to install a few dependencies, notably the &lt;a href="https://github.com/plougher/squashfs-tools" rel="noopener noreferrer"&gt;SquashFS&lt;/a&gt; and &lt;a href="https://github.com/libfuse/libfuse" rel="noopener noreferrer"&gt;FUSE&lt;/a&gt;, and Snap itself:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;apt &lt;span class="nb"&gt;install &lt;/span&gt;libsquashfuse0 squashfuse fuse snapd
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you try to install Snap without Fuse, you'll get this error:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;error: system does not fully support snapd: cannot mount squashfs image using "squashfs": mount:&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;By default &lt;code&gt;snapd&lt;/code&gt; will not start automatically when the Linux system is restarted; trying to run &lt;code&gt;snap&lt;/code&gt; will fail with the following error:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;error: cannot communicate with server: Post &lt;a href="http://localhost/v2/snaps/hello-world:" rel="noopener noreferrer"&gt;http://localhost/v2/snaps/hello-world:&lt;/a&gt; dial unix /run/snapd.socket: connect: no such file or directory&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;em&gt;permanent&lt;/em&gt; fix is to enable the service at startup:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;sudo &lt;/span&gt;systemctl &lt;span class="nb"&gt;enable&lt;/span&gt; &lt;span class="nt"&gt;--now&lt;/span&gt; snapd.apparmor
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Installing Snaps
&lt;/h2&gt;

&lt;p&gt;Find some snaps from &lt;a href="https://snapcraft.io/store" rel="noopener noreferrer"&gt;https://snapcraft.io/store&lt;/a&gt; and follow the instructions to install them.&lt;/p&gt;

&lt;h2&gt;
  
  
  Running Snaps
&lt;/h2&gt;

&lt;p&gt;To run the snap for VS Code, for example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;snap run code
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the first time you run a snap it may take a long time to initialize. Subsequent runs will be quick.&lt;/p&gt;

&lt;h1&gt;
  
  
  SSH Keys
&lt;/h1&gt;

&lt;p&gt;Might as well generate an SSH key while we're at it. ECDSA with key size of 521 bits is the &lt;a href="https://www.ssh.com/academy/ssh/keygen" rel="noopener noreferrer"&gt;currently-recommended standard&lt;/a&gt; but be warned it is not widely adopted:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;ssh-keygen &lt;span class="nt"&gt;-t&lt;/span&gt; ecdsa &lt;span class="nt"&gt;-b&lt;/span&gt; 521
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hat-tips:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://linuxconfig.org/gui-software-installers-for-kali-linux" rel="noopener noreferrer"&gt;https://linuxconfig.org/gui-software-installers-for-kali-linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://forums.kali.org/showthread.php?18079-Public-key-error" rel="noopener noreferrer"&gt;https://forums.kali.org/showthread.php?18079-Public-key-error&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://medium.com/@jeffrey.cardillo/using-intellij-and-other-linux-apps-on-your-chromebook-51fd7fadb9db" rel="noopener noreferrer"&gt;https://medium.com/@jeffrey.cardillo/using-intellij-and-other-linux-apps-on-your-chromebook-51fd7fadb9db&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>chromebook</category>
      <category>kali</category>
      <category>snap</category>
      <category>linux</category>
    </item>
    <item>
      <title>Kali VPN Tweaks for TryHackMe</title>
      <dc:creator>Michael Sanford</dc:creator>
      <pubDate>Thu, 23 Dec 2021 16:27:25 +0000</pubDate>
      <link>https://dev.to/msanford/kali-vpn-tweaks-for-tryhackme-4k4m</link>
      <guid>https://dev.to/msanford/kali-vpn-tweaks-for-tryhackme-4k4m</guid>
      <description>&lt;p&gt;I recently &lt;a href="https://tryhackme.com/p/unit.vector"&gt;signed up for TryHackMe&lt;/a&gt;, a CTF-style online platform for learning cyber security, using hands-on exercises and labs. I prefer to use my own tooling (&lt;a href="//kali.org/"&gt;Kali&lt;/a&gt;) in a local virtual machine rather than the browser-based Attack Box. This requires an OpenVPN tunnel connection.&lt;/p&gt;

&lt;p&gt;I discovered that while you can use Kali's default VPN client, you need to make a few configuration changes once you import your personalized &lt;code&gt;.ovpn&lt;/code&gt; configuration file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This assumes you have configured your LAN to use a private IP range of &lt;code&gt;192.168.0.0/16&lt;/code&gt; which virtually all SoHo routers do. (If you've reconfigured your router to address in &lt;code&gt;10.0.0.0/8&lt;/code&gt; you probably don't need this guide.)&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 1 - Download &amp;amp; Import your Configuration File
&lt;/h1&gt;

&lt;p&gt;Click the Network Connections menu in the quick launch bar (top right), choose VPN Connections &amp;gt; New, choose Import A Saved VPN Confiruation... and provide your &lt;code&gt;&amp;lt;tryhackme-username&amp;gt;.ovpn&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3Lh92Tn0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hve603oydhgycbwa0ybl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3Lh92Tn0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hve603oydhgycbwa0ybl.png" alt="Picture of described GUI" width="593" height="281"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 2 - Tweak Routes
&lt;/h1&gt;

&lt;p&gt;Open the configuration's settings and choose the &lt;code&gt;IPv4 Settings&lt;/code&gt; Tab, and click &lt;code&gt;Routes...&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Check off &lt;code&gt;Use this connection only for resources on its network&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--heEIzMa9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o50yl5mhi1uevsielnbk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--heEIzMa9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/o50yl5mhi1uevsielnbk.png" alt="Picture of described GUI" width="460" height="286"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Without this, &lt;em&gt;all&lt;/em&gt; traffic will pass over the VPN tunnel, which has the negative side-effect of blocking anything that isn't served from the TryHackMe &lt;code&gt;10.0.0.0/8&lt;/code&gt; network.&lt;/p&gt;

&lt;h1&gt;
  
  
  Step 3 - Set tool scope
&lt;/h1&gt;

&lt;p&gt;You could additionally set scope of tools like BurpSuite to TryHackMe's IP range:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--x-AzmN1e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n2lthqkdsbkm5flgk5n6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--x-AzmN1e--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/n2lthqkdsbkm5flgk5n6.png" alt="BurpSuite &amp;gt; Target &amp;gt; Scope &amp;gt; Use advanced scope control" width="746" height="382"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>cybersecurity</category>
      <category>tutorial</category>
      <category>beginners</category>
      <category>kali</category>
    </item>
    <item>
      <title>Clean up Github Actions Workflow Runs in PowerShell</title>
      <dc:creator>Michael Sanford</dc:creator>
      <pubDate>Wed, 13 Oct 2021 15:47:01 +0000</pubDate>
      <link>https://dev.to/msanford/clean-up-github-actions-workflow-runs-in-powershell-3pao</link>
      <guid>https://dev.to/msanford/clean-up-github-actions-workflow-runs-in-powershell-3pao</guid>
      <description>&lt;p&gt;Eager to set up all the CI bells-and-whistles, I went to test out Github Actions Workflows in a small, simple Python project.&lt;/p&gt;

&lt;p&gt;I had two peculiarities with the project I was testing it with, though:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;It's a serial modem adapter (yes, &lt;a href="https://www.youtube.com/watch?v=ckc6XSSh52w"&gt;this kind&lt;/a&gt;) and I was using my git repo largely to version code and move it my Raspberry Pi.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;After every test, I'd realize I needed another serial setting. Rather than polluting my commit history with broken intermediary projects, I would just &lt;a href="https://dev.to/msanford/rebasing-to-avoid-merge-commits-2k0k"&gt;amend the same commit&lt;/a&gt; and force push over and over. That rendered past Workflow runs uninformative garbage because they no longer referred to commits in the repo's history.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now that I'm back in a more Operations-focused role, I'm keen to use PowerShell where I can, so I whipped up this "one-liner":&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;p&gt;based on the bash-isms found herein (I also posted this as an answer there):&lt;/p&gt;


&lt;div class="ltag__stackexchange--container"&gt;
  &lt;div class="ltag__stackexchange--title-container"&gt;
    
      &lt;div class="ltag__stackexchange--title"&gt;
        &lt;h1&gt;
          &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7Gn-iPj_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/stackoverflow-logo-b42691ae545e4810b105ee957979a853a696085e67e43ee14c5699cf3e890fb4.svg" alt=""&gt;
            &lt;a href="https://stackoverflow.com/questions/57927115/anyone-know-a-way-to-delete-a-workflow-from-github-actions" rel="noopener noreferrer"&gt;
              Anyone know a way to delete a workflow from GitHub Actions?
            &lt;/a&gt;
        &lt;/h1&gt;
        &lt;div class="ltag__stackexchange--post-metadata"&gt;
          &lt;span&gt;Sep 13 '19&lt;/span&gt;
            &lt;span&gt;Comments: 1&lt;/span&gt;
            &lt;span&gt;Answers: 19&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;a class="ltag__stackexchange--score-container" href="https://stackoverflow.com/questions/57927115/anyone-know-a-way-to-delete-a-workflow-from-github-actions" rel="noopener noreferrer"&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Y9mJpuJP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/stackexchange-arrow-up-eff2e2849e67d156181d258e38802c0b57fa011f74164a7f97675ca3b6ab756b.svg" alt=""&gt;
        &lt;div class="ltag__stackexchange--score-number"&gt;
          80
        &lt;/div&gt;
        &lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wif5Zq3z--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev.to/assets/stackexchange-arrow-down-4349fac0dd932d284fab7e4dd9846f19a3710558efde0d2dfd05897f3eeb9aba.svg" alt=""&gt;
      &lt;/a&gt;
    
  &lt;/div&gt;
  &lt;div class="ltag__stackexchange--body"&gt;
    
&lt;p&gt;I create a couple workflows in the &lt;code&gt;.github/workflows&lt;/code&gt; folder of my repository to experiment with GitHub Actions. I have since learned quite a bit and deleted said "experimental" workflows from my repo. After deleting the "experimental" workflow yaml files and committing the deletions, when I go to the Actions tab…&lt;/p&gt;
    
  &lt;/div&gt;
  &lt;div class="ltag__stackexchange--btn--container"&gt;
    
      &lt;a href="https://stackoverflow.com/questions/57927115/anyone-know-a-way-to-delete-a-workflow-from-github-actions" rel="noopener noreferrer"&gt;Open Full Question&lt;/a&gt;
    
  &lt;/div&gt;
&lt;/div&gt;


</description>
      <category>powershell</category>
      <category>github</category>
      <category>operations</category>
      <category>ci</category>
    </item>
    <item>
      <title>Finding breaking commits with git bisect</title>
      <dc:creator>Michael Sanford</dc:creator>
      <pubDate>Fri, 21 Jul 2017 17:18:44 +0000</pubDate>
      <link>https://dev.to/msanford/finding-breaking-commits-with-git-bisect-2300</link>
      <guid>https://dev.to/msanford/finding-breaking-commits-with-git-bisect-2300</guid>
      <description>&lt;h3&gt;
  
  
  Step-by-step guide
&lt;/h3&gt;

&lt;p&gt;The workflow goes like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;git log&lt;/strong&gt; to examine the commit history&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;git checkout&lt;/strong&gt; &amp;lt;a confirmed working commit&amp;gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;git checkout&lt;/strong&gt; &amp;lt;a confirmed broken commit; often HEAD&amp;gt;&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;git bisect&lt;/strong&gt; to find the breaking commit&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;To “bisect” means to cut in two. Git bisect does just that: you pick two commits, one that is known to be bad, and one that is known to be good, and git will check out revisions about half-way between both, and ask you to check each one and mark is as good or bad until you find the specific commit that introduced a bug.&lt;/p&gt;

&lt;p&gt;In a small project with a handful of developers, it may be trivially easy to identify breaking commits. But when projects grow in complexity and large blocks are committed in rapid succession, by a large, distributed team, tools like this become useful.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Important note:&lt;/strong&gt; &lt;em&gt;Git bisect&lt;/em&gt; exists because people are human and make mistakes; this is simply a walkthrough of a tool used to help find those mistakes that slip through despite our best efforts.&lt;/p&gt;

&lt;h3&gt;
  
  
  Working Example
&lt;/h3&gt;

&lt;p&gt;We will take a real-world example and walk through resolving the issue.&lt;/p&gt;

&lt;h3&gt;
  
  
  Noticing the problem
&lt;/h3&gt;

&lt;p&gt;A developer attempts to start the exostore and is greeted with this message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;14:29:24.78 \&amp;lt;trace\&amp;gt; [init][db]start createDataPool (in dblink.js:63)
14:29:24.80 \&amp;lt;trace\&amp;gt; [kakyo] Init DB OK (in dblink.js:59)

/vagrant/exostore-v4/exo\_lib/data/modules/dbapi\_admin\_device.js:66
).error(errorHandler ).then(funcation(result){
^
SyntaxError: Unexpected token {
at Module.\_compile (module.js:439:25)
at Object.Module.\_extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module.\_load (module.js:312:12)
at Module.require (module.js:364:17)
at require (module.js:380:17)
at Object.\&amp;lt;anonymous\&amp;gt; (/vagrant/exostore-v4/exo\_lib/data/dbmodules.js:9:23)
at Module.\_compile (module.js:456:26)
at Object.Module.\_extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
**error: Forever detected script exited with code: 8**
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While it is immediately obvious where the problem lies (i.e., dbapi_admin_device.js:66), it would be imprudent to simply run in and fix it. We need to examine the commit history and see if other things were changed as part of a batch that may affect other components.&lt;/p&gt;

&lt;h3&gt;
  
  
  Examining the Log
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git log oneline decorate

**759c997** ( **HEAD** , **origin/master** , **origin/HEAD** , **msanford** , **master** ) Globally refactor SUCCESSED \&amp;gt; SUCCESS; MSGID \&amp;gt; MSG\_ID; datas \&amp;gt; data.

**47a77a2** [EXO-135](https://exouinc.atlassian.net/browse/EXO-135) #resolve Add admin user account creation API, update stored procedure for error handling, scaffold unit test.

**19371ec** 1. Added a constraint in admin db tbe\_domain. 2. Added two test helper functions. 3. Added a insertion helper function. 4. Added a unit test case set for db\_store\_app model class.

**d38a884** add device related implementations

**9f05de2** Remove old fixture generation script

**a1f5ff3** Refactor comment style in db/\*.sql

**ea1b955** Manually regenerate vagrant-v4 fixtures

**3248f20** Updated translation support — Added data table sample — Removed unused stuff — Replaced message APIs routes by correct paths in `app.js`

**d7f3076** add get msg count apis
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here we see a series of commits, any one of which have the potential to break the system.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Rebasing is a time machine&lt;/p&gt;

&lt;p&gt;While it might be tempting to assume the last commit in the history introduced the breaking change if you just saw it break for the first time, that is not necessarily the case!&lt;/p&gt;

&lt;p&gt;Because we work in a private branch, rebase onto master, and then rebase master onto our working branch before pushing, commits made &lt;em&gt;later in time&lt;/em&gt; may &lt;em&gt;appear earlier in the work history&lt;/em&gt; because they were rebased.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Finding a good state
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout 9f05de2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Store starts correctly!&lt;/p&gt;

&lt;h3&gt;
  
  
  Find a bad state
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git checkout master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This checks out origin/master HEAD (which at this time is 759c997). Store breaks!&lt;/p&gt;

&lt;h3&gt;
  
  
  Finding the breaking commit
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Set up the initial state
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git bisect start

git bisect good 9f05de2
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Begin bisecting by marking a bad commit
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git bisect bad 759c997
Bisecting: 1 revision left to test after this (roughly 1 step)
[19371eca935657ebaecb0a4e9879ce295a91f5a2] 1. Added a constraint in admin db tbe\_domain. 2. Added two test helper functions. 3. Added a insertion helper function. 4. Added a unit test case set for db\_store\_app model class.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Found bad commit, continue
&lt;/h4&gt;

&lt;p&gt;At this point, git has checked out a specific revision (commit) &lt;em&gt;about halfway between good and bad&lt;/em&gt;. After testing it, we see that the store fails to load, so we mark this as a bad commit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git bisect bad

Bisecting: 0 revisions left to test after this (roughly 0 steps)
[d38a88471524c07f3762921a030887e29460dc3e] add device related implementations
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;0 revisions to test after this means we have to test this revision, too. We’re getting close! But the store fails to start in this scenario as well. So, we mark this commit as bad.&lt;/p&gt;

&lt;h4&gt;
  
  
  Found another bad commit, continue
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git bisect bad

**d38a88471524c07f3762921a030887e29460dc3e is the first bad commit**
commit d38a88471524c07f3762921a030887e29460dc3e
Author: [REDACTED]
Date: Thu Aug 28 09:16:14 2014 -0700

add device related implementations

:040000 040000 53c2f55597509733e427063ff7c8c8d9f6d5efeb aa6a09dd673be0a7d73ccf36f25fc6078ee3ae5d M exo\_lib
:040000 040000 f1d3b03ff9ffd3a56fa16a7f698c76bbc7883dd0 a75004b9fe513ec4edd27c12d5d7ae25177c3134 M routes
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Found it!
&lt;/h3&gt;

&lt;p&gt;The bisection is complete, we have identified the bad commit, so we can reset our working copy to its previous state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git bisect reset

Previous HEAD position was d38a884… add device related implementations
Switched to branch ‘master’
Your branch is up-to-date with ‘origin/master’
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Fixing it
&lt;/h3&gt;

&lt;p&gt;Now that you have found the commit that introduced the breaking change, you can take steps to remedy it, which may include:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Contacting the commit author directly,&lt;/li&gt;
&lt;li&gt;Correcting it yourself and pushing an urgent fix commit.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this case, finding the commit was useful because it surfaced not only the obvious, known issue as well as another, related issue in the same commit.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Bisection_method" rel="noopener noreferrer"&gt;Bisection&lt;/a&gt; is usually the term given to searching over a continuous value function, whereas git commits are obviously discrete elements, properly making git-bisect a &lt;a href="https://en.wikipedia.org/wiki/Binary_search_algorithm" rel="noopener noreferrer"&gt;binary search&lt;/a&gt; algorithm.&lt;/p&gt;

&lt;p&gt;Binary search runs in worst case &lt;em&gt;O(log n)&lt;/em&gt; time and &lt;em&gt;O(1)&lt;/em&gt; space.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F470%2F1%2A-9MWPstfy1BgClAs3JJTAw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F470%2F1%2A-9MWPstfy1BgClAs3JJTAw.png"&gt;&lt;/a&gt;Binary search method for the value 7 starting at 14; &lt;a href="https://en.wikipedia.org/wiki/Binary_search_algorithm" rel="noopener noreferrer"&gt;WikiMedia Commons&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Replace 14 and 6 with “known good” and “known bad” commits, and it’s essentially the same process.&lt;/p&gt;

</description>
      <category>softwaredevelopment</category>
      <category>tutorial</category>
      <category>terminal</category>
      <category>git</category>
    </item>
    <item>
      <title>Popups in Print Media 2.0</title>
      <dc:creator>Michael Sanford</dc:creator>
      <pubDate>Wed, 08 Jul 2015 02:42:41 +0000</pubDate>
      <link>https://dev.to/msanford/popups-in-print-media-2-0-32c2</link>
      <guid>https://dev.to/msanford/popups-in-print-media-2-0-32c2</guid>
      <description>&lt;p&gt;Well, we’ve come full circle. This morning, I took a &lt;a href="http://journalmetro.com/"&gt;Journal métro&lt;/a&gt; (while exiting the &lt;a href="http://stm.info/"&gt;Métro&lt;/a&gt;) to discover that an enterprising marketing guy had stuck a popup on my print media.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V1Z5RKHt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/630/0%2Ac2j8Q3jfOLyQMnNy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V1Z5RKHt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/630/0%2Ac2j8Q3jfOLyQMnNy.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’m a fan of print media. I prefer to read &lt;a href="http://www.monde-diplomatique.fr/"&gt;Le Monde Diplomatique&lt;/a&gt; or &lt;a href="http://monocle.com/"&gt;Monocle&lt;/a&gt; in their print forms (even considering tablets). I also think that traditional media can learn from new media. But, seriously, let popups and popovers die already.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="http://michaelsanford.com/popups-in-print-media-2-0/"&gt;&lt;em&gt;michaelsanford.com&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on January 15, 2013.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Compiling xslcache 0.7.1 for PHP 5.4</title>
      <dc:creator>Michael Sanford</dc:creator>
      <pubDate>Fri, 22 May 2015 19:46:09 +0000</pubDate>
      <link>https://dev.to/msanford/compiling-xslcache-0-7-1-for-php-5-4-2l7</link>
      <guid>https://dev.to/msanford/compiling-xslcache-0-7-1-for-php-5-4-2l7</guid>
      <description>&lt;p&gt;We make heavy use of xslt at work (parsing xml data generated by php controllers), so the &lt;a href="http://pecl.php.net/package/xslcache/0.7.1"&gt;xslcache pecl module&lt;/a&gt; is pretty fundamental to our infrastructure. Of course, if you are using PHP 5.4 or above, like many pecl modules, &lt;a href="https://bugs.php.net/bug.php?id=62856"&gt;it breaks&lt;/a&gt;. Here’s how to get it to work.&lt;/p&gt;

&lt;p&gt;Currently, trying sudo pecl install xslcache-beta with PHP &amp;gt;= 5.4 throws the following error at make:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/tmp/pear/temp/xslcache/php\_xsl.c: In function 'xslcache\_objects\_new': /tmp/pear/temp/xslcache/php\_xsl.c:211:52: error: 'zend\_class\_entry' has no member named 'default\_properties' make: \*\*\* [php\_xsl.lo] Error 1 ERROR: `make' failed
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Download xslcache
&lt;/h3&gt;

&lt;p&gt;Download the original source from the pecl svn repository, the 5.4 patch, and patch it manually:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;svn checkout [http://svn.php.net/repository/pecl/xslcache/trunk](http://svn.php.net/repository/pecl/xslcache/trunk) xslcache cd xslcache wget -O php\_xsl.c.patch 'https://bugs.php.net/patch-display.php?bug\_id=62856&amp;amp;patch=xslcache-php5.4-compat&amp;amp;revision=1362641549&amp;amp;download=1' patch \&amp;lt; php\_xsl.c.patch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Make and install
&lt;/h3&gt;

&lt;p&gt;This is a pretty straightforward make process for most linux software (you may need to adjust the location of xslcache.ini):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;phpize ./configure make make test sudo make install sudo nano /etc/php5/cgi/conf.d/xslcache.ini #add "extension=xslcache.so"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that if you make test the tenth may fail with the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;=================================================================== FAILED TEST SUMMARY 
------------------------------------------------------------------- Test 10: EXSLT Support [tests/xslt010.phpt] ===================================================================
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you’re using XSLT 2.0, you probably &lt;a href="http://stackoverflow.com/a/5899319/114900"&gt;don’t need&lt;/a&gt; to worry about it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Verify that xslcache is installed and enabled
&lt;/h3&gt;

&lt;p&gt;Since we’re already in the command line, let’s check there:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php -i | grep XSLCACHE
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hopefully, you will see the following line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;XSLCACHE =\&amp;gt; enabled
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Furthermore, you should be able to actually know it’s &lt;em&gt;doing its job&lt;/em&gt; because your benchmarks should improve.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="http://michaelsanford.com/compiling-xslcache-0-7-1-for-php-5-4/"&gt;&lt;em&gt;michaelsanford.com&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on March 22, 2013.&lt;/em&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Clean up and compact your VDI</title>
      <dc:creator>Michael Sanford</dc:creator>
      <pubDate>Fri, 22 May 2015 19:24:34 +0000</pubDate>
      <link>https://dev.to/msanford/clean-up-and-compact-your-vdi-4bml</link>
      <guid>https://dev.to/msanford/clean-up-and-compact-your-vdi-4bml</guid>
      <description>&lt;h3&gt;
  
  
  TL;DR
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Guest OS: sudo sfill -llvz /

Host OS: VBoxManage modifyhd --compact \&amp;lt;\_.vdi\&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Details
&lt;/h3&gt;

&lt;p&gt;My VirtualBox thin server had put on a few pounds over the months of guest OS database imports, static resource creation, temp file creation, log rotation, and a bunch of other stuff I don’t need to store indefinitely. Every time more sectors need to be called upon to store something in the guest, VirtualBox will grow the physical VDI image accordingly, up to the maximum size specified. However, when you delete files from the guest system, the VDI doesn’t shrink accordingly (and with good reason).&lt;/p&gt;

&lt;p&gt;If you have implemented a backup strategy — as I have with Time Machine — you probably don’t want to back up a 30 GB VDI file every single time a single bit changes (for example, when you boot the virtual machine). This is particularly true when you have deleted old databases, resources and logs, and the guest OS really only represents about 5 GB of data.&lt;/p&gt;

&lt;p&gt;VBoxManage modifyhd allows you to compact a physical VDI, but with &lt;em&gt;one important precondition&lt;/em&gt;, it only truncates &lt;em&gt;zeros&lt;/em&gt; in the guest from the VDI:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;With the — compact option, can be used to compact disk images, i.e. remove blocks that only contains zeros. This will shrink a dynamically allocated image again; it will reduce the &lt;em&gt;physical&lt;/em&gt; size of the image without affecting the logical size of the virtual disk. Compaction works both for base images and for diff images created as part of a snapshot.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So simply having deleted a file from your guest will not allow you to reclaim space. You have to zerofill the free space on guest OS’s volumes.&lt;/p&gt;

&lt;p&gt;In your Guest (in this case, Ubuntu Server 12.04.02 LTS)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo apt-get install secure-delete sudo sfill -llvz /
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The -ll option writes only one pass (instead of the default 38) and the -z option replaces the single pass of data from /dev/urandom with zeros, which is what VBoxManage is looking for.&lt;/p&gt;

&lt;p&gt;In your host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;VBoxManage modifyhd --compact \&amp;lt;virtual\_disk\_file.vdi\&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I shrunk mine from 25 GB to 5 GB in a single step. My SSD allowed me to zerofill about 20 GB in the guest and compact the VDI in less than 90 seconds.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Originally published at&lt;/em&gt; &lt;a href="http://michaelsanford.com/clean-up-and-compact-your-vdi/"&gt;&lt;em&gt;michaelsanford.com&lt;/em&gt;&lt;/a&gt; &lt;em&gt;on August 8, 2013.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>virtualbox</category>
    </item>
    <item>
      <title>Rebasing to avoid merge commits</title>
      <dc:creator>Michael Sanford</dc:creator>
      <pubDate>Fri, 15 Aug 2014 17:00:10 +0000</pubDate>
      <link>https://dev.to/msanford/rebasing-to-avoid-merge-commits-2k0k</link>
      <guid>https://dev.to/msanford/rebasing-to-avoid-merge-commits-2k0k</guid>
      <description>&lt;p&gt;Everyone likes to keep the source control history linear, preferring fast-forward merges to merge commits. It’s really not that hard. &lt;em&gt;Promise.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Git’s commit structure is a &lt;em&gt;linked list of snapshots&lt;/em&gt; whose commits point to one or several &lt;em&gt;ancestors&lt;/em&gt;. This means that you must “base” your work on a previous commit.&lt;/p&gt;

&lt;h3&gt;
  
  
  What’s a merge commit?
&lt;/h3&gt;

&lt;p&gt;Merge commits can be useful when merging topic/feature branches together to indicate, in the history, where branches were combined.&lt;/p&gt;

&lt;p&gt;When working on a single branch, however, they are ugly, unnecessary, clutter the history, and look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F280%2F1%2AjierxlydpVNF-LgiSh134w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F280%2F1%2AjierxlydpVNF-LgiSh134w.png"&gt;&lt;/a&gt;Here, I worked on master in two places,&lt;/p&gt;

&lt;p&gt;This is the result of doing work — not necessarily on the same file just in the &lt;em&gt;same branch&lt;/em&gt; — in two places at once. Here, &lt;em&gt;eada9ae&lt;/em&gt; and &lt;em&gt;eac49bb&lt;/em&gt; are both children of &lt;em&gt;7036724&lt;/em&gt;, but they contain different snapshots which were merged at 53ad270.&lt;/p&gt;

&lt;h3&gt;
  
  
  Rebasing for great success
&lt;/h3&gt;

&lt;p&gt;Let’s start with a history like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F509%2F1%2ADuATfls-IfdYIFQCi3hJ4g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F509%2F1%2ADuATfls-IfdYIFQCi3hJ4g.png"&gt;&lt;/a&gt;Nice, linear history (so far)&lt;/p&gt;

&lt;p&gt;Now, let’s work on the same file in two places at once (and also simulate a merge conflict). To do this, I’ll edit the file locally in the working copy, and I’ll edit it in the BitBucket editor (which gets committed and pushed immediately):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F566%2F1%2AycX1RUN6abhyBu0qoOKPKg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F566%2F1%2AycX1RUN6abhyBu0qoOKPKg.png"&gt;&lt;/a&gt;BitBucket edit appears in the history.&lt;/p&gt;

&lt;p&gt;Now, edit and commit the file locally:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;msanford@Tenjin:/tmp/rebase-example $ git commit -m “Fourth commit — working copy”
[master 25dd301] Fourth commit — working copy
 1 file changed, 1 insertion(+)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Our branches are now out of sync: HEAD in origin/master points to 4ff5d2 whereas it points to 25dd301 in the working copy:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;msanford@Tenjin:/tmp/rebase-example $ git log --oneline
25dd301 Fourth commit — working copy
e8a2bb8 Third commit — working copy
988eb03 Second commit — working copy
4168ee0 Initial commit — working copy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At this point, if you git push from the working copy, you’ll see this familiar message, suggesting that you &lt;em&gt;git pull&lt;/em&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;msanford@Tenjin:/tmp/rebase-example $ git push
To [git@bitbucket.org](mailto:git@bitbucket.org):michaelsanford/rebase-example.git
 ! [rejected] master -&amp;gt; master (fetch first)
error: failed to push some refs to ‘[git@bitbucket.org](mailto:git@bitbucket.org):michaelsanford/rebase-example.git’
hint: **Updates were rejected because the remote contains work that you do**
hint: **not have locally**. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., ‘ **git pull** …’) before pushing again.
hint: See the ‘Note about fast-forwards’ in ‘ **git push --help** ’ for details.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the hint also suggests consulting “the fast-forward section of the manpage” which, of course, nobody has ever done. It suggests a more elegant course of action.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;msanford@Tenjin:/tmp/rebase-example $ **git pull --rebase**
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From bitbucket.org:michaelsanford/rebase-example
 e8a2bb8..4ff45d2 master -&amp;gt; origin/master
**First, rewinding head to replay your work on top of it…**
Applying: Fourth commit — working copy
**Using index info to reconstruct a base tree…**
M README.md
Falling back to patching base and 3-way merge…
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
Failed to merge in the changes.
Patch failed at 0001 Fourth commit — working copy
The copy of the patch that failed is found in:
 /private/tmp/rebase-example/.git/rebase-apply/patch

When you have resolved this problem, run “git rebase —continue”.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Rebase succeeded (no error messages)? No merge conflicts? You can push right away!&lt;/p&gt;

&lt;h3&gt;
  
  
  Handling Merge Conflicts
&lt;/h3&gt;

&lt;p&gt;Oh no, a merge conflict in the file we were working on!&lt;/p&gt;

&lt;h4&gt;
  
  
  README.md:
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Edited locally in the working copy.
Second edit locally from the working copy.
Third commit locally from the working copy.
&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt;&amp;lt; HEAD
Fourth commit from BitBucket.
=======
Fourth commit locally from the working copy.
&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt;&amp;gt; Fourth commit — working copy
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No problem: we can edit the file in the working copy, resolve the conflict, and &lt;em&gt;rebase continue&lt;/em&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;msanford@Tenjin:/tmp/rebase-example $ vi README.md
msanford@Tenjin:/tmp/rebase-example $ git add README.md
msanford@Tenjin:/tmp/rebase-example $ git rebase —continue
Applying: Fourth commit — working copy

msanford@Tenjin:/tmp/rebase-example $ git status
On branch master
Your branch is ahead of ‘origin/master’ by 1 commit.
 (use “git push” to publish your local commits)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What happened?
&lt;/h3&gt;

&lt;p&gt;Git rebase has, as the name suggests, changed the &lt;em&gt;base&lt;/em&gt; of our working copy’s commit history to match origin/master’s base. Since both the local working copy and the remote have the &lt;em&gt;same base commit&lt;/em&gt; (after fixing the merge conflict) it has allowed us to &lt;em&gt;fast-forward&lt;/em&gt; our work as a patch on top of the remote’s commit and maintain a linear history.&lt;/p&gt;

&lt;p&gt;This results in a nice, straight line that contains &lt;em&gt;all of the work done in a semantically-sensible way&lt;/em&gt; (because the merged changes are topical):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F567%2F1%2ADQFoHYpM_4r4iRnXZv37HA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F567%2F1%2ADQFoHYpM_4r4iRnXZv37HA.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the first example (with the merge commit) if our working copy held the blue line with &lt;em&gt;eac49bb&lt;/em&gt;, &lt;em&gt;git pull rebase&lt;/em&gt; would pull &lt;em&gt;eada9ae&lt;/em&gt;, then create a patch and replay the work contained in &lt;em&gt;eac49bb&lt;/em&gt; on top of &lt;em&gt;that commit (_instead of using _7036724&lt;/em&gt; as the base_)_, &lt;a href="http://ariya.ofilabs.com/2013/09/fast-forward-git-merge.html" rel="noopener noreferrer"&gt;fast-forwarding&lt;/a&gt; it and preserving a linear topical history.&lt;/p&gt;

&lt;h3&gt;
  
  
  Teams
&lt;/h3&gt;

&lt;p&gt;In this example I have used only one developer, but that is not relevant: you can do this in teams exactly the same way!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
