<?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>Forem: Pauline Vos</title>
    <description>The latest articles on Forem by Pauline Vos (@paulinevos).</description>
    <link>https://forem.com/paulinevos</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%2F597312%2F08c8102c-5d9a-479f-aa91-2bb73da76843.jpg</url>
      <title>Forem: Pauline Vos</title>
      <link>https://forem.com/paulinevos</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/paulinevos"/>
    <language>en</language>
    <item>
      <title>Git Legit cheat sheet</title>
      <dc:creator>Pauline Vos</dc:creator>
      <pubDate>Wed, 12 Mar 2025 09:22:24 +0000</pubDate>
      <link>https://forem.com/paulinevos/git-legit-cheat-sheet-2gf0</link>
      <guid>https://forem.com/paulinevos/git-legit-cheat-sheet-2gf0</guid>
      <description>&lt;p&gt;&lt;strong&gt;This is a repost of my 2018 Git cheat sheet, due to getting rid of my personal blog :) Enjoy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I’ve given my talk about best practices in Git a few times now, and I’ve had several people come up to me asking if I’m going to upload the slides, or “what was that one Git command again?” I thought it might be a good idea to offer a cheat sheet based on the talk to refer them to in the future. Maybe throw in some handy resources.&lt;/p&gt;

&lt;p&gt;So here you go 🙂 There’s a lot more options to Git than this, but this is what I use daily to easily keep my commits atomic and my sanity in tact. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Here’s &lt;a href="https://dev.to/paulinevos/atomic-commits-will-help-you-git-legit-35i7"&gt;a quick recap &lt;/a&gt; of the talk. It explains atomic commits and why they’re a Good Thing™. You’ll need them for the below to help you&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Add changes to your last commit
&lt;/h4&gt;

&lt;p&gt;Stage your changes with &lt;code&gt;git add .&lt;/code&gt;, then &lt;em&gt;amend them to your last commit&lt;/em&gt; with &lt;code&gt;git commit --am&lt;/code&gt;. Edit your commit message and/or description if desired, and write the file.&lt;/p&gt;

&lt;h4&gt;
  
  
  Change several past commits
&lt;/h4&gt;

&lt;p&gt;Go into interactive rebase with &lt;code&gt;git rebase -i HEAD~5&lt;/code&gt; where 5 is the number of commits you want to go back. Change pick into &lt;code&gt;e&lt;/code&gt; for edit on any commit you want to change. Write the file. Make the changes you want to do on that commit. Continue to the next commit with &lt;code&gt;git rebase --continue&lt;/code&gt;. It will first offer you to change the commit message and/or description, similar to when you &lt;code&gt;git commit --am&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Stash your changes
&lt;/h4&gt;

&lt;p&gt;You can stash away your changes with &lt;code&gt;git stash&lt;/code&gt; and retrieve them later with &lt;code&gt;git stash pop&lt;/code&gt;. Very handy if you’ve made some changes that you want to add to a commit further back than your latest one.&lt;/p&gt;

&lt;h4&gt;
  
  
  Drop a commit
&lt;/h4&gt;

&lt;p&gt;Enter interactive rebase. Simply delete the line that shows the commit you want to drop. Write the file. Done.&lt;/p&gt;

&lt;h4&gt;
  
  
  Change the order of commits
&lt;/h4&gt;

&lt;p&gt;Enter interactive rebase. Cut the line of a commit you want to move. Paste it anywhere in the list to change the order, and write the file.&lt;/p&gt;

&lt;h4&gt;
  
  
  Reset a commit
&lt;/h4&gt;

&lt;p&gt;Resetting a commit will remove the commit and make all its changes reappear in your working directory (soft reset). Especially handy when you’ve made a quick checkpoint commit and want to organize all the changes into relevant commits. Use &lt;code&gt;git reset HEAD~&lt;/code&gt; to reset your latest commit. Add a number to the end to reset that many of your latest commits.&lt;/p&gt;

&lt;p&gt;Adding the &lt;code&gt;--hard&lt;/code&gt; option will remove the changes entirely, as if they never happened.&lt;/p&gt;

&lt;h4&gt;
  
  
  Take a commit from another branch
&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;git log [branch]&lt;/code&gt; where &lt;code&gt;branch&lt;/code&gt; is the name of the branch that has the commit. Find the commit you want. Copy the commit hash. Move back to your own branch. Cherry-pick the commit with &lt;code&gt;git cherry-pick 887ab710ac81a5d8cf6986305e9303ae5771b602&lt;/code&gt; (replace with the commit hash).&lt;/p&gt;

&lt;h4&gt;
  
  
  Stage a hunk of changes
&lt;/h4&gt;

&lt;p&gt;Instead of staging all the changes in a file, you can stage hunks of changes separately so as to add them to their respective atomic commits. Do this with &lt;code&gt;git add --patch some-file.php&lt;/code&gt;. Git will stop at each hunk and ask you if you want to stage it (y, n).&lt;/p&gt;

&lt;p&gt;Some other options are: &lt;code&gt;–d&lt;/code&gt;: Don’t add this and any remaining hunks. You’re finished. &lt;code&gt;–s&lt;/code&gt;: Split the hunk into smaller hunks.&lt;br&gt;
&lt;code&gt;–e&lt;/code&gt;: Manually edit the hunk. Keep in mind you're editing _which changes you want to stage`. You are not affecting the actual change.&lt;/p&gt;

&lt;h4&gt;
  
  
  Find the commit that broke something
&lt;/h4&gt;

&lt;p&gt;You’re a bunch of commits along and notice something’s broken along the way. You can either check out every commit separately (takes a while), or use the binary search method (takes less time). Here’s how: &lt;/p&gt;

&lt;p&gt;– &lt;code&gt;git bisect start&lt;/code&gt; &lt;br&gt;
– &lt;code&gt;git bisect bad&lt;/code&gt; will mark your &lt;code&gt;HEAD&lt;/code&gt; as the bad commit. Pass a commit hash if the bad commit it an earlier one.&lt;br&gt;
– &lt;code&gt;git bisect good 887ab710ac81a5d8cf6986305e9303ae5771b602&lt;/code&gt; (replace with hash of good commit) &lt;/p&gt;

&lt;p&gt;Git will now check out a commit somewhere in the middle. Check if it’s broken (bad) or not (good) and mark it in the same way as the last two steps. Repeat this until there’s nothing more to check. The CLI output will give you the &lt;code&gt;first bad commit&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;– Run &lt;code&gt;git bisect reset&lt;/code&gt; to leave the bisect.&lt;/p&gt;

</description>
      <category>git</category>
      <category>rebase</category>
      <category>bisect</category>
    </item>
    <item>
      <title>Fix bugs ⚡ fast with regression tests and auto-bisect</title>
      <dc:creator>Pauline Vos</dc:creator>
      <pubDate>Wed, 17 Mar 2021 15:54:04 +0000</pubDate>
      <link>https://forem.com/paulinevos/fix-bugs-fast-with-regression-tests-and-auto-bisect-3khh</link>
      <guid>https://forem.com/paulinevos/fix-bugs-fast-with-regression-tests-and-auto-bisect-3khh</guid>
      <description>&lt;p&gt;Even if you have amazing test coverage (don’t we all?), chances are you’ll still run into unexpected behavior in your application. You may have missed a case, or you may not have thought it was crucial to test at the time. Whatever the reason, it can be tricky to debug unexpected behavior after the fact. Once you do find and fix the bug, you might create a regression test to prevent it from happening again…&lt;/p&gt;

&lt;p&gt;… but did you know you can write the regression test first and make it debug for you?&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;NOTE: If you haven’t heard of atomic commits or interactive rebase, now might be a good time to read my &lt;a href="https://www.pauline-vos.nl/atomic-commits/" rel="noopener noreferrer"&gt;post&lt;/a&gt; + &lt;a href="https://www.pauline-vos.nl/git-legit-cheatsheet/" rel="noopener noreferrer"&gt;cheatsheet&lt;/a&gt; on that.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Take this completely reasonable and realistic scenario: you write an application for a dragon whose sole job it is to destroy villages:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Trogdor&lt;/span&gt; 
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/** * @var Type */&lt;/span&gt; 
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Type&lt;/span&gt; &lt;span class="nv"&gt;$type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$type&lt;/span&gt; &lt;span class="o"&gt;??&lt;/span&gt; &lt;span class="nc"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;dragon&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;burninate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Village&lt;/span&gt; &lt;span class="nv"&gt;$village&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$village&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getCottages&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$cottage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; 
            &lt;span class="nv"&gt;$cottage&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;burn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; 
        &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="p"&gt;}&lt;/span&gt; 
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getType&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;Type&lt;/span&gt; 
    &lt;span class="p"&gt;{&lt;/span&gt; 
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; 
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You did some refactoring and you’re a bunch of commits in, when suddenly you notice your dragon has stopped burning cottages. When and how did this happen? Let’s assume you know that last week everything was working fine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 1: write a test
&lt;/h2&gt;

&lt;p&gt;First, write a regression test that covers your expected behavior. At this point it will fail. Commit your test. Don’t worry about writing a pretty message.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TrogdorTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testCottagesShouldBurn&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$application&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;TrogdorApplication&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Trogdor&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="nc"&gt;Village&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;withCottages&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="nv"&gt;$application&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;run&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$village&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getCottages&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$cottage&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;assertTrue&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$cottage&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isBurned&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: move the test
&lt;/h2&gt;

&lt;p&gt;Using interactive rebase, move the commit back in time to the point everything was still working. In this example we’ll just assume that wasn’t so long ago, but bisect is especially useful in situations where you have many more commits to work through.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt; git rebase &lt;span class="nt"&gt;-i&lt;/span&gt; HEAD~7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A file will open in your default text editor. Cut and paste the line to a place in time where the test will pass, then save and close the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pick 1b81fc5 Create Trogdor 
pick 51927a0 TROGDOR TEST
pick cf3ea2d Introduce dragon types
pick 6882ded He was a man
pick 95a11c7 I mean he was a... dragonman
pick 0f763a8 Or maybe he was just a... dragon
pick 8587b82 Add people to the cottages
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will reorder the commit. To check that the test now passes, you can check out the commit and run it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git checkout 51927a0    // Replace this with the correct commit ID.
phpunit TrogdorTest.php // Check that this passes.
git checkout -          // Return to your HEAD.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 3: run bisect
&lt;/h2&gt;

&lt;p&gt;If you’re unfamiliar with bisect, in a nutshell it’s a Git feature that helps you find a point in history efficiently. Instead of manually checking out and investigating commits one by one, bisect will automatically check out commits for you using a binary search strategy, making it much more efficient. Again, you might want to head over to my &lt;a href="https://www.pauline-vos.nl/git-legit-cheatsheet/" rel="noopener noreferrer"&gt;cheatsheet&lt;/a&gt; and jump to bisect for more context.&lt;/p&gt;

&lt;p&gt;You can run bisect automatically by feeding it any script that will either succeed (exit code 0) or fail (anything else). That’s how tests succeed or fail, so your test is one such script. If you provide bisect a commit on which the test will pass (good), and one on which it will fail (bad), it will use binary search to automatically find the first point in time where it will fail:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git bisect start
git bisect good ea7753a                // Mark the passing commit as good
git bisect bad HEAD                    // Mark your HEAD as bad
git bisect run phpunit TrogdorTest.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When bisect is finished running, it will present the commit that introduced the bug:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;0f763a8374ecb38fdc02657f0502495227cb2d94 is the first bad commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can then exit bisect by running &lt;code&gt;git bisect reset&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 4: fix the bug
&lt;/h2&gt;

&lt;p&gt;Now that you know which commit introduced the bug, you can check it out and inspect the changes it introduced. In this case, it seems that you forgot to change a conditional that checks Trogdor’s type when you changed his default type from &lt;code&gt;dragonMan&lt;/code&gt; to &lt;code&gt;dragon&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Application&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/**
     * @var Trogdor
     */&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$trogdor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * @var Village
     */&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$village&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Trogdor&lt;/span&gt; &lt;span class="nv"&gt;$trogdor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Village&lt;/span&gt; &lt;span class="nv"&gt;$village&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;trogdor&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$trogdor&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;village&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$village&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;run&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$trogdor&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nb"&gt;getType&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isDragonMan&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;// &amp;lt;- This should check for `isDragon()`!&lt;/span&gt;
            &lt;span class="nv"&gt;$trogdor&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;burninate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$village&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your detached HEAD state, do what you need to do to make the test pass. Create a commit for the fix, and check out a new branch from there.&lt;/p&gt;

&lt;p&gt;Step 5: apply the fix&lt;br&gt;
Great, so now you’ve implemented a fix. But you’ll probably want to apply it to your original branch and commit it together with your test. So copy the commit ID of the fix, and check out your previous branch. Then, cherry pick your fix so that it’s on your branch:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git cherry-pick cc78654
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, enter interactive rebase, move your test commit, and squash them together. Don’t forget to write a nice commit message describing the &lt;strong&gt;what&lt;/strong&gt; and the &lt;strong&gt;why&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git rebase &lt;span class="nt"&gt;-i&lt;/span&gt; HEAD~8
pick 1b81fc5 Create Trogdor 
pick cf3ea2d Introduce dragon types
pick 6882ded He was a man
pick 95a11c7 I mean he was a... dragonman
pick 0f763a8 Or maybe he was just a... dragon
pick 8587b82 Add people to the cottages
pick cc78654 fix
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All done! Of course, this was a simplified example. But in complex projects, it can be very hard to pinpoint exactly what went wrong. Especially if you’re looking at 20+ commits. You don’t want to go through them one by one, and with this strategy you won’t have to.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want to try it out yourself, &lt;a href="https://github.com/paulinevos/money" rel="noopener noreferrer"&gt;clone this repo&lt;/a&gt; and check out a branch called &lt;code&gt;4_bisect&lt;/code&gt;. I’ve broken a test in the &lt;code&gt;HEAD&lt;/code&gt;. The commit you’ll want to mark as good is &lt;code&gt;85ce6e4 Fix risky tests&lt;/code&gt;. Good luck 🙂&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;iframe width="710" height="399" src="https://www.youtube.com/embed/7gz1DIIxmEE"&gt;
&lt;/iframe&gt;
&lt;/p&gt;

</description>
      <category>git</category>
      <category>bisect</category>
      <category>testing</category>
    </item>
    <item>
      <title>Atomic commits will help you git legit.</title>
      <dc:creator>Pauline Vos</dc:creator>
      <pubDate>Wed, 17 Mar 2021 12:20:09 +0000</pubDate>
      <link>https://forem.com/paulinevos/atomic-commits-will-help-you-git-legit-35i7</link>
      <guid>https://forem.com/paulinevos/atomic-commits-will-help-you-git-legit-35i7</guid>
      <description>&lt;p&gt;I’ve given a talk (Git Legit) a few times that basically makes a case for atomic commits. I’ve created a &lt;a href="https://dev.to/paulinevos/git-legit-cheat-sheet-2gf0"&gt;cheatsheet&lt;/a&gt; to go with it, but then I realized there’s no point to the cheatsheet if you don’t use atomic commits. Then I realized you won’t start using atomic commits until you know the benefits. So, here’s basically a short recap of my talk if you haven’t seen it.&lt;/p&gt;

&lt;p&gt;When I started using Git, I used it as a save point. Similarly to when you’re playing a video game, made a bunch of progress, and think “I should probably find a save point or I’ll lose all my progress”. This makes a lot of sense; we’re used to this linear, “checkpoint” mindset. But I shifted from the “checkpoint commit” mindset to atomic commits and haven’t looked back once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Firstly, what are atomic commits?
&lt;/h2&gt;

&lt;p&gt;Atomic commits, in short, are what they sound like: atomic. So small that they can't be broken up any further. I feel like there’s basically three features a commit needs to have to be atomic:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fv6mgjsd7mrm9ziw9jngb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fv6mgjsd7mrm9ziw9jngb.png" alt="A list. 1: Single, irreducible unit. Every commit pertains to one fix or feature. 2: Everything works. Don't break the build on any commit. 3: Clear and concise. Purpose is clear from the commit message and description." width="800" height="415"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In short, all your tests need to be green on every commit and your application shouldn’t break. Every commit has a clear commit message and a description detailing what the purpose of these changes was. Lastly, the commit should only have changes pertaining to one fix or feature (or whatever you were working on). Don’t have commits where you “fixed that bug and also implemented the feature and then also refactored some class”.&lt;/p&gt;

&lt;p&gt;Why, you ask? Well,&lt;/p&gt;

&lt;h2&gt;
  
  
  Atomic commits have big benefits
&lt;/h2&gt;

&lt;p&gt;For me, one of the biggest advantages of atomic commits is spending a LOT less time solving merge conflicts. Because all your commits are concentrated to a certain part of the code, merging and rebasing become so, so much less painful. You’ll have a lot more context to the conflict and your conflicts will become smaller and much more rare. Any time you need to rebase your branch will go much more smoothly. Also, dropping and cherry-picking commits become very handy options.&lt;/p&gt;

&lt;p&gt;Atomic commits also make code review much more pleasant. You’ll be able to review commit by commit, which will give your brain less information overload and offer a clear context of what you’re reviewing. After all, the commit is about one fix or feature only, and the message and description are clear and concise. Having this context and diminished confusion will not only make reviewing more pleasant; it will make you better at reviewing. This commit by commit review isn’t possible if you’re using git like a save point, creating checkpoint commits. That’s because they’re based on time, not on a portion of the code. Consequently, you might request changes or comment on one commit, when that particular change was already undone in a next commit. You just hadn’t gotten to that commit yet. Very inconvenient.&lt;/p&gt;

&lt;p&gt;Lastly, your history becomes much more relevant. Without atomic commits, it becomes difficult to be descriptive in your commit messages, since you’re touching different areas of the code and not focusing on one central theme per commit. So, at a glance, people won’t be able to tell what happened in your history. Take this scenario:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fzz4lxo6i42kvque92gev.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fzz4lxo6i42kvque92gev.png" alt="A screenshot of a Terminal window showing 6 commits, all with vague names and descriptions like " width="353" height="540"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You fix a bug. Commit. You realize you broke something else in the process. Another commit. You address comments on your PR. Commit. And so on, and so on. You end up with this:&lt;/p&gt;

&lt;p&gt;Anyone looking through your history won’t know what commit actually fixed the bug. Without the context of your PR, the upper commit messages have no meaning. Every commit captures your application in a broken state, so you can’t revert comfortably. All you really wanted was to fix the bug. So amend your initial commit until you’ve actually fixed the bug.&lt;/p&gt;

&lt;p&gt;How, you ask? Well, here’s&lt;/p&gt;

&lt;h2&gt;
  
  
  How to keep your commits atomic
&lt;/h2&gt;

&lt;p&gt;While on your task/feature/whatever branch, group all the changes to their relevant commits. This means you’ll need to change your commits if you make any changes to them afterwards. This is possible through interactive rebase and amending.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Please note:&lt;/strong&gt; any time you change a commit, it changes the commit hash. This means that if you try to push it to your origin, it will be rejected (your origin thinks the commit doesn’t belong there), unless you &lt;code&gt;git push -f&lt;/code&gt;. You should probably protect master and any other important branches.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;My &lt;a href="https://dev.to/paulinevos/git-legit-cheat-sheet-2gf0"&gt;cheatsheet&lt;/a&gt; lays out some handy commands Git offers to help you keep your commits atomic. It takes some learning and getting used to, but you’ll breathe a lot easier once you do.&lt;/p&gt;

</description>
      <category>git</category>
      <category>rebase</category>
      <category>atomiccommits</category>
    </item>
    <item>
      <title>A Bit About Kanban</title>
      <dc:creator>Pauline Vos</dc:creator>
      <pubDate>Wed, 17 Mar 2021 12:08:44 +0000</pubDate>
      <link>https://forem.com/paulinevos/a-bit-about-kanban-281b</link>
      <guid>https://forem.com/paulinevos/a-bit-about-kanban-281b</guid>
      <description>&lt;p&gt;I have a lot of feelings about Kanban. Mostly because I’ve had brilliant experiences with it, and I see it go wrong so often. As with anything new in software development, knowing why it was designed a certain way is essential to its successful adoption.&lt;/p&gt;

&lt;p&gt;The main reason I see teams make the switch from Scrum to Kanban is because they think it’s more flexible, and there’s essentially no rules. While in some ways that’s true, that mindset is a common pitfall. And, of course, this misconception will often lead to the conclusion that Kanban sucks, and a frustrated team switching back to Scrum or some strange hybrid for the n-th time.&lt;/p&gt;

&lt;p&gt;Let’s have a look at some commonly held views about Kanban:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There is no commitment in Kanban.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;FALSE:&lt;/strong&gt; while the team does not commit to a set of stories over a cycle, once a task is picked up and moving along the board, it is committed to. It cannot suddenly be taken out or abandoned for no good reason.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can constantly change prioritization in Kanban.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;FALSE:&lt;/strong&gt; once an item is picked up, it has to move forward on the board and cannot be swapped with something deemed higher priority (unless an expedite lane is implemented). However, as the team doesn’t plan for a sprint cycle, anything in the ready column or in the backlog can be moved up or down in priority. So it does give the team more flexibility in prioritization to a degree.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;There are no rituals in Kanban.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;TRUE:&lt;/strong&gt; Kanban does not dictate that the team must have retro or planning sessions like Scrum does, but it also leaves teams free to have them if they so please. Many teams still prefer having a regular retrospective to reflect on their process or check in on team dynamics. And that’s totally fine!&lt;/p&gt;

&lt;p&gt;As you can see, although there are fewer than in Scrum, ground rules definitely exist. I’d even argue that to be successful with Kanban, the few rules it has should be followed quite strictly. There are reasons these rules exist, and, just like the rules in the Scrum framework, I would not forego them unless you know &lt;em&gt;why&lt;/em&gt; they exist and &lt;em&gt;why&lt;/em&gt; you’re doing it.&lt;/p&gt;

&lt;p&gt;Most of the “why” boils down to this: &lt;strong&gt;Kanban is designed to show you flaws in your process.&lt;/strong&gt; The goal is to optimize your work pipeline to be as smooth as possible, always flowing. This means your main priority is to remove bottlenecks. The rules in Kanban all work towards showing you where these bottlenecks exist:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Each column has &lt;strong&gt;transitioning rules&lt;/strong&gt; dictating when a task can be moved into it.&lt;/li&gt;
&lt;li&gt;Every column has a &lt;strong&gt;WIP (work in progress) limit.&lt;/strong&gt; The amount of tasks in a column can never exceed it.&lt;/li&gt;
&lt;li&gt;Tasks move column to column from left to right. &lt;strong&gt;They never move back.&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;You can only work &lt;strong&gt;on one task at a time&lt;/strong&gt; (but multiple developers working on one task is allowed). If you switch to another task for a while, you unassign yourself from the current task and anyone else on the team can pick it up.&lt;/li&gt;
&lt;li&gt;Kanban is a &lt;strong&gt;pull system&lt;/strong&gt;, meaning a tast is only &lt;em&gt;pulled&lt;/em&gt; (not pushed) into the next column, when that column has availability.&lt;/li&gt;
&lt;li&gt;Tasks on the right of the pipeline have priority, clearing the path for tasks on the left to be pulled in.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That’s really about it. The WIP limits prevent developers from moving forward with a task if the subsequent column has already reached its limit. Not being able to move tasks around makes it so that devs are forced to clear work further along in the pipeline.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.amazon.co.uk/Phoenix-Project-DevOps-Helping-Business-ebook/dp/B00AZRBLHO" rel="noopener noreferrer"&gt;The Phoenix Project&lt;/a&gt; is a “Dev-Ops novel” that follows a character who’s faced with the challenge of delivering a complex project in a highly unstable environment. He meets an enigmatic mentor, who compares the software development process to a factory, with work stations and conveyor belts. If you think about it, the above rules apply to such a factory too. If one work station has reached its maximum capacity, the conveyor belt has to be stopped until the work station is cleared. There’s no use in piling more work onto the work station, because it’s not going to make the work station clear out any faster. It will only make subsequent items get stuck on the same things, and actual output will be minimal. The same applies to your software development pipeline.&lt;/p&gt;

&lt;p&gt;Following these rules strictly may become annoying, but that’s exactly the point. &lt;strong&gt;Kanban is meant to feel uncomfortable sometimes.&lt;/strong&gt; Bottlenecks become painfully obvious, and the team is motivated to resolve them. This in turn improves predictability and productivity. Before you know it, the entire process feels smooth and beautiful ✨&lt;/p&gt;

&lt;p&gt;Take a conversation that happened today:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.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%2Fygf0wm2tun3vk01flji3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fygf0wm2tun3vk01flji3.png" alt="Screenshot of a Slack conversation. Lisa says: " width="800" height="117"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This seems like a fairly straightforward decision. There’s no hard rules, right? Shouldn’t be a problem to increase the WIP limit, surely? Sure, but the question is always “why?”. Is there a reason the column can’t be cleared out?&lt;/p&gt;

&lt;p&gt;And, sure enough:&lt;br&gt;
&lt;a href="https://media2.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%2Fyjtpyt0xxsgeoqxif1ei.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.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%2Fyjtpyt0xxsgeoqxif1ei.png" alt="Screenshot of a Slack conversation. Lisa says: " width="800" height="264"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;By increasing the WIP limit any time the pipeline is blocked, this problem would never have been noticed. Now, with the underlying issue revealed, the team can ask themselves how to resolve it. Maybe the technical solution should be documented somewhere in the ticket? Maybe everyone should push to origin before going home? &lt;/p&gt;

&lt;p&gt;Of course, any decision is still up to the team. Nobody’s calling the Kanban police 🚓 if you break a rule. But trust me: you’ll do yourself a massive favor if you ask yourself “why?” any time you’re tempted to break any of the rules mentioned above. More often than not, I think you’ll find you’ll change your mind.&lt;/p&gt;

&lt;p&gt;Do you still have hangups about your Kanban process? Let’s see if we can resolve them in the comments.&lt;/p&gt;

</description>
      <category>kanban</category>
      <category>agile</category>
    </item>
  </channel>
</rss>
