<?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: Annie Sexton</title>
    <description>The latest articles on Forem by Annie Sexton (@anniesexton).</description>
    <link>https://forem.com/anniesexton</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%2F61324%2F81ac95e0-2102-4a9e-993e-f06bf82d71b2.jpeg</url>
      <title>Forem: Annie Sexton</title>
      <link>https://forem.com/anniesexton</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/anniesexton"/>
    <language>en</language>
    <item>
      <title>Git Organized: A Better Git Flow</title>
      <dc:creator>Annie Sexton</dc:creator>
      <pubDate>Thu, 13 Jan 2022 18:58:36 +0000</pubDate>
      <link>https://forem.com/render/git-organized-a-better-git-flow-56go</link>
      <guid>https://forem.com/render/git-organized-a-better-git-flow-56go</guid>
      <description>&lt;p&gt;Imagine this: you've been paged to investigate a production incident, and after some digging, you identify the commit with the breaking code. You decide to revert the change:&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="nv"&gt;$ &lt;/span&gt;git revert 1a2b3c
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Unfortunately, in doing so, a new bug is introduced! As it turns out, hidden in that old "broken" commit was some code that another part of the app depended upon, and when you reverted those lines, it left the site once again in a broken state. 🙃 Oh dear.&lt;/p&gt;

&lt;p&gt;How can situations like this be avoided? To answer this question, we first need to examine how these types of commits come to be.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Common Git Flow
&lt;/h2&gt;

&lt;p&gt;Let's take a look at a common git flow when building a new feature:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a new branch off of &lt;code&gt;main&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create commits as you go to save your work and fix bugs you find along the way.&lt;/li&gt;
&lt;li&gt;When the feature is complete, make a pull request.&lt;/li&gt;
&lt;li&gt;Merge branch into &lt;code&gt;main&lt;/code&gt; once PR is approved.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This flow might feel quite familiar to you, and that's fine. It's how many of us were taught to work with git. However, &lt;strong&gt;there are two problems with this approach.&lt;/strong&gt; The first problem we've already discussed is that some commits may contain incomplete work when you simply commit as you go. This makes reverting quite risky.&lt;/p&gt;

&lt;p&gt;The second problem is that &lt;strong&gt;it can make reviewing pull requests very tedious.&lt;/strong&gt; For example, what if you've been asked to review a recent PR in which the author states that, on top of adding a new feature, they fixed an unrelated bug as well. The PR consists of changes across &lt;em&gt;dozens&lt;/em&gt; of files. Looking at each commit individually does not illuminate which changes pertain to the bug fix and which are for the new feature. Additionally, you notice some changes that seem &lt;em&gt;unrelated to anything in the description of the PR&lt;/em&gt;. Clearly, this will not be a quick review.&lt;/p&gt;

&lt;p&gt;Now, as lovely as it would be for each commit to neatly relate to only &lt;em&gt;one&lt;/em&gt; change, that's a tall order to fill when you're in the midst of development. Tangents and rewrites are just part of the process. Our work is rarely so linear, and our git commits tend to reflect this.&lt;/p&gt;

&lt;p&gt;So how can we guarantee that our git history is tidy and easily reviewable while also accepting the somewhat tangential nature of development? By modifying this basic git flow just slightly, we can create a better process that accomplishes just this.&lt;/p&gt;

&lt;h2&gt;
  
  
  An Improved Git Flow
&lt;/h2&gt;

&lt;p&gt;The following approach was inspired by my coworker, Dan Wendorf, whose git flow tends to revolve around one core principle: &lt;strong&gt;do the work first, clean up the commits later.&lt;/strong&gt; The benefit of this flow is that it separates the &lt;em&gt;engineering&lt;/em&gt;  &lt;em&gt;work&lt;/em&gt; from the &lt;em&gt;commit writing&lt;/em&gt;. In the end, we'll be left with a sequence of commits that are &lt;em&gt;logically grouped&lt;/em&gt;, each relating to one main change in the code, thus cleaning up our git history and paving the way for a quicker PR review.&lt;/p&gt;

&lt;p&gt;We can break it down into three steps, as follows.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Make your changes
&lt;/h3&gt;

&lt;p&gt;The first step isn't too different than before. Start by creating a new branch and getting to work on making your changes. Don't worry too much about writing descriptive commit messages just yet, as these won't be included in your final PR. For now a simple, "work in progress" or "WIP" message will do, or something that will help you remember what was in that commit like "WIP: Started building new model". The purpose of these commits are to make sure you don't lose work and provide some general guideposts along the path of that work.&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="nv"&gt;$ &lt;/span&gt;git checkout &lt;span class="nt"&gt;-b&lt;/span&gt; my-feature-branch

...make changes...

&lt;span class="nv"&gt;$ &lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="s2"&gt;"WIP"&lt;/span&gt;

...make more changes...

&lt;span class="nv"&gt;$ &lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="s2"&gt;"WIP"&lt;/span&gt;

...make even more changes...

&lt;span class="nv"&gt;$ &lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="s2"&gt;"WIP"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this step, it's &lt;em&gt;okay&lt;/em&gt; to leave the codebase in a broken state or to commit half-baked features. This will all get cleaned up later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Reset
&lt;/h3&gt;

&lt;p&gt;Once you've finished making your changes, it's time to prepare your work for some "git clean up." To do this, we'll run the following command:&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="nv"&gt;$ &lt;/span&gt;git reset origin/main
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Without any extra arguments, &lt;code&gt;git reset&lt;/code&gt; won't change the working tree, so your code won't change — all the work you've done will still be there. But because you've reset to an &lt;em&gt;older&lt;/em&gt; commit, &lt;code&gt;git status&lt;/code&gt; will show all the changes you've made since you started building your feature. It will look like you did all the work but never made any of those "WIP" commits earlier.&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="nv"&gt;$ &lt;/span&gt;git reset origin/main
Unstaged changes after reset:
M       src/components/Footer/Footer.tsx
M       src/components/Nav/Nav.css
M       src/components/Nav/Nav.tsx
M       src/components/Posts/Post.tsx
M       src/components/Posts/PostList.tsx

&lt;span class="nv"&gt;$ &lt;/span&gt;git status
On branch feature-branch
Your branch is behind &lt;span class="s1"&gt;'origin/feature-branch'&lt;/span&gt; by 3 commits, and can be fast-forwarded.
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git pull"&lt;/span&gt; to update your &lt;span class="nb"&gt;local &lt;/span&gt;branch&lt;span class="o"&gt;)&lt;/span&gt;

Changes not staged &lt;span class="k"&gt;for &lt;/span&gt;commit:
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git add &amp;lt;file&amp;gt;..."&lt;/span&gt; to update what will be committed&lt;span class="o"&gt;)&lt;/span&gt;
  &lt;span class="o"&gt;(&lt;/span&gt;use &lt;span class="s2"&gt;"git restore &amp;lt;file&amp;gt;..."&lt;/span&gt; to discard changes &lt;span class="k"&gt;in &lt;/span&gt;working directory&lt;span class="o"&gt;)&lt;/span&gt;
        modified:   src/components/Footer/Footer.tsx
        modified:   src/components/Nav/Nav.css
        modified:   src/components/Nav/Nav.tsx
        modified:   src/components/Posts/Post.tsx
        modified:   src/components/Posts/PostList.tsx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;In case you get in over your head here, don't worry&lt;/strong&gt; — you can always bring back your original commits! Every commit you make lives in your &lt;code&gt;.git&lt;/code&gt; folder, even after a &lt;code&gt;reset&lt;/code&gt;. Even though it might seem like they've disappeared, they're still there, hiding.&lt;/p&gt;

&lt;p&gt;If you want to go back to a commit where things weren't broken, &lt;code&gt;git reflog&lt;/code&gt; will show you a timeline of every commit you've referenced in your local repository, even across branches. Run &lt;code&gt;git reflog&lt;/code&gt; to find the commit you want to return to and then run &lt;code&gt;git reset &amp;lt;commit-sha&amp;gt;&lt;/code&gt;. This command will point the HEAD of your current branch to that commit, and you're back in business!&lt;/p&gt;

&lt;p&gt;From here, we're ready to start making our &lt;em&gt;new&lt;/em&gt; commits.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Create new, logically-grouped commits
&lt;/h3&gt;

&lt;p&gt;Now, take a look at all the files you've changed. Are there any that you can logically group? For example, all the dependency updates or changes related to a particular model. There's no "right" way to group files, so use your best judgment here. Add these files to your staging area, and make a commit describing the changes.&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="nv"&gt;$ &lt;/span&gt;git add src/components/Nav/Nav.css
&lt;span class="nv"&gt;$ &lt;/span&gt;git add src/components/Nav/Nav.tsx
&lt;span class="nv"&gt;$ &lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="s2"&gt;"Added new styles to navigation"&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;git add src/components/Posts/Post.tsx
&lt;span class="nv"&gt;$ &lt;/span&gt;git add src/components/Posts/PostList.tsx
&lt;span class="nv"&gt;$ &lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="s2"&gt;"Updated author images on posts"&lt;/span&gt;

&lt;span class="nv"&gt;$ &lt;/span&gt;git add src/components/Footer/Footer.tsx
&lt;span class="nv"&gt;$ &lt;/span&gt;git commit &lt;span class="nt"&gt;-m&lt;/span&gt;&lt;span class="s2"&gt;"Fixed responsive bug in footer"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you haven't changed many files, you might not need more than one commit, but we can often make our pull requests much easier to review by splitting up our changes into human-readable, easy-to-follow commits.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What if the same file contains multiple changes that should be grouped separately?&lt;/strong&gt; It's possible to &lt;a href="https://nuclearsquid.com/writings/git-add/" rel="noopener noreferrer"&gt;stage &lt;em&gt;part&lt;/em&gt; of a file&lt;/a&gt; using &lt;code&gt;git add --patch&lt;/code&gt; (or &lt;code&gt;git add -p&lt;/code&gt;). Some code editors also provide a way to stage a &lt;em&gt;range&lt;/em&gt; of changes rather than a whole file.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Be mindful of not leaving your codebase in a broken state during this step.&lt;/strong&gt; Remember, a huge reason we're cleaning up our commits in the first place is so that nothing will break if we ever want to revert our changes. After making one of these new commits, you can &lt;code&gt;git stash&lt;/code&gt; the rest of the unstaged changes and test that everything's still in working order. If you realize you should have included another file in that commit, you can &lt;code&gt;git stash pop&lt;/code&gt; to bring back the other changes, &lt;code&gt;git add&lt;/code&gt; the missing file, and perform a &lt;code&gt;git commit --amend&lt;/code&gt; . This command will replace the last commit with a new one with the same description, including the old commit and the change you just made.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Final Result
&lt;/h3&gt;

&lt;p&gt;Once you've split your work into logically grouped commits, you're ready to create your pull request! The final result is a set of changes that your colleague can review one commit at a time in manageable chunks.&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%2Fdn0zd76mhkfvtk0qrjzr.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%2Fdn0zd76mhkfvtk0qrjzr.png" alt="Logically-organized commits in a PR" width="800" height="268"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The benefit of this git flow is that it allows for the fluidity of typical development while also providing some much-needed order to maintain the repository's history.&lt;/p&gt;

</description>
      <category>tutorial</category>
      <category>productivity</category>
      <category>git</category>
    </item>
  </channel>
</rss>
