<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Mark&#39;s Dev Blog</title>
    <link>https://blog.isquaredsoftware.com/tags/history/index.xml</link>
    <description>Recent content on Mark&#39;s Dev Blog</description>
    <generator>Hugo -- gohugo.io</generator>
    <atom:link href="https://blog.isquaredsoftware.com/tags/history/index.xml" rel="self" type="application/rss+xml" />
    
    <item>
      <title>Coding Career Advice: Using Git for Version Control Effectively</title>
      <link>https://blog.isquaredsoftware.com/2021/01/coding-career-git-usage/</link>
      <pubDate>Wed, 27 Jan 2021 10:00:00 -0500</pubDate>
      
      <guid>https://blog.isquaredsoftware.com/2021/01/coding-career-git-usage/</guid>
      <description>&lt;p&gt;&lt;/p&gt;

&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;

&lt;p&gt;Git has become the standard tool for software development version control.  Other VCS tools exist, and some work better than Git for certain scenarios, but most of today&#39;s development world relies on using Git.  So, becoming comfortable with Git and knowing how to use it effectively is a key skill for any software developer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I&#39;d like to pass along some of the most useful Git concepts and tips&lt;/strong&gt; that I&#39;ve learned over the last few years.  In addition, I&#39;ve covered &lt;strong&gt;background info on how Git works and common operations&lt;/strong&gt;, and there&#39;s some &lt;strong&gt;specific usage patterns I&#39;ve found to be especially valuable&lt;/strong&gt; when working with a team and trying to understand a codebase.&lt;/p&gt;

&lt;p&gt;As usual, none of the info or advice in this post is completely new or original, and there&#39;s many other sites that cover the same topics (and probably explain them better).  I&#39;m just trying to provide an overview of the relevant material and provide enough details that you can do further research and learning from there.&lt;/p&gt;

&lt;p&gt;This post is largely based on my slideset &lt;a href=&#34;https://blog.isquaredsoftware.com/2019/10/presentation-git-internals-rewrite/&#34;&gt;&lt;strong&gt;Git Under the Hood: Internals, Techniques, and Rewriting History&lt;/strong&gt;&lt;/a&gt;, and I talked about rewriting repo history in my post &lt;a href=&#34;https://blog.isquaredsoftware.com/2018/11/git-js-history-rewriting/&#34;&gt;&lt;strong&gt;Rewriting Your Git History and JS Source for Fun and Profit&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id=&#34;table-of-contents&#34;&gt;Table of Contents&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#introduction&#34;&gt;Introduction&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#table-of-contents&#34;&gt;Table of Contents&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#git-fundamentals&#34;&gt;Git Fundamentals&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#git-terms-and-concepts-overview&#34;&gt;Git Terms and Concepts Overview&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#git-basics&#34;&gt;Git Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#sharing-data-between-repositories&#34;&gt;Sharing Data Between Repositories&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#branches&#34;&gt;Branches&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#understanding-git-internals&#34;&gt;Understanding Git Internals&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#git-tools&#34;&gt;Git Tools&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#git-techniques&#34;&gt;Git Techniques&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#improving-cli-logging&#34;&gt;Improving CLI Logging&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#preparing-commits-in-pieces&#34;&gt;Preparing Commits in Pieces&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#stashing-changes&#34;&gt;Stashing Changes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#working-with-branches&#34;&gt;Working with Branches&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#creating-and-switching-branches&#34;&gt;Creating and Switching Branches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#fetching-pushing-and-pulling-branches&#34;&gt;Fetching, Pushing, and Pulling Branches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#merging-branches&#34;&gt;Merging Branches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#feature-branch-strategies&#34;&gt;Feature Branch Strategies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#pull-requests&#34;&gt;Pull Requests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#updating-branches-in-the-background&#34;&gt;Updating Branches in the Background&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#rewriting-git-history&#34;&gt;Rewriting Git History&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#amending-commits&#34;&gt;Amending Commits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#resetting-branches&#34;&gt;Resetting Branches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#rebasing-branches&#34;&gt;Rebasing Branches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#reverting-commits&#34;&gt;Reverting Commits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#cherry-picking&#34;&gt;Cherry-Picking&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#interactive-rebasing&#34;&gt;Interactive Rebasing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#reflog&#34;&gt;Reflog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#advanced-history-rewriting&#34;&gt;Advanced History Rewriting&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#git-patterns-and-best-practices&#34;&gt;Git Patterns and Best Practices&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#write-good-commit-messages&#34;&gt;Write Good Commit Messages&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#make-small-focused-commits&#34;&gt;Make Small, Focused Commits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#clean-up-commit-history-before-pushing&#34;&gt;Clean Up Commit History Before Pushing&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#only-rewrite-unpushed-history&#34;&gt;Only Rewrite Unpushed History&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#keep-feature-branches-short-lived&#34;&gt;Keep Feature Branches Short-Lived&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#code-archeology-with-git&#34;&gt;Code Archeology with Git&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#displaying-historical-file-changes&#34;&gt;Displaying Historical File Changes&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#bisecting-bugs&#34;&gt;Bisecting Bugs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#final-thoughts&#34;&gt;Final Thoughts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#further-information&#34;&gt;Further Information&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;git-fundamentals&#34;&gt;Git Fundamentals&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Git is notoriously difficult to work with, especially using the command line&lt;/strong&gt;.  The CLI commands and options are confusing, mismatched, and hard to remember.  There&#39;s phrases and warnings like &amp;quot;detached &lt;code&gt;HEAD&lt;/code&gt;&amp;quot;.  Git, frankly, is not easy to learn and kinda scary.&lt;/p&gt;

&lt;p&gt;The good news is that &lt;strong&gt;once you understand &lt;em&gt;how&lt;/em&gt; Git works, it becomes an extremely powerful tool that offers a lot of flexibility&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&#34;git-terms-and-concepts-overview&#34;&gt;Git Terms and Concepts Overview&lt;/h3&gt;

&lt;p&gt;While I&#39;m not going to turn this into a complete &amp;quot;Git tutorial from scratch&amp;quot;, it&#39;s worth reviewing some of the key concepts.&lt;/p&gt;

&lt;h4 id=&#34;git-basics&#34;&gt;Git Basics&lt;/h4&gt;

&lt;p&gt;Git is a tool for tracking changes to file content over time.  A Git &lt;em&gt;repository&lt;/em&gt; is a folder that has a &lt;code&gt;.git&lt;/code&gt; folder inside.  The &lt;code&gt;.git&lt;/code&gt; folder contains all the metadata and stored history of the project&#39;s changes.&lt;/p&gt;

&lt;p&gt;The &lt;em&gt;working copy&lt;/em&gt; is all other folders and files in the repository folder that Git is storing and tracking.  Any newly created files start out &lt;em&gt;untracked&lt;/em&gt;.  Git knows that the files are there, but you haven&#39;t told Git to save them.&lt;/p&gt;

&lt;p&gt;To tell Git to start tracking a file, you &lt;em&gt;add&lt;/em&gt; the file (&lt;code&gt;git add some-file&lt;/code&gt;).  Git then saves a copy of the file in an internal section called the &lt;em&gt;staging area&lt;/em&gt;.  Staged files are not being saved permanently, yet. Instead, they represent the set of files and contents that &lt;em&gt;will&lt;/em&gt; be saved when you actually tell Git to save them.&lt;/p&gt;

&lt;p&gt;Once you&#39;ve added one or more files to the staging area, you can save them by &lt;em&gt;committing&lt;/em&gt; them.  &amp;quot;Commit&amp;quot; is both a verb and a noun here: we &amp;quot;commit&amp;quot; files to save them, and every time we save them, we make a &amp;quot;commit&amp;quot;.&lt;/p&gt;

&lt;p&gt;Git commits contain a certain set of files and their contents, at a specific point in time.  They also contain metadata, including the author&#39;s name and email address, and a &lt;em&gt;commit message&lt;/em&gt; that you write to describe the changes that were saved.&lt;/p&gt;

&lt;p&gt;After a file has been added at least once, making further changes to that file will cause Git to mark it as &lt;em&gt;modified&lt;/em&gt;.  That means that Git knows the contents are different, but you haven&#39;t told Git to save the new changes yet.  Once you add that file to the staging area again, Git sees that its latest copy of the file is the same as what&#39;s on disk, so it describes the file as &lt;em&gt;unchanged&lt;/em&gt;.&lt;/p&gt;

&lt;h4 id=&#34;sharing-data-between-repositories&#34;&gt;Sharing Data Between Repositories&lt;/h4&gt;

&lt;p&gt;Each Git repository folder is standalone.  However, Git repositories can be shared across folders, computers, and networks, allowing developers to collaborate on the same codebase.  A Git repo can be configured with the URL of another repo, allowing the two repos to send commits back and forth.  Each URL entry is called a &lt;em&gt;remote&lt;/em&gt;.  Downloading commit data from a remote repo is a &lt;em&gt;fetch&lt;/em&gt; or a &lt;em&gt;pull&lt;/em&gt; (with slight differences in behavior), and uploading commit data from local to remote is a &lt;em&gt;push&lt;/em&gt;.  Downloading a complete repo from scratch is making a &lt;em&gt;clone&lt;/em&gt; of that repo.&lt;/p&gt;

&lt;p&gt;Repositories normally have a default remote repo they point to, called the &lt;em&gt;origin&lt;/em&gt;.  Whenever you clone a repo, the new local repo points to the remote source as the origin, but that entry can be changed later.  Repos can be configured to talk to many other repos at once, and can push and pull data from any remote.&lt;/p&gt;

&lt;h4 id=&#34;branches&#34;&gt;Branches&lt;/h4&gt;

&lt;p&gt;Git commits are tracked using &lt;em&gt;branches&lt;/em&gt;. A branch is like a pointer to the latest commit in a specific series of commits.  Any time you make a new commit, Git bumps that branch pointer to point to the newest commit.  You can make many branches within a repo, and most devs create a new branch for each task they work on.  You can also make &lt;em&gt;tags&lt;/em&gt;, which also point to a specific commit, but don&#39;t get moved or changed automatically. Tags are normally used to identify checkpoints and releases, so you can easily jump back and see how the code was at that point in time.&lt;/p&gt;

&lt;p&gt;Changes from multiple branches can be brought together using a &lt;em&gt;merge&lt;/em&gt; process.  If some of the changes apply to the same lines of code, there is a &lt;em&gt;merge conflict&lt;/em&gt;, and it&#39;s up to you as the developer to look at the mismatched changes and &lt;em&gt;resolve&lt;/em&gt; the conflict by picking out what the right contents are.&lt;/p&gt;

&lt;p&gt;Historically, most repos use a branch called &lt;code&gt;master&lt;/code&gt; as the primary development branch. More recently, the community has started switching to use a primary branch named &lt;code&gt;main&lt;/code&gt; instead.  But, you can configure Git to use any branch name as the &amp;quot;default development branch&amp;quot; if you want.&lt;/p&gt;

&lt;p&gt;Git uses the term &lt;em&gt;checking out&lt;/em&gt; to refer to updating the working copy files on disk, based on previously committed values.  Typically you check out a branch, which overwrites the files on disk to match the files as they exist in the latest commit of the branch.  However, you can check out other versions of files as well&lt;/p&gt;

&lt;p&gt;Uncommitted changes can be copied and saved for later by creating a &lt;em&gt;stash&lt;/em&gt;.  A stash is kind of like an unnamed commit - it again points to specific files at a certain point in time, but it doesn&#39;t exist in a branch. Stashed changes can later be applied on top of your working copy.&lt;/p&gt;

&lt;p&gt;Overall, the Git data workflow looks like this:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/git-staging-workflow.png&#34; alt=&#34;Git blob&#34; /&gt;&lt;/p&gt;

&lt;h3 id=&#34;understanding-git-internals&#34;&gt;Understanding Git Internals&lt;/h3&gt;

&lt;p&gt;I really feel that &lt;strong&gt;understanding Git&#39;s internal data structures is critical to understanding how Git works and how to use it correctly&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Git tracks all content using SHA1 hashes of byte data.  Running any specific sequence of bytes through the hashing function calculates a specific hex string as a result:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-py&#34;&gt;from hashlib import sha1

sha1(&amp;quot;abcd&amp;quot;).hexdigest()
&#39;81fe8bfe87576c3ecb22426f8e57847382917acf&#39;

sha1(&amp;quot;abce&amp;quot;).hexdigest()
&#39;0a431a7631cabf6b11b984a943127b5e0aa9d687&#39;

readme = open(&amp;quot;README.md&amp;quot;, &amp;quot;rt&amp;quot;).read()
sha1(readme).hexdigest()
&#39;45257c0245c56a4d5990827b044f897c674c8512&#39;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Git hashes files and data structures, then stores them inside the &lt;code&gt;.git&lt;/code&gt; folder based on the hash:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;/my-project
  /.git
    /objects
      /00
      /01
      ...
      /81
        81fe8bfe87576c3ecb22426f8e57847382917acf
      /82
      ...
      /fe
      /ff
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Git has three primary internal data structures:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;blobs&lt;/em&gt; are file contents, and identified by a hash of the file&#39;s bytes&lt;/li&gt;
&lt;li&gt;&lt;em&gt;file trees&lt;/em&gt; associate folder and file names with file blobs, and are identified by a hash of the file tree data structure&lt;/li&gt;
&lt;li&gt;&lt;em&gt;commits&lt;/em&gt; contain metadata (author, timestamp, message), point to a specific file tree, and are identified by a hash of the commit data structure&lt;/li&gt;
&lt;/ul&gt;

&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Type&lt;/th&gt;
&lt;th&gt;Contains&lt;/th&gt;
&lt;th&gt;Identified By&lt;/th&gt;
&lt;th&gt;&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;

&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Blob&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;File contents&lt;/td&gt;
&lt;td&gt;Hash of the file&#39;s bytes&lt;/td&gt;
&lt;td&gt;&lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/object-blob.png&#34; alt=&#34;Git blob&#34; /&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;File tree&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Associates names and folder definitions with file blobs&lt;/td&gt;
&lt;td&gt;Hash of the file tree data structure&lt;/td&gt;
&lt;td&gt;&lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/object-tree.png&#34; alt=&#34;Git file tree&#34; /&gt;&lt;/td&gt;
&lt;/tr&gt;

&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Commit&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Metadata for author, commit timestamps, and message&lt;/td&gt;
&lt;td&gt;Hash of the commit data structure&lt;/td&gt;
&lt;td&gt;&lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/object-commit.png&#34; alt=&#34;Git commit&#34; /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;

&lt;p&gt;A file tree may point to multiple other file trees for subfolders:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/objects-example.png&#34; alt=&#34;Git nested file trees&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Commit objects themselves form a linked list, which points backwards to earlier commits based on their hashes: &lt;code&gt;A &amp;lt;- B &amp;lt;- C &amp;lt;- D&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/commit-list.png&#34; alt=&#34;Git commit linked list&#34; /&gt;&lt;/p&gt;

&lt;p&gt;A Git &amp;quot;ref&amp;quot; is a name label that points to a specific commit.  Branches are names associated with a given ref, where each time a new commit is made, the ref is updated to point to that latest commit.  So, you can start from the branch ref pointer, then walk backwards through the chain of commits to see the history.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/branch-pointer-2.png&#34; alt=&#34;Git branch pointers&#34; /&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;HEAD&lt;/code&gt; is a ref that points to &amp;quot;whatever the current active commit&amp;quot; is.  Normally this is the same as the current branch pointer, but if you check out a specific earlier commit, you get the ever-popular warning about a &amp;quot;detached &lt;code&gt;HEAD&lt;/code&gt;&amp;quot;.  This just means that &lt;code&gt;HEAD&lt;/code&gt; is pointing to a specific commit instead of a branch, and if you make any new commits, they won&#39;t be part of any branch.&lt;/p&gt;

&lt;p&gt;Because commits are a linked list based on hashes, and the hashes are based on byte contents of files and other structures, changing any one bit in an earlier commit would have a ripple effect - every hash of each commit after that would be different.&lt;/p&gt;

&lt;p&gt;Git commit objects are &lt;em&gt;immutable&lt;/em&gt; - once created, they cannot actually be changed. This means that you can&#39;t change history, exactly - you can only create an alternate history.&lt;/p&gt;

&lt;h2 id=&#34;git-tools&#34;&gt;Git Tools&lt;/h2&gt;

&lt;p&gt;I&#39;ve seen a lot of arguments about whether it&#39;s better to use a Git GUI tool, or use Git from the command line.  To those people, I say: &lt;strong&gt;why not both?&lt;/strong&gt; :)&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/why-not-both.gif&#34; alt=&#34;Why not both?&#34; /&gt;&lt;/p&gt;

&lt;p&gt;I find that &lt;strong&gt;having a Git GUI tool is absolutely invaluable&lt;/strong&gt;.  It makes visualizing the state of the repository and its branches much easier, and many operations are &lt;em&gt;way&lt;/em&gt; simpler via a GUI.  For example, I can view the diffs for many pieces of a file at once, and selectively add specific changes to the staging area by clicking &amp;quot;Add Hunk&amp;quot; or CTRL-clicking a few lines to select them and clicking &amp;quot;Add Lines&amp;quot;. This is much simpler and more intuitive than trying to use Git&#39;s &amp;quot;patch editing&amp;quot; text UI to manipulate pieces of changes.  Interactive rebasing is also &lt;em&gt;much&lt;/em&gt; easier to do via a GUI.  I can&#39;t remember what the different options like &amp;quot;pick&amp;quot; mean, but it&#39;s straightforward to use a GUI listview with arrow buttons that lets you reorder commits and squash them together.&lt;/p&gt;

&lt;p&gt;On the other hand, &lt;strong&gt;it&#39;s often faster to create or switch branches from the CLI&lt;/strong&gt;.  You can add all changed files to the staging area with a single command of &lt;code&gt;git add -u&lt;/code&gt;.  And of course, if you are using a remote system via SSH, you probably do only have the Git CLI available.&lt;/p&gt;

&lt;p&gt;So, &lt;strong&gt;I use &lt;em&gt;both&lt;/em&gt; a Git GUI, &lt;em&gt;and&lt;/em&gt; the CLI, based on what tasks I&#39;m doing&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I primarily use &lt;a href=&#34;https://sourcetreeapp.com/&#34;&gt;Atlassian SourceTree&lt;/a&gt; (Win, Mac).  It&#39;s very powerful, with a lot of options, and has a good built-in UI for &lt;a href=&#34;#interactive-rebasing&#34;&gt;interactive rebasing&lt;/a&gt;.  It also happens to be free.  The biggest downside is that it doesn&#39;t have a way to view the contents of the repo file tree as of a given commit.&lt;/p&gt;

&lt;p&gt;Other Git tools I&#39;ve used in some form include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://gitextensions.github.io/&#34;&gt;Git Extensions for Windows&lt;/a&gt; (Win): integrates with Windows Explorer to let you perform Git operations from the filesystem.  I mostly use this to do a quick view of a given file&#39;s history if I happen to be browsing the folder contents of the repo.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://git-fork.com/&#34;&gt;Git Fork&lt;/a&gt; (Win, Mac): excellent UI design, and does have an interactive rebase UI. Recently switched from being free to $50, but likely worth paying for.&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.sublimemerge.com/&#34;&gt;Sublime Merge&lt;/a&gt; (Win, Mac, Linux): from the makers of Sublime Text. Fewer options and tool integrations, but very snappy. Tells you what CLI operations it&#39;s doing when you try to push or pull, so it expects familiarity with the CLI. $100, but will run for a while with nag messages.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There&#39;s also &lt;a href=&#34;https://www.git-tower.com/windows&#34;&gt;Tower&lt;/a&gt; (Win, Mac) and &lt;a href=&#34;https://www.gitkraken.com/git-client&#34;&gt;Git Kraken&lt;/a&gt; (Win, Mac, Linux), which have slick UIs but require yearly subscriptions, and &lt;a href=&#34;https://git-scm.com/downloads/guis&#34;&gt;a laundry list of other smaller Git GUIs&lt;/a&gt;.  There&#39;s even &amp;quot;text-based UI&amp;quot; tools like &lt;a href=&#34;https://github.com/jesseduffield/lazygit&#34;&gt;&lt;code&gt;lazygit&lt;/code&gt;&lt;/a&gt;, &lt;a href=&#34;https://github.com/extrawurst/gitui&#34;&gt;&lt;code&gt;gitui&lt;/code&gt;&lt;/a&gt;, and &lt;a href=&#34;https://github.com/chriswalz/bit&#34;&gt;&lt;code&gt;bit&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;All major IDEs have Git integration.  &lt;a href=&#34;https://www.jetbrains.com/idea/features/&#34;&gt;JetBrains IDEs like IntelliJ and WebStorm have excellent Git capabilities&lt;/a&gt;.  &lt;a href=&#34;https://code.visualstudio.com/docs/editor/versioncontrol&#34;&gt;VS Code has adequate Git integration&lt;/a&gt;, but really needs &lt;a href=&#34;https://marketplace.visualstudio.com/items?itemName=donjayamanne.git-extension-pack&#34;&gt;additional extensions like Git History and GitLens&lt;/a&gt; to be useful.&lt;/p&gt;

&lt;p&gt;I also really prefer using external diff tools for comparing complete files, or fixing merge conflicts.  I personally use &lt;a href=&#34;https://www.scootersoftware.com/&#34;&gt;Beyond Compare&lt;/a&gt; as my external diff tool, and &lt;a href=&#34;https://sourcegear.com/diffmerge/&#34;&gt;DiffMerge&lt;/a&gt; as my conflict resolution diffing tool.&lt;/p&gt;

&lt;h2 id=&#34;git-techniques&#34;&gt;Git Techniques&lt;/h2&gt;

&lt;h3 id=&#34;improving-cli-logging&#34;&gt;Improving CLI Logging&lt;/h3&gt;

&lt;p&gt;The default &lt;code&gt;git log&lt;/code&gt; output is ugly and hard to read.  Whenever I start using Git on a new machine, the very first thing I do is browse to &lt;a href=&#34;https://coderwall.com/p/euwpig/a-better-git-log&#34;&gt;https://coderwall.com/p/euwpig/a-better-git-log&lt;/a&gt; and copy-paste the instructions for creating a &lt;code&gt;git lg&lt;/code&gt; alias to set up a much pretter CLI logging view that shows the branch and commit message history:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;git config --global alias.lg &amp;quot;log --color --graph --pretty=format:&#39;%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)&amp;lt;%an&amp;gt;%Creset&#39; --abbrev-commit&amp;quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;That gives us this view whenever we run &lt;code&gt;git lg&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/git-lg.jpg&#34; alt=&#34;git lg output&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Note that &lt;a href=&#34;https://www.atlassian.com/git/tutorials/git-log&#34;&gt;&lt;code&gt;git log&lt;/code&gt; accepts a variety of filtering options&lt;/a&gt;, including text strings, dates, branches, etc.&lt;/p&gt;

&lt;h3 id=&#34;preparing-commits-in-pieces&#34;&gt;Preparing Commits in Pieces&lt;/h3&gt;

&lt;p&gt;I&#39;ve seen comments that complain that the Git staging area is confusing.  To me, &lt;strong&gt;the staging area is one of the most valuable features of Git&lt;/strong&gt; - it lets me carefully craft commits that contain &lt;em&gt;only&lt;/em&gt; the code that belongs together.&lt;/p&gt;

&lt;p&gt;When I work on a task, I frequently end up modifying multiple files before I&#39;m ready to make a commit.  However, &lt;strong&gt;the changes might logically belong in several smaller commits instead of one big commit&lt;/strong&gt;.  If I do &lt;code&gt;git add some-file&lt;/code&gt;, it adds &lt;em&gt;all&lt;/em&gt; the current changes in the file to the staging area.  Instead, &lt;strong&gt;I often want to stage just a couple sections from file A, and a couple sections from file B, and maybe all of file C, because those are the changes that should go together in one commit&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;You can do this from the commandline using the &lt;code&gt;git add -p&lt;/code&gt; flag, which brings up a text UI that lets you view each &amp;quot;hunk&amp;quot; of changes in a file, and decide whether to stage that hunk or not. However, &lt;strong&gt;I strongly recommend using a Git GUI tool like SourceTree for adding pieces of files&lt;/strong&gt;, because it&#39;s easier to click &amp;quot;Add Hunk&amp;quot; or CTRL-click a couple lines and click &amp;quot;Add Lines&amp;quot; than it is try to decipher what the command abbreviations in the text UI actually mean:&lt;/p&gt;

&lt;div style=&#34;display: flex; flex-wrap: wrap;&#34;&gt;
  &lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/git-add-hunk.jpg&#34; style=&#34;max-width: 560px;&#34; width=&#34;560px&#34; /&gt;
  &lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/sourcetree-stage-hunks.gif&#34; style=&#34;max-width: 560px;&#34; width=&#34;560px&#34; /&gt;
&lt;/div&gt;

&lt;p&gt;Once you&#39;ve got these pieces added, you can make a commit with just chose changes, and repeat the process for the next commit.  This is a key part of the &amp;quot;making small commits&amp;quot; practice that I cover below.&lt;/p&gt;

&lt;p&gt;On the flip side, sometimes you &lt;em&gt;do&lt;/em&gt; just want to add everything that&#39;s been changed at once.  In that case, the fast way is to run &lt;code&gt;git add -u&lt;/code&gt; from the command line, which adds all modified files to the staging area.&lt;/p&gt;

&lt;h3 id=&#34;stashing-changes&#34;&gt;Stashing Changes&lt;/h3&gt;

&lt;p&gt;Stashes are most useful when you&#39;ve got some modified files that aren&#39;t committed, and need to set those aside to work on a different branch for a while.  Git&#39;s list of stashes acts like a stack data structure, but you can also supply names for stash entries when you create them.  Creating stash entries normally resets the modified files back to the latest commit, but you can choose to leave the modifications in place.&lt;/p&gt;

&lt;p&gt;From the CLI, the main options are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git stash&lt;/code&gt;: save a copy of local changes for later reuse, and clears the working directory/index

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git stash push&lt;/code&gt;: creates a new stash entry&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git stash pop&lt;/code&gt; applies changes from the top stash entry and removes it&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git stash apply stash@{2}&lt;/code&gt;: applies changes from the third stash entry&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git stash -p&lt;/code&gt;: choose specific pieces to stash&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git checkout stash@{2} -- someFile&lt;/code&gt;: retrieve a specific file contents from the stash&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But, this is another situation where it&#39;s particularly useful to use a GUI instead.  It&#39;s easier to just click a &amp;quot;Stash&amp;quot; button in a toolbar and type in a name for the entry to create one, or to expand a &amp;quot;Stashes&amp;quot; section of a treeview, right-click an entry, and &amp;quot;Apply Stash&amp;quot; to apply a stash.&lt;/p&gt;

&lt;h3 id=&#34;working-with-branches&#34;&gt;Working with Branches&lt;/h3&gt;

&lt;h4 id=&#34;creating-and-switching-branches&#34;&gt;Creating and Switching Branches&lt;/h4&gt;

&lt;p&gt;Git has a bunch of different commands for working with branches. The most common way to create a branch is actually with &lt;strong&gt;&lt;code&gt;git checkout -b NAME_OF_NEW_BRANCH&lt;/code&gt;&lt;/strong&gt;.  That creates a new branch, starting from the latest commit on the current branch, and switches to it.&lt;/p&gt;

&lt;p&gt;You can also use &lt;code&gt;git checkout NAME_OF_EXISTING_BRANCH&lt;/code&gt; (without the &lt;code&gt;-b&lt;/code&gt; flag) to switch to an existing branch.&lt;/p&gt;

&lt;p&gt;There&#39;s many other branching commands - see &lt;a href=&#34;https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging&#34;&gt;the Git docs&lt;/a&gt; and other pages like &lt;a href=&#34;https://devhints.io/git-branch&#34;&gt;this Git branching cheatsheet&lt;/a&gt; for lists of commands and options.&lt;/p&gt;

&lt;h4 id=&#34;fetching-pushing-and-pulling-branches&#34;&gt;Fetching, Pushing, and Pulling Branches&lt;/h4&gt;

&lt;p&gt;Most Git network operation commands accept the name of the remote repo to talk to, but assume that you want to talk to the &lt;code&gt;origin&lt;/code&gt; remote repo by default if you don&#39;t specify a remote name.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git fetch&lt;/code&gt; tells Git to contact another repo, and download copies of all commits that the local repo doesn&#39;t have stored.  This includes information on branches in the remote repo as well.&lt;/p&gt;

&lt;p&gt;Once your repo has downloaded the list of remote branches, you can create a &lt;em&gt;local&lt;/em&gt; branch based on the remote branch&#39;s name, with &lt;code&gt;git checkout NAME_OF_REMOTE_BRANCH&lt;/code&gt;.  Git will create a new branch that points to the same commit.  It also sets up the local branch to &lt;em&gt;track&lt;/em&gt; the remote branch, which means that any pushes from the local branch will update the remote branch.&lt;/p&gt;

&lt;p&gt;Later, you can update the remote branch with the new commits you made locally, with &lt;code&gt;git push&lt;/code&gt;.  You can also push local branches taht the remote repo doesn&#39;t know about yet.&lt;/p&gt;

&lt;p&gt;If the remote branch has commits you don&#39;t have in your local branch, &lt;code&gt;git pull&lt;/code&gt; will both fetch the set of new commits into your local repo, &lt;em&gt;and&lt;/em&gt; update your local branch to contain those commits.&lt;/p&gt;

&lt;p&gt;If you rewrite history on your local branch so that it&#39;s different than the remote branch, a &lt;code&gt;git push&lt;/code&gt; attempt will fail with an error. You can &lt;em&gt;force push&lt;/em&gt; , which will hard-update the remote branch to use these commits instead.  &lt;strong&gt;Force pushing is semi-dangerous, depending on workflow.&lt;/strong&gt;  If someone else pulled the old history, and you force-push, now they have a conflict to deal with.  Force pushing is a valuable tool if you need it, and can be a legitimate solution to fixing problems or repeatedly updating a PR, but should be used cautiously.  Think of it as a chainsaw - if you need it, you need it, you just have to be very careful when using it :)&lt;/p&gt;

&lt;h4 id=&#34;merging-branches&#34;&gt;Merging Branches&lt;/h4&gt;

&lt;p&gt;&lt;em&gt;Merging&lt;/em&gt; allows you to take changes and history that exist on branch B, and combine them into the changes on your current branch A.  The assumption is that both branches have a common set of ancestor commits, and two different sets of changes (either to different files, or even the same files).  Merging creates a new &amp;quot;merge commit&amp;quot; on the current branch that has all of the changes together in one spot.  This is used to let developers collaborate by writing code separately, but combine their changes together.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/merging-after.png&#34; alt=&#34;Merging branches - before&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Merging is done with &lt;code&gt;git merge OTHER_BRANCH_NAME&lt;/code&gt;, which tells Git to merge from the other branch into the current branch.&lt;/p&gt;

&lt;p&gt;If the changes on the two branches interfere with each other, there&#39;s a merge conflict.  Git will mark the file with text strings indicating the two mismatched sections.  It&#39;s up to you to fix the problem, save the corrected file, add it, and finish the merge commit.  I like using SourceGear DiffMerge as a GUI tool for fixing conflicts, but VS Code also does a nice job of highlighting conflict markers in files and offering hover buttons to pick one side or the other.&lt;/p&gt;

&lt;h4 id=&#34;feature-branch-strategies&#34;&gt;Feature Branch Strategies&lt;/h4&gt;

&lt;p&gt;Most teams use some kind of a &amp;quot;feature branch&amp;quot; strategy for development.  They have a primary development branch such as &lt;code&gt;main&lt;/code&gt;, &lt;code&gt;master&lt;/code&gt;, or &lt;code&gt;develop&lt;/code&gt;.  Any time a developer starts work on a new task, they create a new branch based on the primary branch, and often using the name and ID of a task/issue as the branch name: &lt;code&gt;git checkout -b feature/myapp-123-build-todos-list&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The developer works on their feature for a while.  Once the work is complete, they push the branch up to the team&#39;s central repository, other team members review the changes, the developer makes any needed fixes from the review, and then the feature branch is merged back into the primary development branch.&lt;/p&gt;

&lt;p&gt;Developers may need to pull down changes that have been added to the primary branch, then &amp;quot;merge down&amp;quot; from the primary branch into their feature branch.  Merging the feature branch back into the primary branch is referred to as &amp;quot;merging up&amp;quot;.&lt;/p&gt;

&lt;h4 id=&#34;pull-requests&#34;&gt;Pull Requests&lt;/h4&gt;

&lt;p&gt;If you&#39;ve worked with Git at all, you&#39;ve probably heard the term &amp;quot;pull request&amp;quot; (also know as a &amp;quot;PR&amp;quot; for short, or occasionally &amp;quot;merge request&amp;quot;) before.  Strictly speaking, a &amp;quot;pull request&amp;quot; isn&#39;t even a Git concept - it&#39;s a merging workflow that is built on top of Git by repository hosting sites and tools like Github, Gitlab, and Bitbucket.&lt;/p&gt;

&lt;p&gt;Pull Requests are an approach to doing code reviews and handling merging at the central Git repo/server level.  This is typically associated with using feature branches.  A developer pushes up their completed feature branch, and creates a PR that will merge &lt;code&gt;some-feature&lt;/code&gt; into &lt;code&gt;main&lt;/code&gt;.  Other devs can look at the page for the PR, see the file diffs, and leave comments on specific lines suggesting changes.  The feature dev makes more commits based on those suggestions, pushes them up, and the PR is updated to reflect the changes.  After other team members approve, the PR can be merged and the feature branch can be deleted.&lt;/p&gt;

&lt;h4 id=&#34;updating-branches-in-the-background&#34;&gt;Updating Branches in the Background&lt;/h4&gt;

&lt;p&gt;Normally, the main way to update a local copy of a branch is to &lt;code&gt;git checkout some-branch&lt;/code&gt; and then &lt;code&gt;git pull&lt;/code&gt;.  But, if I&#39;m working on a feature branch, I often have unsaved changes and don&#39;t want to switch over to the main branch just to do a pull.&lt;/p&gt;

&lt;p&gt;There&#39;s &lt;a href=&#34;https://stackoverflow.com/a/17722977/62937&#34;&gt;&lt;strong&gt;a really useful trick for doing a &amp;quot;background pull&amp;quot; of a branch without checking it out&lt;/strong&gt;&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;git fetch &amp;lt;remote&amp;gt; &amp;lt;remoteBranch&amp;gt;:&amp;lt;localBranch&amp;gt;&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;So, say I&#39;m on &lt;code&gt;features/some-feature&lt;/code&gt;, and I want to update my &lt;code&gt;main&lt;/code&gt; branch without switching to it.  Typically the local branch and remote branch have the same name.  So, I can run:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;code&gt;git fetch origin main:main&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;and Git will download any new commits on the remote &lt;code&gt;origin/main&lt;/code&gt; branch, then update my local &lt;code&gt;main&lt;/code&gt; branch to have those commits too.&lt;/p&gt;

&lt;h3 id=&#34;rewriting-git-history&#34;&gt;Rewriting Git History&lt;/h3&gt;

&lt;p&gt;There&#39;s a variety of ways to alter the history in a Git repository.  Each technique is useful in different situations, and these are often valuable for fixing earlier problems.  As mentioned earlier, Git commits are immutable, so you can never actually modify them - you can only &lt;em&gt;replace&lt;/em&gt; commits with new ones.  So, &lt;strong&gt;when we &amp;quot;rewrite history&amp;quot;, we&#39;re actually creating an &amp;quot;alternate history&amp;quot; instead&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;It&#39;s critical that &lt;strong&gt;you should only ever rewrite history that is still local to your own repository and has never been pushed up to another repository!&lt;/strong&gt;  As long as commits haven&#39;t been pushed, no one else cares about them, and you can rewrite them to your heart&#39;s content.  But, once they&#39;ve been pushed, someone else&#39;s Git repo clone may be relying on the old history, and changing that history will likely cause conflicts for them.&lt;/p&gt;

&lt;h4 id=&#34;amending-commits&#34;&gt;Amending Commits&lt;/h4&gt;

&lt;p&gt;The easiest technique for rewriting history is to &amp;quot;amend&amp;quot; the latest commit.&lt;/p&gt;

&lt;p&gt;Amending a commit really means replacing it with a slightly different one.  This can be done via &lt;code&gt;git commit --amend&lt;/code&gt;, or a corresponding option in a GUI tool:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/git-amend.png&#34; alt=&#34;Amending Git commits&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Technically, the old commit still exists in Git&#39;s storage, but the current branch ref now points to the newly created commit instead.&lt;/p&gt;

&lt;h4 id=&#34;resetting-branches&#34;&gt;Resetting Branches&lt;/h4&gt;

&lt;p&gt;Since branch refs are pointers to a given commit, we can &lt;em&gt;reset&lt;/em&gt; a branch by updating the ref to point to an earlier commit.  This is typically used to roll back some of the commits you made.&lt;/p&gt;

&lt;p&gt;When you reset a branch, you have three options for what happens to the files on disk and in the staging area:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;git reset&lt;/code&gt;: move a branch pointer to point to a different commit

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;--soft&lt;/code&gt;: keep the current files on disk and in the staging area&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--mixed&lt;/code&gt;: keep the current files on disk, but clear the staging area&lt;/li&gt;
&lt;li&gt;&lt;code&gt;--hard&lt;/code&gt;: clear the staging area &lt;em&gt;and&lt;/em&gt; make the working directory look exactly like this specific commit&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So, &lt;code&gt;git reset --soft&lt;/code&gt; is fairly &amp;quot;safe&amp;quot; to do, because it doesn&#39;t change any files on disk.  &lt;code&gt;git reset --hard&lt;/code&gt; is &amp;quot;dangerous&amp;quot;, because it will wipe out any files that were changed during these commits &lt;em&gt;or&lt;/em&gt; that haven&#39;t been committed yet, and replace them all with the files from this exact commit.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git reset&lt;/code&gt; requires a commit identifier as an argument.  This could be a specific commit hash ( &lt;code&gt;git reset ABCD1234&lt;/code&gt; ), or &lt;a href=&#34;https://devhints.io/git-revisions&#34;&gt;some other revision identifier&lt;/a&gt;.  You can even update your current branch to point to the same commit as a different branch ( &lt;code&gt;git reset --hard some-other-branch&lt;/code&gt; ).&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/reset-commit.svg&#34; alt=&#34;Resetting Git commits&#34; /&gt;&lt;/p&gt;

&lt;h4 id=&#34;rebasing-branches&#34;&gt;Rebasing Branches&lt;/h4&gt;

&lt;p&gt;&amp;quot;Rebasing&amp;quot; is a technique that is an alternative to merging for updating one branch with another&#39;s changes.  Instead of combining the two sets of changes directly, rebasing rewrites history to act as if the current branch was created &lt;em&gt;now&lt;/em&gt;, off the latest commits on the source branch, instead of starting from the earlier commits.  Similar to merging, this is done with &lt;code&gt;git rebase OTHER_BRANCH_NAME&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Imagine that the &lt;code&gt;main&lt;/code&gt; branch has commits &lt;code&gt;A &amp;lt;- B&lt;/code&gt; to start with, and we make a feature branch starting from commit B.  Now, someone else merges some more work into &lt;code&gt;main&lt;/code&gt;, giving it commits &lt;code&gt;A &amp;lt;- B &amp;lt;- C &amp;lt;- D&lt;/code&gt;.  If we rebase our feature branch against &lt;code&gt;main&lt;/code&gt;, it&#39;s kind of like cutting off the line of our feature branch, transplanting it to the end, and pretending we really started this branch after commit &lt;code&gt;D&lt;/code&gt; instead of &lt;code&gt;B&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/rebase.svg&#34; alt=&#34;Resetting Git commits&#34; width=&#34;800px&#34; /&gt;&lt;/p&gt;

&lt;h4 id=&#34;reverting-commits&#34;&gt;Reverting Commits&lt;/h4&gt;

&lt;p&gt;Resetting a branch effectively throws away the newer commits.  What if we want to undo the changes in an earlier commit, but keep the history since then?&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Reverting&lt;/em&gt; a commit with &lt;code&gt;git revert&lt;/code&gt; creates a new commit that has the opposite changes of the commit you specified.  It doesn&#39;t remove the original commit, so the history isn&#39;t actually modified - it just inverts the changes.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/revert-concept.png&#34; alt=&#34;Reverting Git commits&#34; /&gt;&lt;/p&gt;

&lt;h4 id=&#34;cherry-picking&#34;&gt;Cherry-Picking&lt;/h4&gt;

&lt;p&gt;Cherry-picking allows you to copy the &lt;em&gt;changes&lt;/em&gt; in specific commits, and apply those as new commits onto a different branch.  For example, maybe there&#39;s an urgent patch that has to be created directly onto a hotfix branch and deployed to production, but you need to also make sure that &lt;code&gt;main&lt;/code&gt; has that commit as well.  You can cherry-pick the individual commit from the hotfix branch over onto &lt;code&gt;main&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git cherry-pick&lt;/code&gt; accepts either a single commit reference, or a commit range.  Note that the range excludes the first commit you list.  if I run &lt;code&gt;git cherry-pick A..E&lt;/code&gt;, then it will copy commits &lt;code&gt;B,C,D,E&lt;/code&gt; over onto this branch.  This creates new commits with new hashes (because the timestamps and parent commits are different), but preserves the diffs and commit metadata.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/rewriting_history_004.png&#34; alt=&#34;Reverting Git commits&#34; /&gt;&lt;/p&gt;

&lt;h4 id=&#34;interactive-rebasing&#34;&gt;Interactive Rebasing&lt;/h4&gt;

&lt;p&gt;&amp;quot;Rebasing&amp;quot; involves rewriting the entire history of a branch.  There is a variation on this called &amp;quot;interactive rebasing&amp;quot;, which allows you to selectively modify earlier commits on a branch.  This is done with &lt;code&gt;git rebase -i STARTING_COMMIT&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Interactive rebasing lets you perform several different types of modifications.  You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Edit the message for a commit&lt;/li&gt;
&lt;li&gt;Reorder commits&lt;/li&gt;
&lt;li&gt;Squash multiple commits together&lt;/li&gt;
&lt;li&gt;Remove commits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After you specify the desired changes to the commit history, Git will execute the modifications you listed, and update all commits after the starting point accordingly.  As with other history rewriting operations, this always produces a new set of commits after any changed commit, with new hashes even if the rest of the contents haven&#39;t changed due to the parent commits changing.&lt;/p&gt;

&lt;p&gt;Running an interactive rebase from the CLI brings up a list of all commits after the starting commit in your text editor, along with a column of odd command names like &amp;quot;pick&amp;quot; and &amp;quot;squash&amp;quot;.  You rework the commits by actually modifying the text in the file, and then saving and exiting.  For example, if you want to swap a couple commits, you&#39;d cut one of the text lines and paste it in a different location.&lt;/p&gt;

&lt;p&gt;I find this very unintuitive to work with, so &lt;strong&gt;I &lt;em&gt;strongly&lt;/em&gt; recommend using a Git GUI for any interactive rebase operations&lt;/strong&gt;.  SourceTree and Fork have pretty good UIs for performing interactive rebasing.&lt;/p&gt;

&lt;div style=&#34;display: flex; flex-wrap: wrap;&#34;&gt;
  &lt;div style=&#34;display: flex; flex-direction: column;&#34;&gt;
    &lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/rewriting_history_002.png&#34; style=&#34;max-width: 560px;&#34; width=&#34;560px&#34; /&gt;
    &lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/rewriting_history_003.png&#34; style=&#34;max-width: 560px;&#34; width=&#34;560px&#34; /&gt;
  &lt;/div&gt;
  &lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/sourcetree_interactive_rebase.png&#34; style=&#34;max-width: 560px;&#34; width=&#34;560px&#34; /&gt;
&lt;/div&gt;

&lt;h4 id=&#34;reflog&#34;&gt;Reflog&lt;/h4&gt;

&lt;p&gt;It&#39;s actually very hard to completely wipe out your Git commits and permanently lose work.  Even if you do a &lt;code&gt;git reset --hard&lt;/code&gt; and the commits &lt;em&gt;appear&lt;/em&gt; to have vanished, Git still has a copy of those commits saved internally.&lt;/p&gt;

&lt;p&gt;If you do end up in a situation where you can&#39;t see those commits referenced from any tag or branch, you can use the Git &lt;em&gt;reflog&lt;/em&gt; to look back and find them again.  The reflog shows all commits, no matter what branch they&#39;re on or whether there&#39;s still a meaningful pointer to that commit.  That way you can check them out again, create a new tag or branch pointing to those commits, or at least see the diffs.&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/reflog.png&#34; alt=&#34;Git reflog&#34; /&gt;&lt;/p&gt;

&lt;h4 id=&#34;advanced-history-rewriting&#34;&gt;Advanced History Rewriting&lt;/h4&gt;

&lt;p&gt;Finally, Git supports some very advanced tools for rewriting history at the whole repository level.  In particular, &lt;code&gt;git filter-branch&lt;/code&gt; lets you perform tasks like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;rewriting file names and paths in the history (example: changing files in &lt;code&gt;./src&lt;/code&gt; so that they now appear to be in the repo root)&lt;/li&gt;
&lt;li&gt;creating a new repo that contains just certain folders from the original, but with all their history&lt;/li&gt;
&lt;li&gt;rewriting actual file contents in many historical commits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;git filter-branch&lt;/code&gt; &lt;em&gt;is&lt;/em&gt; notoriously slow, so there&#39;s other external tools that can perform similar tasks.  While I haven&#39;t used it, &lt;a href=&#34;https://github.com/newren/git-filter-repo&#34;&gt;https://github.com/newren/git-filter-repo&lt;/a&gt; claims to be able to run the same kinds of operations much more quickly, and is apparently now even recommended by the actual Git docs.&lt;/p&gt;

&lt;p&gt;Sometimes repos end up with very large files cluttering the history, and you want to rewrite the history to pretend those files never existed.  A tool called &lt;a href=&#34;https://rtyley.github.io/bfg-repo-cleaner/&#34;&gt;the BFG Repo Cleaner&lt;/a&gt; does a good job of that.&lt;/p&gt;

&lt;p&gt;If these existing tools don&#39;t do what you need, you can always write your own.  &lt;a href=&#34;https://blog.isquaredsoftware.com/2018/11/git-js-history-rewriting/&#34;&gt;I once wrote a set of Python-based tools to rewrite the JS source for for an entire repository with multiple years of history&lt;/a&gt;, including optimizing it to run in just a few hours.&lt;/p&gt;

&lt;p&gt;These tools are very powerful and should not be something you use for day-to-day tasks.  Think of them as fire extinguishers. You hope you never need to use them, but it&#39;s good to have it sitting around in case something happens.&lt;/p&gt;

&lt;h2 id=&#34;git-patterns-and-best-practices&#34;&gt;Git Patterns and Best Practices&lt;/h2&gt;

&lt;p&gt;So now that we&#39;ve covered a bunch of commands and technical details, how do you actually &lt;em&gt;use&lt;/em&gt; Git well?  Here&#39;s the things that I&#39;ve found to be most helpful:&lt;/p&gt;

&lt;h3 id=&#34;write-good-commit-messages&#34;&gt;Write Good Commit Messages&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;It&#39;s critical to write good commit messages&lt;/strong&gt;.  It&#39;s not just a chore to satisfy the Git tools. You&#39;re leaving notes to any future developers on this project as to what changes were made, or even more importantly, &lt;em&gt;why&lt;/em&gt; those changes were made.  Anyone can look at a set of diffs from a commit and see the changed lines, but without a good commit message, you may have no idea what the reason was to make those changes in the first place.&lt;/p&gt;

&lt;p&gt;There&#39;s lots of good articles out there discussing rules for writing commit messages, with plenty of good advice.  I personally don&#39;t care so much about things like &amp;quot;max 72 characters per line&amp;quot; or &amp;quot;use present tense for the top line and past tense for other lines&amp;quot;, although there&#39;s valid reasons to do those things.  To me, the critical rules are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Always start the commit message with a relevant issue tracker ID number&lt;/strong&gt; if there is one. That way you can always go back to the issue tracker later to see more details on what the specific task was supposed to be.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;First line should be a short high-level summary of the &lt;em&gt;intent&lt;/em&gt; of the changes&lt;/strong&gt;.  This line of the message is what will be shown in any Git history log display, so it needs to both fit in one line, and clearly describe the commit overall. Aim more for the &lt;em&gt;purpose&lt;/em&gt; of the changes than a specific list of &amp;quot;what changed&amp;quot; in this line.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;If you have any further details, add a blank line, then write additional paragraphs or bullet points&lt;/strong&gt;.  Write as much as you want here!  This section will usually be collapsed by default in a Git UI, but can be expanded to show more details.  I&#39;ve seen some excellent commit messages that were multiple paragraphs long, and they provided important context for why changes were being made.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;A typical example of this format would look like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;MYAPP-123: Rewrite todos slice logic for clarity

- Added Redux Toolkit
- Replaced handwritten reducer with `createSlice`.  This simplified the logic considerably, 
  because we can now use Immer and it auto-generates the action creators for us.
- Updated `TodosList` to use the selectors generated by the slice.
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;make-small-focused-commits&#34;&gt;Make Small, Focused Commits&lt;/h3&gt;

&lt;p&gt;This goes hand-in-hand with the advice to write good commit messages.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Commits should be relatively small and self-contained, conceptually&lt;/strong&gt;.  One commit might touch several files, but the changes in those files should be closely related to each other.  There&#39;s multiple reasons for this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It makes it easier to describe the changes in the commit&lt;/li&gt;
&lt;li&gt;It&#39;s easier to look at that one commit and see what changes it includes&lt;/li&gt;
&lt;li&gt;If the commit needs to be reverted later, there&#39;s fewer other changes that would be affected&lt;/li&gt;
&lt;li&gt;When someone looks at the line-by-line history, there will be more specific comments associated with each line (&amp;quot;Fixed bug X&amp;quot; instead of &amp;quot;Made a bunch of changes&amp;quot;, etc)&lt;/li&gt;
&lt;li&gt;It&#39;s easier to bisect the commit history and narrow down what changes might have caused a particular bug&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, say I&#39;m adding a new JS library to a project.  I would make one commit that just updates &lt;code&gt;package.json&lt;/code&gt; and &lt;code&gt;yarn.lock&lt;/code&gt;, then put the initial code changes using that library into a separate commit.  You can see an example of this commit approach in &lt;a href=&#34;https://github.com/reduxjs/redux-fundamentals-example-app/commits/tutorial-steps&#34;&gt;the commits for the &amp;quot;Redux Fundamentals&amp;quot; tutorial example app&lt;/a&gt; I wrote.&lt;/p&gt;

&lt;p&gt;To me, &lt;strong&gt;the commit history should &amp;quot;tell a story&amp;quot; of how a given task was accomplished&lt;/strong&gt;.  Someone should be able to read through the series of commits, whether it be during the PR review process or years down the road, and be able to understand my thought process for what changes I made and why I made them.&lt;/p&gt;

&lt;h3 id=&#34;clean-up-commit-history-before-pushing&#34;&gt;Clean Up Commit History Before Pushing&lt;/h3&gt;

&lt;p&gt;I frequently have to make &amp;quot;WIP&amp;quot; commits as I&#39;m working on a task.  Maybe I&#39;ve just made a bunch of edits, the code is now mostly working, and I want to record a checkpoint before I keep going.  Or, maybe I forgot to commit a particular bit of code, added it in another commit later, but it doesn&#39;t really belong as part of the &amp;quot;story&amp;quot; that I&#39;m telling.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I often use interactive rebase to clean up my commits before I push a branch for a PR&lt;/strong&gt;.  Just because I have some junk commits in my history locally doesn&#39;t mean that the rest of the world needs to know or care that was part of my actual progress for this task.  The &amp;quot;story&amp;quot; that I&#39;m telling with my commits is sort of the idealized version - ie, &amp;quot;let&#39;s pretend that I did this task perfectly without any mistakes along the way&amp;quot;.&lt;/p&gt;

&lt;h3 id=&#34;only-rewrite-unpushed-history&#34;&gt;Only Rewrite Unpushed History&lt;/h3&gt;

&lt;p&gt;As mentioned earlier: as long as a branch is still local and hasn&#39;t been pushed, it&#39;s fair game - rewrite it all you want!  Once it&#39;s been pushed, though, you should avoid rewriting it.&lt;/p&gt;

&lt;p&gt;The one main exception to that is if the branch is still up for PR, and you redo the history.  At that point, most likely no one depends on it yet, so you can get away with force-pushing the branch to update the PR.  (The React team does this frequently.)&lt;/p&gt;

&lt;h3 id=&#34;keep-feature-branches-short-lived&#34;&gt;Keep Feature Branches Short-Lived&lt;/h3&gt;

&lt;p&gt;There&#39;s no hard rule about how many lines of code or commits can be in a branch.  In general, though, try to keep feature branches relatively short-lived.  That way the size of the changes to merge in a PR is smaller, and it&#39;s less likely that you&#39;ll need to pull down changes from someone else.&lt;/p&gt;

&lt;p&gt;Some people argue about whether it&#39;s better to &lt;em&gt;merge&lt;/em&gt; feature branches back into the primary branch, or &lt;em&gt;rebase&lt;/em&gt; them when they&#39;re done to keep the main branch history &amp;quot;clean and linear&amp;quot;. I kinda like having merge commits, personally - I prefer seeing when things got merged in.  The important thing is to pick a convention as a team and stick with it.&lt;/p&gt;

&lt;h2 id=&#34;code-archeology-with-git&#34;&gt;Code Archeology with Git&lt;/h2&gt;

&lt;p&gt;So why do all these good commit practices matter?&lt;/p&gt;

&lt;p&gt;Say you&#39;re working in a codebase with multiple years of history.  One day, you&#39;re assigned a task to work on some portion of the codebase.  Maybe it&#39;s fixing a bug that just popped up, or adding a new feature.  You open up a file, and there&#39;s hundreds of lines of code inside.  You read through it, and it&#39;s kind of ugly - there&#39;s a bunch of extra conditions in the logic, and you&#39;re really not sure how it ended up this way.&lt;/p&gt;

&lt;p&gt;Reading through that file tells you &lt;em&gt;what&lt;/em&gt; the code does, &lt;em&gt;now&lt;/em&gt;.  Unless the file has a lot of good comments, there may not be much information for &lt;em&gt;why&lt;/em&gt; the code is like that, or &lt;em&gt;how&lt;/em&gt; it got that way.  We naturally have a tendency to assume that &amp;quot;whatever code is there currently must be correct&amp;quot;, but that&#39;s not always true :)&lt;/p&gt;

&lt;p&gt;That&#39;s where having a good Git history is critical.  Digging through a file&#39;s history can show you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who wrote each line of code&lt;/li&gt;
&lt;li&gt;When that code was changed, and what &lt;em&gt;other&lt;/em&gt; code changed at the same time&lt;/li&gt;
&lt;li&gt;What task the changes were part of&lt;/li&gt;
&lt;li&gt;What the intent was behind the change&lt;/li&gt;
&lt;li&gt;What the author was thinking at the time&lt;/li&gt;
&lt;li&gt;When a bug was introduced&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These can all be extremely valuable pieces of information when tracking down a bug or working on a feature.&lt;/p&gt;

&lt;h3 id=&#34;displaying-historical-file-changes&#34;&gt;Displaying Historical File Changes&lt;/h3&gt;

&lt;p&gt;There&#39;s a variety of ways to view the history of changes to a file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git log&lt;/code&gt; lets you look at the commits that affected a specific file.  IDEs and Git GUIs let you explore the history of a file as well, showing each commit its diffs, often including the ability to diff two arbitrary versions of a file.  Some Git GUIs also let you explore the entire repo file tree as of a specific commit.&lt;/p&gt;

&lt;p&gt;Git has a feature called &lt;code&gt;git blame&lt;/code&gt;, which prints the commit ID, author, and timestamp for each line. The CLI output is hard to read, but every good IDE has the ability to show file blame information next to the actual code in a file. IDEs typically enhance the blame information to show you more details on the author, the commit message, and the commits before and after this one:&lt;/p&gt;

&lt;p&gt;&lt;img src=&#34;https://blog.isquaredsoftware.com/images/2021-01-career-advice-git-usage/git-file-blame.png&#34; alt=&#34;VS Code file blame view&#34; /&gt;&lt;/p&gt;

&lt;p&gt;Github offers a &amp;quot;blame&amp;quot; view as well, and makes it easy to jump back to view an earlier version of the repo.  Github also lets you browse specific file versions and trees.  For example, &lt;a href=&#34;https://github.com/reduxjs/react-redux/tree/v7.1.2&#34;&gt;https://github.com/reduxjs/react-redux/tree/v7.1.2&lt;/a&gt; shows the React-Redux codebase as of tag &lt;code&gt;v7.1.2&lt;/code&gt;, and &lt;a href=&#34;https://github.com/reduxjs/react-redux/blob/5f495b23bcf3f03e0bee85fa5f7b9c2afc193457/src/components/connectAdvanced.js&#34;&gt;https://github.com/reduxjs/react-redux/blob/5f495b23bcf3f03e0bee85fa5f7b9c2afc193457/src/components/connectAdvanced.js&lt;/a&gt; shows that exact file version.  (Press &lt;code&gt;y&lt;/code&gt; while browsing a file on Github to change the URL to the exact file hash.)&lt;/p&gt;

&lt;h3 id=&#34;bisecting-bugs&#34;&gt;Bisecting Bugs&lt;/h3&gt;

&lt;p&gt;Git has a really neat command called &lt;code&gt;git bisect&lt;/code&gt;, which you can use to help find the exact commit where a bug was introduced.  When you run &lt;code&gt;git bisect&lt;/code&gt;, you can give it a commit range where you &lt;em&gt;think&lt;/em&gt; the problem started.  Git will then check out one commit, let you run whatever steps you need to with the app to determine if the bug is present or not, and then say &lt;code&gt;git bisect good&lt;/code&gt; or &lt;code&gt;git bisect bad&lt;/code&gt;.  It then jumps to another commit and lets you repeat the process.  It follows a splitting pattern that lets you narrow down the potential problem commit in just a few steps.&lt;/p&gt;

&lt;h2 id=&#34;final-thoughts&#34;&gt;Final Thoughts&lt;/h2&gt;

&lt;p&gt;As software developers, we use lots of tools. Everyone has their own preferences for things like text editors and such, but everyone on a team is going to use the same version control system.  In today&#39;s world, that&#39;s inevitably Git.&lt;/p&gt;

&lt;p&gt;Given how critical Git is to modern development, anything you can do to use it more effectively will pay dividends down the road, and anyone reading your commits will appreciate the effort you put into clearly describing what changes are happening and why.  It might be a teammate reading your PR, an intern exploring the codebase next year, or even yourself revisiting code that you wrote many years ago.&lt;/p&gt;

&lt;p&gt;Ultimately, &lt;strong&gt;good Git practices are a key part of long-term codebase maintainability&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&#34;further-information&#34;&gt;Further Information&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Git Tutorials&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://www.atlassian.com/git/tutorials/what-is-git&#34;&gt;Atlassian Git tutorials&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://speakerdeck.com/alicebartlett/git-for-humans&#34;&gt;Git for Humans slides&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Git Internals&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://raw.githubusercontent.com/pluralsight/git-internals-pdf/master/drafts/peepcode-git.pdf&#34;&gt;Git Internals ebook (PDF)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://jwiegley.github.io/git-from-the-bottom-up/&#34;&gt;Git from the Bottom Up&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.freecodecamp.org/news/git-internals-objects-branches-create-repo/&#34;&gt;A Visual Guide to Git Internals&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.blog/2020-12-17-commits-are-snapshots-not-diffs/&#34;&gt;Commits are Snapshots, Not Diffs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://yurichev.com/news/20201220_git/&#34;&gt;Git Internals exploration&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Commit Messages&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://chris.beams.io/posts/git-commit/&#34;&gt;How to Write a Git Commit Message&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://wiki.openstack.org/wiki/GitCommitMessages&#34;&gt;Git Commit Message Good Practices&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operations&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.bloomca.me/2017/11/17/git-beyond-the-basics.html&#34;&gt;Git Beyond the Basics&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://stosb.com/blog/advanced-git-commands-you-will-actually-use/&#34;&gt;Advanced Git Commands You Will Actually Use&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Cheat Sheets&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;http://marklodato.github.io/visual-git-guide/index-en.html&#34;&gt;A Visual Git Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.git-tower.com/blog/git-cheat-sheet/&#34;&gt;Tower Git Cheat Sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://gist.github.com/akras14/3d242d80af8388ebca60&#34;&gt;akras14 Git Cheat Sheet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;DevHints Git cheat sheets: &lt;a href=&#34;https://devhints.io/git-revisions&#34;&gt;revision syntax&lt;/a&gt;, &lt;a href=&#34;https://devhints.io/git-log&#34;&gt;log syntax&lt;/a&gt;, &lt;a href=&#34;https://devhints.io/git-branch&#34;&gt;branching commands&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Other Resources&lt;/strong&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/k88hudson/git-flight-rules&#34;&gt;Git Flight Rules: a guide for when things go wrong&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/markerikson/react-redux-links/blob/master/git-resources.md&#34;&gt;React/Redux Links: Git Resources&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>Idiomatic Redux: Redux Toolkit 1.0</title>
      <link>https://blog.isquaredsoftware.com/2019/10/redux-toolkit-1.0/</link>
      <pubDate>Wed, 23 Oct 2019 10:00:00 -0500</pubDate>
      
      <guid>https://blog.isquaredsoftware.com/2019/10/redux-toolkit-1.0/</guid>
      <description>&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Today I am &lt;em&gt;extremely&lt;/em&gt; excited to announce that:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;span style=&#34;font-size: 3.0rem;&#34;&gt;
&lt;strong&gt;&lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/releases/tag/v1.0.0&#34;&gt;Redux Toolkit 1.0 is now available!&lt;/a&gt;&lt;/strong&gt;
&lt;/span&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: Redux Toolkit was formerly known as &amp;quot;Redux Starter Kit&amp;quot;, but &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/releases/tag/v1.0.4&#34;&gt;we renamed it to clarify the intended usage and audience&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;As part of that, I&#39;d like to look back at how Redux Toolkit came to be, talk about my goals and vision for the project, and look at how we&#39;ve designed the API to fulfill those goals.&lt;/p&gt;

&lt;p&gt;As a TL;DR, &lt;strong&gt;Redux Toolkit is designed to:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Make it easier to get started with Redux&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Simplify common Redux tasks and code&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Use opinionated defaults guiding towards &amp;quot;best practices&amp;quot;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Provide solutions to reduce or eliminate the &amp;quot;boilerplate&amp;quot; concerns with using Redux&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I&#39;m proud to say that we&#39;ve accomplished all those goals!&lt;/p&gt;

&lt;h4 id=&#34;table-of-contents&#34;&gt;Table of Contents&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#origins&#34;&gt;Origins&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#the-rise-of-redux&#34;&gt;The Rise of Redux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#facing-the-hype-cycle&#34;&gt;Facing the Hype Cycle&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#dealing-with-complexity&#34;&gt;Dealing with Complexity&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#in-search-of-a-solution&#34;&gt;In Search of a Solution&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#jumpstarting-the-process&#34;&gt;Jumpstarting the Process&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#designing-the-toolset&#34;&gt;Designing the Toolset&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#early-implementation-and-naming&#34;&gt;Early Implementation and Naming&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#filling-out-functionality&#34;&gt;Filling Out Functionality&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#defining-a-roadmap-and-clarifying-the-vision&#34;&gt;Defining a Roadmap and Clarifying the Vision&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#honing-the-api&#34;&gt;Honing the API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#the-future-of-redux-toolkit&#34;&gt;The Future of Redux Toolkit&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#review&#34;&gt;Review&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#reception&#34;&gt;Reception&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#next-steps&#34;&gt;Next Steps&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#further-information&#34;&gt;Further Information&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;origins&#34;&gt;Origins&lt;/h2&gt;

&lt;h3 id=&#34;the-rise-of-redux&#34;&gt;The Rise of Redux&lt;/h3&gt;

&lt;p&gt;Redux came out in the summer of 2015, at the tail end of the &amp;quot;Flux Wars&amp;quot;. Within a year, it had swept aside all other Flux implementations, and became the de-facto standard state management tool for React applications.&lt;/p&gt;

&lt;p&gt;Redux was &lt;a href=&#34;https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-1/#redux-should-be-as-extensible-as-possible&#34;&gt;deliberately designed to be extensible&lt;/a&gt;, and it succeeded brilliantly. The design led to &lt;a href=&#34;https://blog.isquaredsoftware.com/2017/09/presentation-might-need-redux-ecosystem/&#34;&gt;a thriving ecosystem of addons and related libraries&lt;/a&gt;, ranging from &lt;a href=&#34;https://github.com/markerikson/redux-ecosystem-links/blob/master/action-reducer-generators.md&#34;&gt;action/reducer generation utilities&lt;/a&gt; to &lt;a href=&#34;https://github.com/markerikson/redux-ecosystem-links/blob/master/store-persistence.md&#34;&gt;store persistence&lt;/a&gt; to &lt;a href=&#34;https://github.com/markerikson/redux-ecosystem-links/blob/master/immutable-data.md&#34;&gt;dozens of immutable update utilities&lt;/a&gt; to &lt;a href=&#34;https://github.com/markerikson/redux-ecosystem-links/blob/master/middleware.md&#34;&gt;middleware for manipulating dispatched actions&lt;/a&gt;. In particular, since Redux deliberately did not include a built-in solution for managing async behavior and side effects, &lt;a href=&#34;https://github.com/markerikson/redux-ecosystem-links/blob/master/side-effects.md&#34;&gt;dozens of side effect addons&lt;/a&gt; appeared.&lt;/p&gt;

&lt;p&gt;In short, if you needed to do something with Redux, odds were an addon already existed for your use case, and it was possible to build something yourself otherwise.&lt;/p&gt;

&lt;h3 id=&#34;facing-the-hype-cycle&#34;&gt;Facing the Hype Cycle&lt;/h3&gt;

&lt;p&gt;Most major technologies go through &lt;a href=&#34;https://en.wikipedia.org/wiki/Hype_cycle&#34;&gt;the hype cycle&lt;/a&gt;. A new product comes out, and early adopters fall in love with it and tout it as the solution to every problem. As more people use it, they begin to run into limitations, and the negative feedback becomes noticeable. Eventually, enough people figure out the best ways to use it, and it settles down as a viable tool with known tradeoffs.&lt;/p&gt;

&lt;p&gt;Redux is no exception to this. It quickly became associated with React, and many tutorials and discussions assumed that &amp;quot;if you&#39;re using React, you must be using Redux too&amp;quot;. This became something of a self-fulfilling prophecy, as new learners would read those tutorials and assume they &lt;em&gt;had&lt;/em&gt; to use Redux with React. Or, in many cases, senior devs might &lt;em&gt;tell&lt;/em&gt; other devs that they had to.&lt;/p&gt;

&lt;p&gt;As a result, &lt;strong&gt;many people began to learn Redux without understanding the context of why it was originally created, what problems it was meant to solve, and what the tradeoffs were. Blindly using &lt;em&gt;any&lt;/em&gt; tool without understanding is a recipe for trouble.&lt;/strong&gt; While many people were happy using Redux, many others began to complain about flaws, both actual and perceived.&lt;/p&gt;

&lt;h3 id=&#34;dealing-with-complexity&#34;&gt;Dealing with Complexity&lt;/h3&gt;

&lt;p&gt;There are several factors that combine to make it relatively harder to use Redux in comparison to other options:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Redux deliberately adds a level of indirection to the idea of updating state, in the form of actions. &lt;a href=&#34;https://twitter.com/dan_abramov/status/733742952657342464&#34;&gt;As Dan said early on&lt;/a&gt;:&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;[Redux] is not designed to be the most performant, or the most concise way of writing mutations. Its focus is on making the code predictable.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-2/&#34;&gt;Common conventions around Redux add additional levels of indirection and code that &amp;quot;needs&amp;quot; to be written&lt;/a&gt; (action creators, action type constants, selectors, thunks, switch statements, immutable updates).&lt;/li&gt;
&lt;li&gt;There&#39;s also a lot of &amp;quot;rules&amp;quot; around Redux that are described in written form, but not obviously enforced by Redux itself, particularly immutability, serializability, and avoiding side effects.&lt;/li&gt;
&lt;li&gt;JS is a mutable language, and &lt;a href=&#34;https://redux.js.org/recipes/structuring-reducers/immutable-update-patterns&#34;&gt;writing correct immutable code is hard&lt;/a&gt;, both in terms of avoiding accidental mutations and the amount of code that has to be written to handle updates immutably&lt;/li&gt;
&lt;li&gt;Redux was always meant to be a small core supporting a larger ecosystem of addons. This means that the core is deliberately tiny, and it&#39;s up to the user to choose how to configure the store. This is great for flexibility, but means that even the most common tasks require multiple semi-complex lines (such as adding thunk middleware for async logic, and also setting up the DevTools Extension). It also means the user has to make decisions early on about which addons they want to use, even in a simple app.&lt;/li&gt;
&lt;li&gt;Functional programming concepts are foreign to most people and hard to grok, especially if you&#39;re coming from an OOP background&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Like most early adopters, many early Redux users were &amp;quot;power users&amp;quot;. Configuration, customization, and &amp;quot;implementing things by hand so I know exactly what&#39;s happening&amp;quot; were key selling points. However, Redux took off across a larger userbase, those early selling points became weaknesses. Many people saw the patterns and practices as simply &amp;quot;boilerplate&amp;quot; that was a pain to deal with, and reasons to look for other options.&lt;/p&gt;

&lt;p&gt;In addition to the minimum &lt;em&gt;required&lt;/em&gt; complexity of dispatching actions and writing reducers, the &lt;em&gt;incidental&lt;/em&gt; complexity became a problem. For example, the original Redux docs divided code up into files and folders by &amp;quot;actions&amp;quot;, &amp;quot;constants&amp;quot;, &amp;quot;reducers&amp;quot;, and &amp;quot;containers&amp;quot;. &lt;a href=&#34;https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-2/#defining-actions-action-creators-and-reducers-in-separate-files&#34;&gt;There are valid reasons to split your code into files by type&lt;/a&gt;. But, at the same time, &lt;a href=&#34;https://redux.js.org/faq/code-structure#what-should-my-file-structure-look-like-how-should-i-group-my-action-creators-and-reducers-in-my-project-where-should-my-selectors-go&#34;&gt;there&#39;s no &lt;em&gt;requirement&lt;/em&gt; that you must write actions, reducers, and constants in separate folders/files&lt;/a&gt;. Because it was in the docs, most people copied what they saw, and this did become the standard pattern.&lt;/p&gt;

&lt;p&gt;Similarly, writing action types as constants like &lt;code&gt;const ADD_TODO = &amp;quot;ADD_TODO&amp;quot;&lt;/code&gt;, or the idea of having action creator functions for every single action type, are not &lt;em&gt;required&lt;/em&gt; either. But, &lt;a href=&#34;https://redux.js.org/faq/actions#why-should-type-be-a-string-or-at-least-serializable-why-should-my-action-types-be-constants&#34;&gt;those were the &lt;em&gt;recommended&lt;/em&gt; patterns&lt;/a&gt;, and users followed the examples in the docs.&lt;/p&gt;

&lt;p&gt;On top of that, the need to make decisions about what addons to use has frequently resulted in decision fatigue. The plethora of side effects libs (each with their own terminology) has been a particular pain point. Even within a year of Redux&#39;s release, &lt;a href=&#34;https://medium.com/javascript-and-opinions/redux-side-effects-and-you-66f2e0842fc3&#34;&gt;it was evident that the rapidly growing list of side effects libs was confusing&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;While the ecosystem has &lt;a href=&#34;https://blog.isquaredsoftware.com/2017/09/presentation-might-need-redux-ecosystem/&#34;&gt;largely settled on thunks, sagas, and observables&lt;/a&gt; as the standard approaches, the situation has made &lt;a href=&#34;https://redux.js.org/faq/actions#what-async-middleware-should-i-use-how-do-you-decide-between-thunks-sagas-observables-or-something-else&#34;&gt;&amp;quot;how do I choose a side effects middleware?&amp;quot;&lt;/a&gt; one of the most frequently asked questions. (Ironically, &lt;a href=&#34;https://github.com/reduxjs/redux/pull/63#issuecomment-110575809&#34;&gt;thunks were originally built into the core, but removed to make things flexible and unopinionated&lt;/a&gt;). Clearly, there&#39;s a need for an official blessing on how to handle side effects.&lt;/p&gt;

&lt;h3 id=&#34;in-search-of-a-solution&#34;&gt;In Search of a Solution&lt;/h3&gt;

&lt;p&gt;I got involved with Redux when I volunteered to write &lt;a href=&#34;https://redux.js.org/faq&#34;&gt;the Redux FAQ&lt;/a&gt; in early 2016. Dan handed over the maintainer keys to myself and Tim Dorr that summer, and I found myself answering Redux questions everywhere across the internet.&lt;/p&gt;

&lt;p&gt;By spring 2017, I realized that the programming landscape had changed enough that most new Redux users didn&#39;t understand the context behind its creation or why the typical usage patterns existed. I attempted to remedy that by writing a pair of comprehensive blog posts: &lt;strong&gt;&lt;a href=&#34;https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-1/&#34;&gt;The Tao of Redux, Part 1: Implementation and Intent&lt;/a&gt;&lt;/strong&gt;, and &lt;strong&gt;&lt;a href=&#34;https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-2/&#34;&gt;The Tao of Redux, Part 2: Practice and Philosophy&lt;/a&gt;&lt;/strong&gt;, which covered how Redux was originally designed and how it was meant to be used.&lt;/p&gt;

&lt;p&gt;Around the same time, I filed &lt;strong&gt;&lt;a href=&#34;https://github.com/reduxjs/redux/issues/2295&#34;&gt;Redux issue #2295: Request for Discussion: Redux &amp;quot;boilerplate&amp;quot;, learning curve, abstraction, and opinionatedness &lt;/a&gt;&lt;/strong&gt;. In that issue, I asked:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;What would idiomatic Redux usage with &amp;quot;less boilerplate&amp;quot; look like? How can we provide solutions to those complaints?&lt;/li&gt;
&lt;li&gt;What possible abstractions could be created that simplify the process of learning and usage, but without actually hiding Redux (and would hopefully provide a migration/learning path to &amp;quot;base&amp;quot; Redux)?&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;The very first reply was from &lt;a href=&#34;https://github.com/reduxjs/redux/issues/2295#issuecomment-287625366&#34;&gt;Justin Falcone (@modernserf)&lt;/a&gt;, who suggested:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;official redux-preset package containing redux, react-redux, redux-thunk already wired together&lt;/li&gt;
&lt;li&gt;built-in jumpstate-style reducer creators, e.g. createReducer({[actionType]: (state, payload) =&amp;gt; state}, initState)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;That suggestion was the genesis for what would eventually become Redux Toolkit.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The thread continued on for over a hundred comments, eventually devolving into users just pasting links and advertisements for their own Redux abstraction libs. In the middle of the thread, Dan Abramov dropped by, and &lt;a href=&#34;https://github.com/reduxjs/redux/issues/2295#issuecomment-287960516&#34;&gt;laid out his own wishlist for an opinionated layer on top of Redux&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If it were up to me I’d like to see this:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A Flow/TypeScript friendly subset that is easier to type than vanilla Redux.&lt;/li&gt;
&lt;li&gt;Not emphasizing constants that much (just make using string literals safer).&lt;/li&gt;
&lt;li&gt;Maintaining independence from React or other view libraries but making it easier to use existing bindings (e.g. providing mapStateToProps implementations).&lt;/li&gt;
&lt;li&gt;Preserving Redux principles (serializable actions, time travel, and hot reloading should work, action log should make sense).&lt;/li&gt;
&lt;li&gt;Supporting code splitting in a more straightforward way out of the box.&lt;/li&gt;
&lt;li&gt;Encouraging colocation of reducers with selectors, and making them less awkward to write together (think reducer-selector bundles that are easy to write and compose).&lt;/li&gt;
&lt;li&gt;Instead of colocating action creators with reducers, getting rid of action creators completely, and make many-to-many mapping of actions-to-reducers natural (rather than shy away from it like most libraries do).&lt;/li&gt;
&lt;li&gt;Making sensible performance defaults so memoization via Reselect “just works” for common use cases without users writing that code.&lt;/li&gt;
&lt;li&gt;Containing built-in helpers for indexing, normalization, collections, and optimistic updates.&lt;/li&gt;
&lt;li&gt;Having built-in testable async flow support.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;On top of core, of course, although it’s fine to brand it in as an official Redux thing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The thread eventually fizzled out, but the discussion stayed in the back of my mind.&lt;/p&gt;

&lt;h3 id=&#34;jumpstarting-the-process&#34;&gt;Jumpstarting the Process&lt;/h3&gt;

&lt;p&gt;In February 2018, &lt;a href=&#34;https://github.com/reduxjs/redux/issues/2858&#34;&gt;Nick McCurdy filed an issue suggestion adding freezing of state in dev to avoid accidental mutations&lt;/a&gt;. In that thread, I commented:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This goes back to my comments in #2295 , about wanting to provide a &amp;quot;starter preset&amp;quot; of packages that would provide a Redux-team-recommended simplified store setup. I&#39;ve seen dozens of variations on the theme, as well as &amp;quot;CRA + Redux&amp;quot; pieces out there already, but we haven&#39;t &amp;quot;blessed&amp;quot; any of them.&lt;/p&gt;

&lt;p&gt;The real issue here is that the Redux core comes completely unconfigured out of the box. We make no assumptions about what middleware you might add in, or even if you&#39;re going to use middleware at all. So, we can&#39;t just add a dev middleware out of the box, because nothing is configured out of the box.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In response, Tim Dorr opened &lt;strong&gt;&lt;a href=&#34;https://github.com/reduxjs/redux/issues/2859&#34;&gt;Redux issue #2859: RFC: Redux Starter Kit&lt;/a&gt;&lt;/strong&gt;, and said:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Based on comments over in #2858 and earlier in #2295, it sounds like a preconfigured starter kit of Redux core + some common middleware + store enhancers + other tooling might be helpful to get started with the library.&lt;/p&gt;

&lt;p&gt;As for what goes in a starter package, the short list in my mind includes one of the boilerplate reduction libraries (or something we build), popular middleware like thunks and sagas, and helpful dev tooling. We could have a subset package for React-specific users. In fact, I started a Twitter poll to find out if that&#39;s even necessary (please RT!).&lt;/p&gt;

&lt;p&gt;I don&#39;t think we need to build a Create React App-like experience with a CLI tool and all that jazz. But something out of the box that gives a great dev experience with better debugging and less code.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Seeing the issue got me incredibly excited, and &lt;a href=&#34;https://discordapp.com/channels/102860784329052160/103538784460615680/418590808992645133&#34;&gt;that led to a &lt;em&gt;very&lt;/em&gt; long discussion on Reactiflux&lt;/a&gt; with Nick McCurdy and Harry Wolff, as we tossed around ideas for what this &amp;quot;starter kit&amp;quot; thing might look like. Afterwards, &lt;a href=&#34;https://github.com/reduxjs/redux/issues/2859#issuecomment-369467568&#34;&gt;Harry summarized the ideas&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;wrapper around createStore with better defaults, i.e. easier way to add middleware, redux dev tools&lt;/li&gt;
&lt;li&gt;built in immutable helper (immer?)&lt;/li&gt;
&lt;li&gt;createReducer built in (the standard &amp;quot;reducer lookup table&amp;quot; utility)&lt;/li&gt;
&lt;li&gt;reselect built-in&lt;/li&gt;
&lt;li&gt;action creator that adheres to FSA&lt;/li&gt;
&lt;li&gt;async action support / side effect support (flux, saga, what?)&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;The discussion continued in the issue. I had some time free the next day, and &lt;a href=&#34;https://github.com/reduxjs/redux/issues/2859#issuecomment-369816441&#34;&gt;put together a notional first sample implementation of &lt;code&gt;configureStore&lt;/code&gt; and &lt;code&gt;createReducer&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Two days later, &lt;a href=&#34;https://github.com/reduxjs/redux/issues/2859#issuecomment-370182309&#34;&gt;I published &lt;code&gt;@acemarke/redux-starter-kit&lt;/code&gt; as an experimental package&lt;/a&gt;, and Redux Starter Kit (the original name) was born!&lt;/p&gt;

&lt;h2 id=&#34;designing-the-toolset&#34;&gt;Designing the Toolset&lt;/h2&gt;

&lt;h3 id=&#34;early-implementation-and-naming&#34;&gt;Early Implementation and Naming&lt;/h3&gt;

&lt;p&gt;Work on RSK advanced intermittently over the next few months. Nick filled out the build setup and initial unit tests, added CI integration, and enabled the Redux DevTools in &lt;code&gt;configureStore&lt;/code&gt;. I added re-exports from Redux and the &lt;code&gt;selectorator&lt;/code&gt; library, and oversaw discussion and improvements to middleware setup. But, after the initial burst of activity in March and April 2018, RSK just sort of sat around for the next few months.&lt;/p&gt;

&lt;p&gt;I came close to burning out in the summer of 2018 due to too many self-assigned responsibilities, such as maintaining my links lists. After taking some time to evaluate, I decided I really needed to focus on &amp;quot;maintainer&amp;quot; responsibilities. As part of that, I decided it was time to start pushing RSK forward seriously.&lt;/p&gt;

&lt;p&gt;The initial name of &amp;quot;Redux Starter Kit&amp;quot; was notional, and part of why I&#39;d originally published it as a personal scoped package. In late August, I opened up &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/issues/36&#34;&gt;an issue to bikeshed over what the final name should be&lt;/a&gt;. We debated various options, including using a &lt;code&gt;@redux/&lt;/code&gt; scoped prefix.&lt;/p&gt;

&lt;p&gt;The discussion trailed off until early October, when someone suggested we just go with plain &lt;code&gt;redux-starter-kit&lt;/code&gt;. The problem was that the unscoped &lt;code&gt;redux-toolkit&lt;/code&gt; package name was already taken on NPM.Just for kicks, we tried pinging the original owner (@shotak) and asked if they would be willing to donate the &lt;code&gt;redux-toolkit&lt;/code&gt; package name. To my surprise, they replied within a few hours and said yes. They transferred ownership of the NPM package, I moved the repo over to the &lt;code&gt;reduxjs&lt;/code&gt; org, and published the first official version as v0.1.0.&lt;/p&gt;

&lt;h3 id=&#34;filling-out-functionality&#34;&gt;Filling Out Functionality&lt;/h3&gt;

&lt;p&gt;The &lt;code&gt;createReducer&lt;/code&gt; and &lt;code&gt;createAction&lt;/code&gt; functions we&#39;d already added were useful, but I wanted to find more ways to simplify things.&lt;/p&gt;

&lt;p&gt;We&#39;d already been discussing &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/issues/17&#34;&gt;possibly bringing in helper functions from packages like &lt;code&gt;redux-utilities&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I&#39;d seen dozens of various similar libs. One that had stuck out to me was &lt;a href=&#34;https://github.com/ericelliott/autodux&#34;&gt;Eric Elliott&#39;s &lt;code&gt;autodux&lt;/code&gt; package&lt;/a&gt;. In particular, &lt;code&gt;autodux&lt;/code&gt; allowed users to auto-generate action creators and action types based on an object full of reducer functions and a &amp;quot;slice name&amp;quot; prefix.&lt;/p&gt;

&lt;p&gt;I&#39;d met Shawn Wang at ReactRally in August and told him about my ideas for RSK, and &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/issues/17#issuecomment-414091942&#34;&gt;he wrote up an assessment of &lt;code&gt;autodux&lt;/code&gt; and several other packages&lt;/a&gt;, concluding:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;using autodux creates a fairly powerful set of creators and selectors and reducers out of the box, and you can further write actions for business logic easily. i like autodux.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ultimately, &lt;code&gt;autodux&lt;/code&gt; served as the direct inspiration for the most useful part of Redux Toolkit: &lt;a href=&#34;https://redux-toolkit.js.org/api/createSlice&#34;&gt;the &lt;code&gt;createSlice&lt;/code&gt; function&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Eric Bower (@neurosnap) was participating in those discussions, and made &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/pull/37&#34;&gt;an initial attempt to port &lt;code&gt;autodux&lt;/code&gt; into our own &lt;code&gt;createSlice&lt;/code&gt;&lt;/a&gt;. The PR stalled a bit. Shortly thereafter, &lt;a href=&#34;https://www.reddit.com/r/javascript/comments/9fu82r/the_rise_of_immer_as_immutability_library_in_react/e5zmo3q/&#34;&gt;I saw someone on Reddit say they&#39;d written a library called &lt;code&gt;robodux&lt;/code&gt; that used Immer&lt;/a&gt;, and after some confusion, I realized that Eric had opted to try putting together his own version as a separate lib written in TypeScript.&lt;/p&gt;

&lt;p&gt;After some further discussion, &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/issues/17#issuecomment-428420190&#34;&gt;Eric agreed to contribute his code back to RSK in whatever form worked best for us&lt;/a&gt;. I ended up compiled his TS code to plain JS and porting that back over to RSK.&lt;/p&gt;

&lt;h3 id=&#34;defining-a-roadmap-and-clarifying-the-vision&#34;&gt;Defining a Roadmap and Clarifying the Vision&lt;/h3&gt;

&lt;p&gt;In early December, we &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/issues/48&#34;&gt;set up a Docusaurus-based docs page for RSK&lt;/a&gt; as a testbed for converting the Redux docs.&lt;/p&gt;

&lt;p&gt;Meanwhile, I added &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/pull/63&#34;&gt;default dev middleware for detecting mutations and non-serializable values&lt;/a&gt;, and enabled &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/pull/64&#34;&gt;the new Redux DevTools Extension &amp;quot;action stack trace&amp;quot; feature&lt;/a&gt; that I&#39;d helped to implement.&lt;/p&gt;

&lt;p&gt;In late January, I filed &lt;strong&gt;&lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/issues/82&#34;&gt;RSK issue #82: Roadmap to 1.0&lt;/a&gt;&lt;/strong&gt;, and began &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/pull/83&#34;&gt;adding the ability for slices to listen to other actions&lt;/a&gt;. In that PR, Denis Washington (@denisw) left &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/pull/83#pullrequestreview-194450952&#34;&gt;a comment suggesting that &lt;code&gt;createSlice&lt;/code&gt; be dropped entirely&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;In response, I put together a very long comment, laying out &lt;strong&gt;&lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/issues/82#issuecomment-456261368&#34;&gt;My Vision for Redux Starter Kit&lt;/a&gt;&lt;/strong&gt;. I&#39;ll skip quoting the entire thing (which is worth reading), but here&#39;s the key section:&lt;/p&gt;

&lt;blockquote&gt;
&lt;h4 id=&#34;objectives&#34;&gt;Objectives&lt;/h4&gt;

&lt;p&gt;Per the README, other specific inspirations are Create-React-App and Apollo-Boost. Both are packages that offer opinionated defaults and abstractions over a more complex and configurable set of tools, with the goal of providing an easy way to get started and be meaningfully productive without needing to know all the details or make complicated decisions up front. At the same time, they don&#39;t lock you in to only using the &amp;quot;default&amp;quot; options. They&#39;re useful for new learners who don&#39;t know all the options available or what the &amp;quot;right&amp;quot; choices are, but also for experienced devs who just want a simpler tool without going through all the setup every time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;I want Redux Starter Kit to be the same kind of thing, for Redux.&lt;/strong&gt;&lt;/p&gt;

&lt;h4 id=&#34;speed-up-getting-started&#34;&gt;&lt;strong&gt;Speed Up Getting Started&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;... I want to give people a way to get working Redux running as fast as possible.&lt;/p&gt;

&lt;h4 id=&#34;simplify-common-use-cases-and-remove-boilerplate&#34;&gt;&lt;strong&gt;Simplify Common Use Cases and Remove Boilerplate&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;I want to remove as many potential pain points from the equation as possible:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduce the amount of actual physical characters that need to be typed wherever possible&lt;/li&gt;
&lt;li&gt;Provide functions that do some of the most obvious things you&#39;d normally do by hand&lt;/li&gt;
&lt;li&gt;Look at how people are using Redux and want to use Redux, and offer &amp;quot;official&amp;quot; solutions for what they&#39;re doing already&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;opinionated-defaults-for-best-practices&#34;&gt;&lt;strong&gt;Opinionated Defaults for Best Practices&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;Redux Toolkit should set things up in ways that guide the user towards the right approach, and automatically prevent or detect+warn about common mistakes wherever possible.&lt;/p&gt;

&lt;h4 id=&#34;no-lock-in-add-it-incrementally&#34;&gt;&lt;strong&gt;No Lock-In / Add It Incrementally&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;If someone starts an app using Redux Toolkit, I don&#39;t want to prevent them from choosing to do some parts of the code by hand, now or later down the road.&lt;/p&gt;

&lt;p&gt;On the flip side, someone should be able to add Redux Toolkit to an existing Redux application, and begin using it incrementally, either by adding new logic or replacing existing logic incrementally.&lt;/p&gt;

&lt;h4 id=&#34;become-the-obvious-default-way-to-use-redux&#34;&gt;&lt;strong&gt;Become the &amp;quot;Obvious Default&amp;quot; Way to Use Redux&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;Long-term, I&#39;d like to see RSK become the &amp;quot;obvious default&amp;quot; way for most people to use Redux, in the same way that Create-React-App is the &amp;quot;obvious default&amp;quot; way to start a React project.&lt;/p&gt;

&lt;h4 id=&#34;don-t-solve-every-use-case-and-stay-visibly-typical-redux&#34;&gt;&lt;strong&gt;Don&#39;t Solve Every Use Case, and Stay Visibly &amp;quot;Typical Redux&amp;quot;&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;Redux is used in lots of different ways. Because of that, and because the core is so minimal, there&#39;s thousands of different Redux addon libraries for a wide spectrum of use cases. We can&#39;t solve all those ourselves, and we won&#39;t solve all those ourselves.&lt;/p&gt;

&lt;h4 id=&#34;reasonable-typescript-support&#34;&gt;&lt;strong&gt;Reasonable TypeScript Support&lt;/strong&gt;&lt;/h4&gt;

&lt;p&gt;I want to support people using TypeScript, same as I want to support anyone else using Redux in specific ways. So, RSK should be reasonably well typed. At the same time, I don&#39;t want &amp;quot;perfect typing&amp;quot; to become the enemy of &amp;quot;good functionality&amp;quot;. I&#39;m fine with trying to shape things so they work well in TS, but I&#39;m very willing to ship a feature that has less-than-ideal typing if that&#39;s what it takes to get it out the door.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;honing-the-api&#34;&gt;Honing the API&lt;/h3&gt;

&lt;p&gt;Simultaneous with this discussion, Denis was busy &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/pull/73&#34;&gt;converting the RSK codebase to TypeScript&lt;/a&gt;, based on a fork from @Dudeonyx. @Jessidhia also chimed in with several good pieces of TS advice.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/1177&#34;&gt;React-Redux v7 rewrite&lt;/a&gt; completely occupied my attention for the next couple months. The &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/1179&#34;&gt;hooks API design process&lt;/a&gt; kept me mostly occupied after that.&lt;/p&gt;

&lt;p&gt;Meanwhile, we had ongoing discussions on things like &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/issues/91&#34;&gt;possible additions to &lt;code&gt;createSlice&lt;/code&gt;&lt;/a&gt;, like maybe a special &lt;code&gt;combineSlices()&lt;/code&gt; function, or whether the auto-generated selector functionality was really useful.&lt;/p&gt;

&lt;p&gt;By summer 2019, the React-Redux work was finally done, and I was ready to turn my attention back to RSK. I began &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/pull/164&#34;&gt;writing an actual set of tutorial docs pages&lt;/a&gt;, finishing in early September.&lt;/p&gt;

&lt;p&gt;Meanwhile, Lenz Weber (@phryneas) had started contributing a number of key improvements, &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/pull/149&#34;&gt;adding a &lt;code&gt;prepare&lt;/code&gt; callback to &lt;code&gt;createAction&lt;/code&gt;&lt;/a&gt;, and &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/pull/168&#34;&gt;rewriting the TS type definitions for readability&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;From there, I began nailing down the final API. This included new functionality like &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/pull/192&#34;&gt;allowing customization of the default middleware&lt;/a&gt; and &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/pull/209&#34;&gt;exporting the case reducers&lt;/a&gt;, and breaking changes such as &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/pull/193&#34;&gt;removing selectors from &lt;code&gt;createSlice&lt;/code&gt;&lt;/a&gt; and &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/pull/197&#34;&gt;renaming the &lt;code&gt;slice&lt;/code&gt; field to &lt;code&gt;name&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There were still plenty of other ideas for more additions, but &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/issues/82#issuecomment-542773046&#34;&gt;I concluded that anything else could be added post-1.0&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;And that leads us up to &lt;strong&gt;the official release of Redux Toolkit 1.0!&lt;/strong&gt;&lt;/p&gt;

&lt;h3 id=&#34;changing-the-name&#34;&gt;Changing the Name&lt;/h3&gt;

&lt;p&gt;I&#39;ve been going back and forth between the names &amp;quot;Redux Starter Kit&amp;quot; and &amp;quot;Redux Toolkit&amp;quot; in this post. We did call it &amp;quot;Redux Starter Kit&amp;quot; up through the actual 1.0 release. But, after the release, we began getting feedback that the word &amp;quot;Starter&amp;quot; was confusing people. They assumed that it was a CLI project creation tool, a cloneable boilerplate project, something that was only suitable for beginners, or something that you&#39;d outgrow later in a project.&lt;/p&gt;

&lt;p&gt;I didn&#39;t want to rename the package, but it was clear that this confusion was going to continue.&lt;/p&gt;

&lt;p&gt;I opened up &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/issues/246&#34;&gt;another thread to discuss naming and marketing&lt;/a&gt;. After some additional discussion, we concluded that &lt;strong&gt;&amp;quot;Redux Toolkit&amp;quot;&lt;/strong&gt; was the best option, and that we should publish it as a scoped &lt;strong&gt;&lt;code&gt;@reduxjs/toolkit&lt;/code&gt;&lt;/strong&gt; package name.&lt;/p&gt;

&lt;p&gt;With that decision made, I was able to push through the rename process fairly quickly, and published the renamed package as &lt;strong&gt;&lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/releases/tag/v1.0.4&#34;&gt;Redux Toolkit v1.0.4&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;h2 id=&#34;the-future-of-redux-toolkit&#34;&gt;The Future of Redux Toolkit&lt;/h2&gt;

&lt;h3 id=&#34;review&#34;&gt;Review&lt;/h3&gt;

&lt;p&gt;Looking back at the original ideas and goals that came up in those early discussion issues, I think we&#39;ve pretty much nailed a majority of the desired capabilities.&lt;/p&gt;

&lt;p&gt;RTK is:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an official opinionated package, with our recommended best practices built in&lt;/li&gt;
&lt;li&gt;that drastically simplifies Redux apps and reduces &amp;quot;boilerplate&amp;quot; for the most common use cases&lt;/li&gt;
&lt;li&gt;while still remaining &amp;quot;visibly Redux&amp;quot; in the process&lt;/li&gt;
&lt;li&gt;that can all be added to a new project on day 1, or used for incremental migration of an existing project&lt;/li&gt;
&lt;li&gt;is useful for both new learners and experienced developers&lt;/li&gt;
&lt;li&gt;and provides solid TypeScript support without requiring a painful amount of type declarations&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I&#39;d say we&#39;ve hit the sweet spot with that list!&lt;/p&gt;

&lt;h3 id=&#34;reception&#34;&gt;Reception&lt;/h3&gt;

&lt;p&gt;I&#39;ve been actively advertising Redux Toolkit for the past year. It&#39;s linked on the front page of the Redux docs, it&#39;s recommended in the &lt;a href=&#34;https://redux.js.org/recipes/configuring-your-store&#34;&gt;&amp;quot;Configuring Your Store&amp;quot; docs page&lt;/a&gt;, and I&#39;ve been telling almost literally everyone I talk to that they should try out RTK :)&lt;/p&gt;

&lt;p&gt;I&#39;ve been excited to see that as a direct result of my efforts, &lt;a href=&#34;https://npm-stat.com/charts.html?package=redux-toolkit&amp;amp;from=2018-07-01&amp;amp;to=2019-10-23&#34;&gt;Redux Toolkit has been picking up some actual adoption&lt;/a&gt;. Starting at effectively 0 a year ago, it&#39;s now at 100K NPM downloads a month and climbing at a solid pace. This is even more impressive given that it&#39;s been pre-1.0 until now.&lt;/p&gt;

&lt;p&gt;I&#39;ve also been thrilled at the reception for RTK. I&#39;ve received numerous comments telling me things like:&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://twitter.com/AdamRackis/status/1104434428661678080&#34;&gt;Honestly your starter thing should have been the advertised api all along. It’s
💯&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://twitter.com/AlaaZork/status/1153124968856788994&#34;&gt;hijacking this to confirm how the redux-toolkit is literally indispensable, from a beginner to an advanced level, the combination of createSlice and immer is just so good&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://twitter.com/ryan_castner/status/1170056095458635776&#34;&gt;I am in the business of building things and having less code to maintain, RTK checks all my boxes.🙏 thank you for making it&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;I&#39;ll admit to a certain amount of pride, in that RSK has basically been my idea, I&#39;ve driven it, and I&#39;ve written a very large portion of the code. So, yeah, it feels great to hear all the compliments.&lt;/p&gt;

&lt;p&gt;But, even more than that, &lt;strong&gt;I&#39;m excited for how much this is going to help people learning and using Redux&lt;/strong&gt;.&lt;/p&gt;

&lt;h3 id=&#34;next-steps&#34;&gt;Next Steps&lt;/h3&gt;

&lt;p&gt;We&#39;re currently planning &lt;a href=&#34;https://github.com/reduxjs/redux/issues/3313#issuecomment-450601554&#34;&gt;a major revamp of the Redux docs&lt;/a&gt;, and I&#39;m hoping to finally begin working on that now that RTK 1.0 is out.&lt;/p&gt;

&lt;p&gt;As part of that docs revamp, &lt;strong&gt;we plan to actually teach using RTK as part of the tutorial sequence, and emphasize that we recommend its use throughout the rest of the docs&lt;/strong&gt;. We&#39;re also going to be reworking the tutorials and other docs sections to emphasize simpler patterns wherever possible, like avoiding use of action constants, dropping the emphasis on writing React &amp;quot;container components&amp;quot;, and recommending &lt;a href=&#34;https://github.com/erikras/ducks-modular-redux&#34;&gt;the &amp;quot;ducks pattern&amp;quot; for organizing Redux logic&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Feature-wise, there&#39;s also plenty more we could consider adding, such as &lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/issues/76&#34;&gt;maybe having a built-in way to define async side effects in slices&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you&#39;ve got any feedback, I&#39;m always interested. Ping me at &lt;a href=&#34;https://twitter.com/acemarke/&#34;&gt;@acemarke on Twitter&lt;/a&gt; and in the Reactiflux chat channels.&lt;/strong&gt;&lt;/p&gt;

&lt;h2 id=&#34;further-information&#34;&gt;Further Information&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://redux-toolkit.js.org&#34;&gt;Redux Toolkit docs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-1/&#34;&gt;The Tao of Redux, Part 1: Implementation and Intent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-tao-of-redux-part-2/&#34;&gt;The Tao of Redux, Part 2: Practice and Philosophy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/redux/issues/2295&#34;&gt;Redux issue #2295: Request for Discussion: Redux &amp;quot;boilerplate&amp;quot;, learning curve, abstraction, and opinionatedness&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/redux/issues/2859&#34;&gt;Redux issue #2859: RFC: Redux Starter Kit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/issues/17&#34;&gt;RTK issue #17: Consider using packages from redux-utilities&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/issues/82&#34;&gt;RTK issue #82: Roadmap to 1.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/redux-toolkit/issues/82#issuecomment-456261368&#34;&gt;Comment: My Vision for Redux Starter Kit&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>Idiomatic Redux: The History and Implementation of React-Redux</title>
      <link>https://blog.isquaredsoftware.com/2018/11/react-redux-history-implementation/</link>
      <pubDate>Thu, 22 Nov 2018 23:50:00 -0500</pubDate>
      
      <guid>https://blog.isquaredsoftware.com/2018/11/react-redux-history-implementation/</guid>
      <description>&lt;p&gt;&lt;/p&gt;

&lt;h2 id=&#34;intro&#34;&gt;Intro&lt;/h2&gt;

&lt;p&gt;React-Redux is conceptually pretty simple.  It subscribes to the Redux store, checks to see if the data your component wants has changed, and re-renders your component.&lt;/p&gt;

&lt;p&gt;However, there&#39;s a lot of internal complexity to make that happen, and most people aren&#39;t aware of all the work that React-Redux does internally.  I&#39;d like to dig through some of the design decisions and implementation details of how React-Redux works, and how those implementation details have changed over time.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This post was originally written before the release of React-Redux v6.  It has since been updated to cover the final release of v6, and the development and release of v7.0 and v7.1.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4 id=&#34;table-of-contents&#34;&gt;Table of Contents&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#integrating-redux-with-a-ui&#34;&gt;Integrating Redux with a UI&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#connect-in-a-nutshell&#34;&gt;&lt;code&gt;connect&lt;/code&gt; in a Nutshell&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#development-history-of-the-react-redux-api&#34;&gt;Development History of the React-Redux API&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#v4-x&#34;&gt;v4.x&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#v5-x&#34;&gt;v5.x&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#v6-0&#34;&gt;v6.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#v7-0&#34;&gt;v7.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#v7-1-hooks&#34;&gt;v7.1: Hooks?!?!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#the-future&#34;&gt;The Future&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#final-thoughts&#34;&gt;Final Thoughts&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;integrating-redux-with-a-ui&#34;&gt;Integrating Redux with a UI&lt;/h2&gt;

&lt;h3 id=&#34;understanding-redux-store-subscriptions&#34;&gt;Understanding Redux Store Subscriptions&lt;/h3&gt;

&lt;p&gt;It&#39;s been said that &amp;quot;Redux is just a [dumb] event emitter&amp;quot;.  There&#39;s actually a fair amount of truth in that statement.  Earlier MVC frameworks like Backbone would allow triggering any string as an event, and automatically trigger events like &lt;code&gt;&amp;quot;change:firstName&amp;quot;&lt;/code&gt; in models.  Redux, on the other hand, only has a single event type:  &amp;quot;some action was dispatched&amp;quot;.&lt;/p&gt;

&lt;p&gt;As a reminder, here&#39;s what a miniaturized (but valid) implementation of the Redux store looks like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-js&#34;&gt;function createStore(reducer) {
    var state;
    var listeners = []

    function getState() {
        return state
    }
    
    function subscribe(listener) {
        listeners.push(listener)
        return function unsubscribe() {
            var index = listeners.indexOf(listener)
            listeners.splice(index, 1)
        }
    }
    
    function dispatch(action) {
        state = reducer(state, action)
        listeners.forEach(listener =&amp;gt; listener())
    }

    dispatch({})

    return { dispatch, subscribe, getState }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Let&#39;s focus in particular on the &lt;code&gt;dispatch()&lt;/code&gt; implementation.  Notice that it doesn&#39;t check to see if the root state actually changed or not - &lt;strong&gt;it runs &lt;em&gt;every&lt;/em&gt; subscriber callback after &lt;em&gt;every&lt;/em&gt; dispatched action, regardless of whether there was any meaningful change to the state or not&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;In addition, &lt;strong&gt;the store state is not passed to the subscriber callbacks&lt;/strong&gt; - it&#39;s up to each subscriber to call &lt;code&gt;store.getState()&lt;/code&gt; if desired to retrieve the latest state.  (See the &lt;a href=&#34;https://redux.js.org/faq/designdecisions#why-doesnt-redux-pass-the-state-and-action-to-subscribers&#34;&gt;Redux FAQ entry on why the state isn&#39;t passed to subscribers&lt;/a&gt; for more details.)&lt;/p&gt;

&lt;h3 id=&#34;the-standard-ui-update-cycle&#34;&gt;The Standard UI Update Cycle&lt;/h3&gt;

&lt;p&gt;Using Redux with &lt;em&gt;any&lt;/em&gt; UI layer requires &lt;a href=&#34;https://blog.isquaredsoftware.com/presentations/workshops/redux-fundamentals/ui-layer.html#/4&#34;&gt;the same consistent set of steps&lt;/a&gt;:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Create a Redux store&lt;/li&gt;
&lt;li&gt;Subscribe to updates&lt;/li&gt;
&lt;li&gt;Inside the subscription callback:

&lt;ol&gt;
&lt;li&gt;Get the current store state&lt;/li&gt;
&lt;li&gt;Extract the data needed by this piece of UI&lt;/li&gt;
&lt;li&gt;Update the UI with the data&lt;/li&gt;
&lt;/ol&gt;&lt;/li&gt;
&lt;li&gt;If necessary, render the UI with initial state&lt;/li&gt;
&lt;li&gt;Respond to UI inputs by dispatching Redux actions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here&#39;s an example with a vanilla JS &amp;quot;counter&amp;quot; app, where the &amp;quot;state&amp;quot; is a single number:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-js&#34;&gt;// 1) Create a store
const store = createStore(counter)

// 2) Subscribe to store updates
store.subscribe(render);

const valueEl = document.getElementById(&#39;value&#39;);

// 3. When the subscription callback runs:
function render() {
    // 3.1) Get the current store state
    const state = store.getState();

    // 3.2) Extract the data you want
    const newValue = state.toString();

    // 3.3) Update the UI with the new value
    valueEl.innerHTML = newValue;
}

// 4) Display the UI with the initial store state
render();

// 5) Dispatch actions based on UI inputs
document.getElementById(&amp;quot;increment&amp;quot;)
    .addEventListener(&#39;click&#39;, () =&amp;gt; {
        store.dispatch({type : &amp;quot;INCREMENT&amp;quot;});
    })
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;strong&gt;Every Redux UI integration layer is simply a fancier version of those steps.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;You &lt;em&gt;could&lt;/em&gt; do this manually, in every React, component, &lt;a href=&#34;https://blog.isquaredsoftware.com/presentations/workshops/redux-fundamentals/ui-layer.html#/7&#34;&gt;but it would quickly get out of hand&lt;/a&gt;, especially once you &lt;a href=&#34;https://blog.isquaredsoftware.com/presentations/workshops/redux-fundamentals/ui-layer.html#/9&#34;&gt;start trying to cut down on unnecessary UI updates&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Clearly, the process of subscribing to the store, checking for updated data, and triggering a re-render can be made more generic and reusable.  That&#39;s where React-Redux and the &lt;code&gt;connect&lt;/code&gt; API come in.&lt;/p&gt;

&lt;h2 id=&#34;connect-in-a-nutshell&#34;&gt;&lt;code&gt;connect&lt;/code&gt; in a Nutshell&lt;/h2&gt;

&lt;p&gt;About a year after Redux came out, Dan Abramov wrote a gist entitled &lt;a href=&#34;https://gist.github.com/gaearon/1d19088790e70ac32ea636c025ba424e&#34;&gt;connect.js explained&lt;/a&gt;.  It contains a miniature version of &lt;code&gt;connect&lt;/code&gt; to illustrate how it works conceptually.  It&#39;s worth pasting that here for emphasis:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-jsx&#34;&gt;// connect() is a function that injects Redux-related props into your component.
// You can inject data and callbacks that change that data by dispatching actions.
function connect(mapStateToProps, mapDispatchToProps) {
  // It lets us inject component as the last step so people can use it as a decorator.
  // Generally you don&#39;t need to worry about it.
  return function (WrappedComponent) {
    // It returns a component
    return class extends React.Component {
      render() {
        return (
          // that renders your component
          &amp;lt;WrappedComponent
            {/* with its props  */}
            {...this.props}
            {/* and additional props calculated from Redux store */}
            {...mapStateToProps(store.getState(), this.props)}
            {...mapDispatchToProps(store.dispatch, this.props)}
          /&amp;gt;
        )
      }
      
      componentDidMount() {
        // it remembers to subscribe to the store so it doesn&#39;t miss updates
        this.unsubscribe = store.subscribe(this.handleChange.bind(this))
      }
      
      componentWillUnmount() {
        // and unsubscribe later
        this.unsubscribe()
      }
    
      handleChange() {
        // and whenever the store state changes, it re-renders.
        this.forceUpdate()
      }
    }
  }
}

// This is not the real implementation but a mental model.
// It skips the question of where we get the &amp;quot;store&amp;quot; from (answer: `&amp;lt;Provider&amp;gt;` puts it in React context)
// and it skips any performance optimizations (real connect() makes sure we don&#39;t re-render in vain).

// The purpose of connect() is that you don&#39;t have to think about
// subscribing to the store or perf optimizations yourself, and
// instead you can specify how to get props based on Redux store state
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We can see the key aspects of the API here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;connect&lt;/code&gt; is a function returning a function returning a wrapper component.&lt;/li&gt;
&lt;li&gt;The wrapped component&#39;s props are a combination of the wrapper component&#39;s props, the values from &lt;code&gt;mapState&lt;/code&gt;, and the values from &lt;code&gt;mapDispatch&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Each wrapper component is an individual subscriber to the Redux store.&lt;/li&gt;
&lt;li&gt;The wrapper component abstracts away the details of &lt;em&gt;which&lt;/em&gt; store you&#39;re using, &lt;em&gt;how&lt;/em&gt; it&#39;s interacting with the store, and optimizing performance so that your own component only re-renders when it needs to.&lt;/li&gt;
&lt;li&gt;You simply specify how to extract the data your component needs based on the store state, and the functions it can call to dispatch actions to the store&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;But, this miniature example hand-waves a lot of the details.  In particular, as the comments point out:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Where does the store come from?&lt;/li&gt;
&lt;li&gt;How does &lt;code&gt;connect&lt;/code&gt; check to see if your component needs to actually update?&lt;/li&gt;
&lt;li&gt;How does it implement the optimizations?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;And beyond that, how did we even end up with an API that looks like this in the first place?&lt;/p&gt;

&lt;h2 id=&#34;development-history-of-the-react-redux-api&#34;&gt;Development History of the React-Redux API&lt;/h2&gt;

&lt;h3 id=&#34;early-iterations&#34;&gt;Early Iterations&lt;/h3&gt;

&lt;p&gt;The first few versions of Redux included React bindings as part of the main package.  I won&#39;t go through those versions specifically, but you can see the changes in the release notes and READMEs for these early releases:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/redux/tree/v0.2.0&#34;&gt;v0.2.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/redux/releases/tag/v0.3.0&#34;&gt;v0.3.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/redux/releases/tag/v0.5.0&#34;&gt;v0.5.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/redux/releases/tag/v0.6.0&#34;&gt;v0.6.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/redux/releases/tag/v0.8.0&#34;&gt;v0.8.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/redux/releases/tag/v0.9.0&#34;&gt;v0.9.0&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Fun side note: amazingly, all that iteration took place over a single week!&lt;/p&gt;

&lt;p&gt;It took another three weeks to get up to &lt;a href=&#34;https://github.com/reduxjs/redux/releases/tag/v1.0.0-rc&#34;&gt;v1.0.0-rc&lt;/a&gt;, which is where the meaningful history begins.&lt;/p&gt;

&lt;h3 id=&#34;original-api-design-constraints&#34;&gt;Original API Design Constraints&lt;/h3&gt;

&lt;p&gt;React-Redux was split out as a separate repo in July 2015, just before Redux v1.0.0-rc came out.&lt;/p&gt;

&lt;p&gt;Dan filed &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/1&#34;&gt;React-Redux issue #1: Alternative API Proposals&lt;/a&gt; to discuss what the final API should look like.  In that issue, he listed a number of design constraints that should guide how the final API worked:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Common pain points:&lt;br /&gt;
- Not intuitive how way to separate smart and dumb components with &lt;code&gt;&amp;lt;Connector&amp;gt;&lt;/code&gt;, &lt;code&gt;@connect&lt;/code&gt;&lt;br /&gt;
- You have to manually bind action creators with &lt;code&gt;bindActionCreators&lt;/code&gt; helper which &lt;a href=&#34;https://github.com/gaearon/redux/pull/86&#34;&gt;some don&#39;t like&lt;/a&gt;&lt;br /&gt;
- Too much nesting for small examples (&lt;code&gt;&amp;lt;Provider&amp;gt;&lt;/code&gt;, &lt;code&gt;&amp;lt;Connector&amp;gt;&lt;/code&gt; both need function children)&lt;/p&gt;

&lt;p&gt;Let&#39;s go wild here. Post your alternative API suggestions.&lt;/p&gt;

&lt;p&gt;They should satisfy the following criteria:&lt;br /&gt;
- Some component at the root must hold the &lt;code&gt;store&lt;/code&gt; instance. (Akin to &lt;code&gt;&amp;lt;Provider&amp;gt;&lt;/code&gt;)&lt;br /&gt;
- It should be possible to connect to state no matter how deep in the tree&lt;br /&gt;
- It should be possible to select the state you&#39;re interested in with a &lt;code&gt;select&lt;/code&gt; function&lt;br /&gt;
- Smart / dumb components separation needs to be encouraged&lt;br /&gt;
- There should be one obvious way to separate smart / dumb components&lt;br /&gt;
- It should be obvious how to turn your functions into action creators&lt;br /&gt;
- Smart components should probably be able to react to updates to the state in &lt;code&gt;componentDidUpdate&lt;/code&gt;&lt;br /&gt;
- Smart components&#39; &lt;code&gt;select&lt;/code&gt; function needs to be able to take their props into account&lt;br /&gt;
- Smart component should be able to do something before/after dumb component dispatches an action&lt;br /&gt;
- We should have &lt;code&gt;shouldComponentUpdate&lt;/code&gt; wherever we can&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These criteria form the basis for the React-Redux API that we have today, and help explain why it works the way it does.&lt;/p&gt;

&lt;p&gt;The biggest points that came out of that discussion were using &lt;code&gt;connect&lt;/code&gt; as a function instead of a decorator, and how to handle binding action creators.&lt;/p&gt;

&lt;p&gt;Another fun side note: the &lt;a href=&#34;https://react-redux.js.org/docs/using-react-redux/connect-dispatching-actions-with-mapdispatchtoprops#defining-mapdispatchtoprops-as-an-object&#34;&gt;&amp;quot;object shorthand&amp;quot; for binding action creators&lt;/a&gt; was one of Dan&#39;s first suggestions for the API:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Perhaps we can even go further and bind automatically if an object is passed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;finalizing-the-api&#34;&gt;Finalizing the API&lt;/h3&gt;

&lt;p&gt;The next few releases continued iterating on the &lt;code&gt;connect&lt;/code&gt; API.  Highlights of the changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v0.5.0&#34;&gt;v0.5.0&lt;/a&gt;: introduced the &lt;code&gt;mapState&lt;/code&gt;, &lt;code&gt;mapDispatch&lt;/code&gt;, and &lt;code&gt;mergeProps&lt;/code&gt; arguments&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v0.6.0&#34;&gt;v0.6.0&lt;/a&gt;: used immutability and reference checks to determine if re-rendering is necessary&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v0.8.0&#34;&gt;v0.8.0&lt;/a&gt;: added the ability to pass &lt;code&gt;store&lt;/code&gt; as a prop&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v0.9.0&#34;&gt;v0.9.0&lt;/a&gt;: added the &lt;code&gt;ownProps&lt;/code&gt; arguments to &lt;code&gt;mapState/mapDispatch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v1.0.0&#34;&gt;v1.0.0&lt;/a&gt;: &lt;code&gt;&amp;lt;Provider&amp;gt;&lt;/code&gt;s single child had to be a function that returned an element&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v2.0.0&#34;&gt;v2.0.0&lt;/a&gt;: no longer supported &amp;quot;magically&amp;quot; hot reloading reducers&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v2.1.0&#34;&gt;v2.1.0&lt;/a&gt;: added an &lt;code&gt;options&lt;/code&gt; argument&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v3.0.0&#34;&gt;v3.0.0&lt;/a&gt;: moved the initial &lt;code&gt;mapState/mapDispatch&lt;/code&gt; calls to be part of the first render, to avoid state staleness issues&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Continuing the observations, at one point &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/86#issuecomment-137237015&#34;&gt;Dan warned against connecting leaf components&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We do warn in the documentation that we encourage you to follow React flow and avoid connect()ing leaf components.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is particularly amusing, given that &lt;a href=&#34;https://redux.js.org/faq/reactredux#should-i-only-connect-my-top-component-or-can-i-connect-multiple-components-in-my-tree&#34;&gt;we now recommend connecting components anywhere in the tree you feel it would be useful&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;That brings us up to what I&#39;d say is the &amp;quot;modern era&amp;quot; of the React-Redux API, starting with version 4.&lt;/p&gt;

&lt;h2 id=&#34;v4-x&#34;&gt;v4.x&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v4.0.0&#34;&gt;React-Redux v4.0.0&lt;/a&gt;&lt;/strong&gt; came out in October 2015, and had four major changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;React 0.14 as a minimum and a peer dependency&lt;/li&gt;
&lt;li&gt;No more React native-specific entry point&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;Provider&amp;gt;&lt;/code&gt; no longer accepted a function as a child, but rather a standard React element&lt;/li&gt;
&lt;li&gt;Refs to the child component now required the &lt;code&gt;withRef&lt;/code&gt; option, instead of always being enabled&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In addition, &lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v4.3.0&#34;&gt;v4.3.0&lt;/a&gt; added the &amp;quot;factory function&amp;quot; syntax of &lt;code&gt;mapState/mapDispatch&lt;/code&gt; to allow per-component-instance memoization of selectors.&lt;/p&gt;

&lt;p&gt;I would consider 4.x the first &amp;quot;complete&amp;quot; version of the React-Redux API.  As such, it&#39;s worth digging in to some of its implementation details, as well as some common points that define the overall behavior of the API across versions.&lt;/p&gt;

&lt;h3 id=&#34;api-behavior&#34;&gt;API Behavior&lt;/h3&gt;

&lt;h4 id=&#34;every-wrapper-component-instance-is-a-separate-store-subscriber&#34;&gt;Every Wrapper Component Instance is a Separate Store Subscriber&lt;/h4&gt;

&lt;p&gt;This one&#39;s pretty simple.  If I have a connected list component, and it renders 10 connected list item children, that&#39;s 11 separate calls to &lt;code&gt;store.subscribe()&lt;/code&gt;.  That &lt;em&gt;also&lt;/em&gt; means that &lt;strong&gt;if I have N connected components in the tree, then N subscriber callbacks are run for &lt;em&gt;every&lt;/em&gt; dispatched action!&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Every single subscriber callback is then responsible for doing its own checks to see if that particular component actually needs to update or not, based on the store state and props.&lt;/p&gt;

&lt;h4 id=&#34;ui-updates-require-store-immutability&#34;&gt;UI Updates Require Store Immutability&lt;/h4&gt;

&lt;p&gt;We&#39;ve already established that the Redux store will run &lt;em&gt;all&lt;/em&gt; subscriber callbacks after &lt;em&gt;every&lt;/em&gt; dispatched action, regardless of whether the state actually changed or not.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In order to implement efficient UI updates, React-Redux assumes you have updated the store state immutably, so it can use reference comparisons to determine if the state changed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This occurs in three stages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;When a &lt;code&gt;connect&lt;/code&gt; wrapper component&#39;s subscriber callback runs, it first calls &lt;code&gt;store.getState()&lt;/code&gt;, and checks to see if &lt;code&gt;prevStoreState !== storeState&lt;/code&gt;.  If the store state did &lt;em&gt;not&lt;/em&gt; change by reference, then it will stop right there and bail out of any further update work, because it assumes that no other part of the store state changed.&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;If the root state &lt;em&gt;has&lt;/em&gt; changed, the wrapper component then runs your &lt;code&gt;mapState&lt;/code&gt; function, and does a &amp;quot;shallow equality&amp;quot; comparison between the current result and the last result.  If any of the fields have changed by reference, then your component probably needs to be updated.&lt;/li&gt;
&lt;li&gt;Assuming that there was some change in the &lt;code&gt;mapState&lt;/code&gt; or &lt;code&gt;mapDispatch&lt;/code&gt; results, the &lt;code&gt;mergeProps()&lt;/code&gt; function is run to combine the &lt;code&gt;stateProps&lt;/code&gt; from &lt;code&gt;mapState&lt;/code&gt;, &lt;code&gt;dispatchProps&lt;/code&gt; from &lt;code&gt;mapDispatch&lt;/code&gt;, and &lt;code&gt;ownProps&lt;/code&gt; from the wrapper component itself.  A final check is done to see if the merged props result has changed since the last time, and if there&#39;s no change, the wrapped component will not be re-rendered.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: The root state comparison relies on a specific optimization in &lt;code&gt;combineReducers&lt;/code&gt;, which checks to see if any state slices were changed while processing an action, and if not, returns the previous state object instead of a new one.  &lt;strong&gt;This is a key reason why mutating your state results in your React UI components not updating!&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4 id=&#34;the-store-instance-is-passed-down-via-legacy-context&#34;&gt;The Store Instance is Passed Down via Legacy Context&lt;/h4&gt;

&lt;p&gt;In v4, rendering &lt;code&gt;&amp;lt;Provider store={store}&amp;gt;&lt;/code&gt; puts that store instance into the legacy context API, as &lt;code&gt;context.store&lt;/code&gt;.  Any nested class component could then request that &lt;code&gt;context.store&lt;/code&gt; be attached to the component.&lt;/p&gt;

&lt;p&gt;The biggest reason why the entire store was put into context was because context itself was flawed.  If you put an initial value into context in a parent, and some child requested that value, it would receive the correct value.  However, if the parent component put an updated value by that name into context, and there was an intervening component that skipped rendering using &lt;code&gt;shouldComponentUpdate -&amp;gt; false&lt;/code&gt;, the nested component would never see the updated value.  That&#39;s one of the reasons why the React team always discouraged people from using legacy context directly, suggesting that any uses should be wrapped up in an abstraction so that when a &amp;quot;future replacement for context&amp;quot; came out, it would be easier to migrate.  (See the &lt;a href=&#34;https://reactjs.org/docs/legacy-context.html&#34;&gt;React &amp;quot;Legacy Context&amp;quot; docs page&lt;/a&gt; and Michel Westrate&#39;s article &lt;a href=&#34;https://medium.com/@mweststrate/how-to-safely-use-react-context-b7e343eff076&#34;&gt;How to Safely Use React Context&lt;/a&gt; for more details.)&lt;/p&gt;

&lt;p&gt;So, one workaround was to put an &lt;em&gt;event emitter instance&lt;/em&gt; into context, instead of an actual value.  The nested components could grab the emitter instance on first render and subscribe directly, thus bypassing the &lt;code&gt;sCU&lt;/code&gt; &amp;quot;roadblocks&amp;quot; to receive updates.  React-Redux did this, as did libraries like &lt;code&gt;react-broadcast&lt;/code&gt;.&lt;/p&gt;

&lt;h4 id=&#34;connected-components-accept-a-store-as-a-prop&#34;&gt;Connected Components Accept a Store as a Prop&lt;/h4&gt;

&lt;p&gt;In addition to checking for the store instance in context, the wrapper components can optionally accept a store instance as a prop named &lt;code&gt;store&lt;/code&gt; instead, like &lt;code&gt;&amp;lt;MyConnectedComponent store={store}&amp;gt;&lt;/code&gt;.  This works because each component subscribes to the store individually, so this component just gets that store a different way.&lt;/p&gt;

&lt;p&gt;This is mostly useful for rendering connected components in a test without putting a &lt;code&gt;&amp;lt;Provider&amp;gt;&lt;/code&gt; around it, but does mean you could have a connected component in the middle of your tree that uses a different store than all the other components around it.&lt;/p&gt;

&lt;h3 id=&#34;implementation-details&#34;&gt;Implementation Details&lt;/h3&gt;

&lt;h4 id=&#34;update-logic-was-directly-in-the-wrapper-component&#34;&gt;Update Logic was Directly in the Wrapper Component&lt;/h4&gt;

&lt;p&gt;Up through v4, all of the logic was part of the &lt;code&gt;connect&lt;/code&gt; component class itself, including handling store updates, calling &lt;code&gt;mapState&lt;/code&gt;, and determining if the wrapped component needed to re-render.&lt;/p&gt;

&lt;p&gt;There&#39;s a couple interesting observations out of this.  First, &lt;a href=&#34;https://github.com/reduxjs/react-redux/blob/v4.3.0/src/components/connect.js#L213-L216&#34;&gt;the wrapper component always called &lt;code&gt;setState()&lt;/code&gt; whenever the root store state had changed&lt;/a&gt;, before it tries to do anything else.&lt;/p&gt;

&lt;p&gt;Second, as a result, the &lt;em&gt;real&lt;/em&gt; work of running &lt;code&gt;mapState&lt;/code&gt; and determining if anything has changed &lt;a href=&#34;https://github.com/reduxjs/react-redux/blob/v4.3.0/src/components/connect.js#L228-L285&#34;&gt;was actually done directly in the &lt;code&gt;render&lt;/code&gt; method&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This meant that any update to the Redux store required &lt;em&gt;all&lt;/em&gt; wrapper components to re-render themselves in order to determine if their wrapped components actually need to update or not.  That&#39;s a lot of components re-rendering every time, and also meant React was &lt;em&gt;always&lt;/em&gt; getting called on every meaningful store update.&lt;/p&gt;

&lt;h4 id=&#34;child-component-rendering-was-optimized-via-memoized-react-elements&#34;&gt;Child Component Rendering was Optimized Via Memoized React Elements&lt;/h4&gt;

&lt;p&gt;It&#39;s not well documented, but React has a particular performance optimization built-in.  Normally, when a component renders, it creates new child elements every time:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-jsx&#34;&gt;render() {
    // Turns into: React.createElement(ChildComponent, {a : 42})
    return &amp;lt;ChildComponent a={42} /&amp;gt;;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Every call to &lt;code&gt;React.createElement()&lt;/code&gt; returns a new element object like &lt;code&gt;{type : ChildComponent, props : {a : 42}, children : []}&lt;/code&gt;.  So, normally every re-render results in all-new element objects being created.&lt;/p&gt;

&lt;p&gt;However, if you return the exact same element objects as before, React will skip updating those specific elements as an optimization.  (This is the basis for &lt;a href=&#34;https://babeljs.io/docs/en/babel-plugin-transform-react-constant-elements&#34;&gt;@babel/plugin-transform-react-constant-elements&lt;/a&gt;, and the behavior is discussed some in &lt;a href=&#34;https://github.com/facebook/react/issues/3226&#34;&gt;React issue #3226&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The v4 implementation takes advantage of this, by &lt;a href=&#34;https://github.com/reduxjs/react-redux/blob/v4.3.0/src/components/connect.js#L268-L283&#34;&gt;memoizing the element for the child component&lt;/a&gt; to skip updating it if not needed.  This is necessary because the wrapper component is itself already re-rendering, so it needs some way to &lt;em&gt;not&lt;/em&gt; have the child re-render.&lt;/p&gt;

&lt;h2 id=&#34;v5-x&#34;&gt;v5.x&lt;/h2&gt;

&lt;p&gt;Up through v4, React-Redux was still primarily the work of Dan Abramov, albeit with a number of external contributions.  Dan had given me commit rights after I wrote the Redux FAQ, and I&#39;d spent enough time working on issues and looking the code that I felt comfortable giving more feedback beyond just how to use Redux.  However, by mid 2016 Dan had joined the React team at Facebook, and was getting busy there, so he told Tim Dorr and I that we were now the primary maintainers.&lt;/p&gt;

&lt;p&gt;About that time, a user named &lt;a href=&#34;https://github.com/jimbolla&#34;&gt;Jim Bolla&lt;/a&gt; filed an issue asking about &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/403&#34;&gt;an unusual use of &lt;code&gt;connect&lt;/code&gt;&lt;/a&gt;.  During the discussion, Jim commented that he was working on &amp;quot;an alternate version of &lt;code&gt;connect&lt;/code&gt;&amp;quot;, and I mentally dismissed that.&lt;/p&gt;

&lt;p&gt;A few days after that, though, Jim filed &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/405&#34;&gt;a follow-up issue asking for feedback on his alternate implementation&lt;/a&gt;.  We discussed some of the complexities in &lt;code&gt;connect&lt;/code&gt;&#39;s implementation, and how those related to the use cases it was trying to solve, but I again otherwise didn&#39;t think much of it.&lt;/p&gt;

&lt;p&gt;To my surprise, a couple days later Jim created &lt;strong&gt;&lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/407&#34;&gt;issue #407: Completely rewrite connect() to offer advanced API, separate concerns, and (probably) resolve a lot of those pesky edge cases&lt;/a&gt;&lt;/strong&gt; as a precursor to filing an actual PR.  I was still really skeptical and began pointing out concerns and edge cases, but to my (pleasant) surprise, Jim kept taking my feedback and improving his WIP branch.  This included producing some benchmarks which indicated that his version was noticeably faster than v4 in some particular scenarios.&lt;/p&gt;

&lt;p&gt;Jim&#39;s efforts &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/407#issuecomment-227925119&#34;&gt;eventually won me over&lt;/a&gt;, and we began seriously collaborating on pushing his rewrite forward.  That became &lt;strong&gt;&lt;a href=&#34;https://github.com/reduxjs/react-redux/pull/416&#34;&gt;PR #416: Rewrite connect() for better performance and extensibility &lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The rewrite was released as &lt;strong&gt;&lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v5.0.0&#34;&gt;v5.0.0&lt;/a&gt;&lt;/strong&gt; in December 2016.  The biggest changes were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Logic was moved from the wrapper component into memoized selectors&lt;/li&gt;
&lt;li&gt;Enforceed top-down subscription updates&lt;/li&gt;
&lt;li&gt;Added a new &lt;code&gt;connectAdvanced&lt;/code&gt; API&lt;/li&gt;
&lt;li&gt;More customization of comparison options&lt;/li&gt;
&lt;li&gt;Overall performance improvements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All of this while keeping the same public &lt;code&gt;connect&lt;/code&gt; API compatible with v4.&lt;/p&gt;

&lt;p&gt;v5 also resolved &lt;a href=&#34;https://github.com/reduxjs/react-redux/pull/416#issuecomment-233144992&#34;&gt;a large number of existing issues&lt;/a&gt; as well.&lt;/p&gt;

&lt;p&gt;There were various bugfixes up through &lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v5.0.7&#34;&gt;v5.0.7&lt;/a&gt;, and &lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v5.1.0&#34;&gt;v5.1.0&lt;/a&gt; recently added support for passing React&#39;s new built-in component types like &lt;code&gt;memo&lt;/code&gt; and &lt;code&gt;lazy&lt;/code&gt; into &lt;code&gt;connect&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Let&#39;s dig through some of the details.&lt;/p&gt;

&lt;h3 id=&#34;api-behavior-1&#34;&gt;API Behavior&lt;/h3&gt;

&lt;h4 id=&#34;top-down-updates&#34;&gt;Top-Down Updates&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;connect&lt;/code&gt; wrapper components subscribe to the store in &lt;code&gt;componentDidMount&lt;/code&gt;.  However, because that lifecycle fires bottom-to-top in a new component tree, it was possible for child components to subscribe to the store before their parents did.  Up through v4, that resulted in some &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/292&#34;&gt;nasty recurring bugs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;As an example, imagine a connected list with 10 connected list item children.  If they all render right away, the list items will subscribe before the list parent.  If you then delete the data for one of the items from the store, the list item component&#39;s &lt;code&gt;mapState&lt;/code&gt; would run before the parent&#39;s did.  This usually meant that the list item&#39;s &lt;code&gt;mapState&lt;/code&gt; would throw an error and break the component tree.&lt;/p&gt;

&lt;p&gt;v5 enforced the idea of top-down updates.  Components higher in the tree &lt;em&gt;always&lt;/em&gt; subscribe to the store before their children do.  That way, in a scenario like the connected list, deleting an item from the store will result in the parent updating first, and re-rendering without that list item child before the child even has a chance to run its own &lt;code&gt;mapState&lt;/code&gt;.  This gives much more predictable behavior, and aligns with how React itself works.&lt;/p&gt;

&lt;p&gt;We&#39;ll discuss the specifics of how this is implemented separately.&lt;/p&gt;

&lt;h4 id=&#34;connectadvanced&#34;&gt;&lt;code&gt;connectAdvanced&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;connect&lt;/code&gt; is fairly opinionated.  It lets you extract data from the store via &lt;code&gt;mapState&lt;/code&gt;, and prepare functions that dispatch actions via &lt;code&gt;mapDispatch&lt;/code&gt;, but it doesn&#39;t let you use store state data in &lt;code&gt;mapDispatch&lt;/code&gt; to prevent performance footguns.  It does provide the &lt;code&gt;mergeProps&lt;/code&gt; argument as an escape hatch, but that&#39;s separate.&lt;/p&gt;

&lt;p&gt;However, for users that want more flexibility (such as Jim himself), v5 adds a new &lt;code&gt;connectAdvanced&lt;/code&gt; API.  Rather than taking &lt;code&gt;(mapState, mapDispatch)&lt;/code&gt;, it asks you to pass in a &amp;quot;selector factory&amp;quot;.  A selector instance will be created for each component and given a reference to &lt;code&gt;dispatch&lt;/code&gt;, and the selectors will be called with &lt;code&gt;(state, ownProps)&lt;/code&gt; on all future updates from the store or the wrapper component.  That way, you can customize exactly how you want to handle derived props based on those inputs.&lt;/p&gt;

&lt;p&gt;The original &lt;code&gt;connect&lt;/code&gt; API is now actually implemented as a specific set of selector functions and options to &lt;code&gt;connectAdvanced&lt;/code&gt;.&lt;/p&gt;

&lt;h3 id=&#34;implementation-notes&#34;&gt;Implementation Notes&lt;/h3&gt;

&lt;h4 id=&#34;logic-is-implemented-in-memoized-selectors&#34;&gt;Logic is Implemented in Memoized Selectors&lt;/h4&gt;

&lt;p&gt;v5 moves all of the state derivation logic out of the wrapper component and into a separate set of homegrown memoized selector functions.  These selectors specifically implement all of the &lt;code&gt;connect&lt;/code&gt; API behavior, like:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Checking if the root state has changed&lt;/li&gt;
&lt;li&gt;Handling the various forms of &lt;code&gt;mapState&lt;/code&gt; and &lt;code&gt;mapDispatch&lt;/code&gt; ( &lt;code&gt;(state)&lt;/code&gt; vs &lt;code&gt;(state, ownProps)&lt;/code&gt;, &lt;code&gt;mapDispatch&lt;/code&gt; as an object vs function, etc)&lt;/li&gt;
&lt;li&gt;Calling &lt;code&gt;mapState&lt;/code&gt;, &lt;code&gt;mapDispatch&lt;/code&gt;, and &lt;code&gt;mergeProps&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Calculating the new child props and determining if a re-render is actually necessary&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;As a result, the subscriber callbacks can run extremely quickly, without involving React at all.  In fact, React will only get involved once the wrapper component &lt;em&gt;knows&lt;/em&gt; the child should re-render, and it uses a dummy &lt;code&gt;this.setState({})&lt;/code&gt; call to queue up that re-render.  (We probably could have used &lt;code&gt;forceUpdate()&lt;/code&gt; instead, but I don&#39;t think it makes any difference in this case.)&lt;/p&gt;

&lt;p&gt;This is the biggest reason why v5 is generally faster than v4.&lt;/p&gt;

&lt;h4 id=&#34;custom-top-down-subscription-logic&#34;&gt;Custom Top-Down Subscription Logic&lt;/h4&gt;

&lt;p&gt;In order to enforce top-down subscriptions, v5 introduced &lt;a href=&#34;https://github.com/reduxjs/react-redux/blob/v5.1.1/src/utils/Subscription.js&#34;&gt;a custom &lt;code&gt;Subscription&lt;/code&gt; class&lt;/a&gt;.  Internally, &lt;code&gt;connect&lt;/code&gt; actually puts both the store instance &lt;em&gt;and&lt;/em&gt; an instance of &lt;code&gt;Subscription&lt;/code&gt; into legacy context.  If no subscription exists in context, that component will subscribe to the store directly, as it must be high up in the tree.  Otherwise, it subscribes to the &lt;code&gt;Subscription&lt;/code&gt; instance.  This means that each connected component is effectively subscribing to its nearest connected ancestor.&lt;/p&gt;

&lt;p&gt;When an action is dispatched, the uppermost connected components will have their callbacks be triggered right away.  If they do need to re-render, they call &lt;code&gt;setState()&lt;/code&gt;, and wait until &lt;code&gt;componentDidUpdate&lt;/code&gt; to trigger notification of the next tier of connected components.  If no update is necessary, the next tier is notified right away.&lt;/p&gt;

&lt;p&gt;This works, but it also requires some very tricky logic in both the &lt;code&gt;Subscription&lt;/code&gt; class and the wrapper component itself (including dynamically adding and removing a &lt;code&gt;componentDidUpdate&lt;/code&gt; function to micro-optimize perf).&lt;/p&gt;

&lt;h2 id=&#34;v6-0&#34;&gt;v6.0&lt;/h2&gt;

&lt;h3 id=&#34;motivations&#34;&gt;Motivations&lt;/h3&gt;

&lt;p&gt;v5 was great.  It performed faster than v4 in almost all scenarios we&#39;ve seen, and it added more flexibility.&lt;/p&gt;

&lt;p&gt;However, the React team has continued to innovate.  In particular, React 16.3 introduced the new &lt;code&gt;React.createContext()&lt;/code&gt; API, which is an officially supported replacement for the legacy context API, and encouraged for production use.  With &lt;code&gt;createContext&lt;/code&gt; now available, they&#39;ve been &lt;a href=&#34;https://github.com/facebook/react/pull/13728&#34;&gt;encouraging the community to migrate away from legacy context&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;They&#39;ve also been working on &amp;quot;concurrent React&amp;quot;, an umbrella that describes future capabilities like &lt;a href=&#34;https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-react-16.html&#34;&gt;&amp;quot;time-slicing&amp;quot; and &amp;quot;Suspense&amp;quot;&lt;/a&gt;.  Long-term, there are questions about how synchronous external stores like Redux will work correctly when React is running in concurrent mode.&lt;/p&gt;

&lt;p&gt;With that in mind, we had several discussion threads about how React-Redux should work with concurrent React (&lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/890&#34;&gt;#890&lt;/a&gt;, &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/950&#34;&gt;#950&lt;/a&gt;), as well as how to deal with the deprecation warnings when used in &lt;code&gt;&amp;lt;StrictMode&amp;gt;&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We originally planned on releasing a 5.1.0 release to fix &lt;code&gt;&amp;lt;StrictMode&amp;gt;&lt;/code&gt; issues, but &lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v5.1.0-test.1&#34;&gt;that test release turned out to be very broken&lt;/a&gt;.  When we tried to fix the breakage, &lt;a href=&#34;https://github.com/reduxjs/react-redux/pull/980&#34;&gt;our attempts turned out to drastically hurt performance&lt;/a&gt;, as well as add way too much complexity.&lt;/p&gt;

&lt;p&gt;We ultimately decided to &lt;a href=&#34;https://github.com/reduxjs/react-redux/pull/980#issuecomment-410924304&#34;&gt;not put out a direct fix for &lt;code&gt;&amp;lt;StrictMode&amp;gt;&lt;/code&gt; warnings in 5.x&lt;/a&gt;, and instead moved on to work on v6.&lt;/p&gt;

&lt;p&gt;The primary drivers for v6 development were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Use &lt;code&gt;createContext&lt;/code&gt; instead of legacy context&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Fix &lt;code&gt;&amp;lt;StrictMode&amp;gt;&lt;/code&gt; warnings&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Be more compatible with concurrent React behavior going forward&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We went through several experimental PRs (particularly &lt;a href=&#34;https://github.com/reactjs/react-redux/pull/898&#34;&gt;#898&lt;/a&gt; and &lt;a href=&#34;https://github.com/reduxjs/react-redux/pull/995&#34;&gt;#995&lt;/a&gt;) before settling on &lt;strong&gt;&lt;a href=&#34;https://github.com/reduxjs/react-redux/pull/1000&#34;&gt;PR #1000: Use React.createContext()&lt;/a&gt;&lt;/strong&gt; as the best approach.  Another contributor named &lt;a href=&#34;https://github.com/cellog&#34;&gt;Greg Beaver&lt;/a&gt; had been working with us on the &lt;code&gt;&amp;lt;StrictMode&amp;gt;&lt;/code&gt; issues, and he and I submitted &amp;quot;competing&amp;quot; candidate PRs for v6 with varying internal implementations.  His approach turned out to be &lt;em&gt;slightly&lt;/em&gt; faster than mine, so we went with that PR, and I was then able to further optimize the PR.&lt;/p&gt;

&lt;h3 id=&#34;api-changes&#34;&gt;API Changes&lt;/h3&gt;

&lt;p&gt;We released &lt;strong&gt;&lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v6.0.0&#34;&gt;React-Redux v6.0&lt;/a&gt;&lt;/strong&gt; in early December 2018.  The primary changes were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Internal&lt;/strong&gt;: Uses &lt;code&gt;createContext&lt;/code&gt; internally instead of legacy context&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Internal&lt;/strong&gt;: Changes to how the components subscribe and receive the updated state from the store&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Breaking&lt;/strong&gt;: The &lt;code&gt;withRef&lt;/code&gt; option has been removed in favor of using React&#39;s &lt;code&gt;forwardRef&lt;/code&gt; capability&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Breaking&lt;/strong&gt;: Passing a store as a prop is no longer supported&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that &lt;strong&gt;there were only two minor breaking changes to the public API!&lt;/strong&gt;.  React-Redux has a fairly comprehensive &lt;a href=&#34;https://github.com/reduxjs/react-redux/tree/v6.0.0-beta.1/test/components&#34;&gt;suite of unit tests for &lt;code&gt;connect&lt;/code&gt; and &lt;code&gt;&amp;lt;Provider&lt;/code&gt;&amp;gt;&lt;/a&gt;, and v6 passed the same unit tests as v5 (with appropriate changes in the tests to match some of the implementation changes).  v6 also ran safely inside a &lt;code&gt;&amp;lt;StrictMode&amp;gt;&lt;/code&gt; tag without any warnings.&lt;/p&gt;

&lt;p&gt;Because of that, for most apps, React-Redux v6 was a drop-in upgrade!  We did require React 16.4 as a minimum because of using &lt;code&gt;createContext&lt;/code&gt;, but other than that, many apps were able to just bump to the new version.  The biggest set of issues came from various community libraries that relied on accessing the store instance directly from legacy context, which broke.&lt;/p&gt;

&lt;p&gt;However, &lt;strong&gt;the implementation changes did result in different behavior tradeoffs&lt;/strong&gt;.  Let&#39;s look at the changes in detail.&lt;/p&gt;

&lt;h3 id=&#34;implementation-notes-1&#34;&gt;Implementation Notes&lt;/h3&gt;

&lt;h4 id=&#34;v6-the-store-state-is-passed-down-via-createcontext&#34;&gt;v6: The Store State is Passed Down via &lt;code&gt;createContext&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;In every version up through v5.x, the Redux store instance itself was put into context, and every connected component subscribed directly.  In v6, that changed drastically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In v6:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Redux &lt;em&gt;store state&lt;/em&gt; is put into an instance of the new &lt;code&gt;createContext&lt;/code&gt; API&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;There is only &lt;em&gt;one&lt;/em&gt; store subscriber: the &lt;code&gt;&amp;lt;Provider&amp;gt;&lt;/code&gt; component&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This had all kinds of ripple effects across the implementation.&lt;/p&gt;

&lt;p&gt;It&#39;s fair to ask why we chose to change this aspect.  We certainly &lt;em&gt;could&lt;/em&gt; have put the store instance into &lt;code&gt;createContext&lt;/code&gt;, but there&#39;s several reasons why it made sense to put the store &lt;em&gt;state&lt;/em&gt; into context instead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The largest reason was to improve compatibility with &amp;quot;concurrent React&amp;quot;, because the entire tree will see a single consistent state value&lt;/strong&gt;.  The very short explanation on this is that React&#39;s &amp;quot;time-slicing&amp;quot; and &amp;quot;Suspense&amp;quot; features can potentially cause problems when used with external synchronous state management tools.  As one example, Andrew Clark has described &amp;quot;tearing&amp;quot; as a possible problem, where different parts of the component tree see different values during the same component tree re-render pass.  By passing down the current state via context, we can ensure that the entire tree sees the same state value, because React takes care of that for us.&lt;/p&gt;

&lt;p&gt;The long-term goal was to hopefully prevent weird bugs when React-Redux is used with concurrent-mode React.  (We do have other questions we need to solve regarding how to fully make use of Suspense - &lt;a href=&#34;https://www.reddit.com/r/reactjs/comments/9xnvs2/how_does_concurrent_react_update_priorities_work/e9toant/?context=3&#34;&gt;I wrote an extensive Reddit comment describing the aspects we might need to solve&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Related to this, React-Redux has previously faced numerous problems around dispatching in constructors and &lt;code&gt;componentWillMount&lt;/code&gt; (see &lt;a href=&#34;https://github.com/reduxjs/react-redux/search?q=dispatch+componentwillmount&amp;amp;type=Issues&#34;&gt;some related issues&lt;/a&gt; ).  Switching to passing the state via context was meant to eliminate those edge cases.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Another big reason was that we got &amp;quot;top-down updates&amp;quot; for free!&lt;/strong&gt;  Context inherently propagates top-down and ties into the render process.  So, if the data for a list item is deleted, the list parent will naturally re-render before the list item does.  As a result, for v6 we were able to delete that custom &lt;code&gt;Subscription&lt;/code&gt; logic - we no longer needed it!  That was less code that we had to maintain, and a slightly smaller package size as a result.&lt;/p&gt;

&lt;p&gt;In addition, the original reason for passing the store instance no longer exists, because &lt;strong&gt;&lt;code&gt;createContext&lt;/code&gt; correctly propagates value changes past &lt;code&gt;shouldComponentUpdate&lt;/code&gt; blockers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Finally, while this would have changed either way we handled the state-vs-store question, &lt;strong&gt;switching to &lt;code&gt;createContext&lt;/code&gt; fixed bugs when mixing old and new context together&lt;/strong&gt;.  There&#39;s already been a number of bugs filed that indicate weird things happen if you use both  forms of context in the same component, and Dan has also said that &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/1083#issuecomment-439958259&#34;&gt;having old context being used anywhere in a component tree slows things down some&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Putting the store state into context did have some interesting implications around performance, which we&#39;ll get to in a bit.&lt;/p&gt;

&lt;h4 id=&#34;update-logic-is-selectors-used-in-rendering&#34;&gt;Update Logic is Selectors, Used In Rendering&lt;/h4&gt;

&lt;p&gt;The new context API relies on a &amp;quot;render props&amp;quot; approach for receiving the values put into context, like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-jsx&#34;&gt;&amp;lt;MyContext.Consumer&amp;gt;
{ (contextValue) =&amp;gt; {
    // render something with the new context value here
}}
&amp;lt;/MyContext.Consumer&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This means that context updates are directly tied to the wrapper component&#39;s &lt;code&gt;render&lt;/code&gt; function.&lt;/p&gt;

&lt;p&gt;v6 still used the exact same set of selector functions for &lt;code&gt;connect&lt;/code&gt; as v5 did.  However, there was also some additional memoization logic built into the wrapper component itself to help with the rendering process.  (I initially tried adding a second inner wrapper component and doing tricks with &lt;code&gt;getDerivedStateFromProps&lt;/code&gt;, but adding an additional selector in the one wrapper component proved to be more efficient.)&lt;/p&gt;

&lt;p&gt;As part of that, &lt;strong&gt;v6 re-used the &amp;quot;memoized React child element&amp;quot; trick&lt;/strong&gt; to indicate that the wrapped component shouldn&#39;t be re-rendered.  As with v4, this is because updates are tied to the wrapper component re-rendering, so we need a way to bail out if the child doesn&#39;t need to update.  (In fact, v6 doesn&#39;t even actually implement &lt;code&gt;shouldComponentUpdate&lt;/code&gt;, because this trick is equivalent in terms of when the child updates.)&lt;/p&gt;

&lt;h4 id=&#34;the-withref-option-is-replaced-by-forwardref&#34;&gt;The &lt;code&gt;withRef&lt;/code&gt; Option is Replaced by &lt;code&gt;forwardRef&lt;/code&gt;&lt;/h4&gt;

&lt;p&gt;One of the acknowledged downsides to Higher-Order Components is that they don&#39;t easily allow you to get access to the wrapped component inside.  React 16.3 introduced a new &lt;a href=&#34;https://reactjs.org/docs/forwarding-refs.html&#34;&gt;&lt;code&gt;React.forwardRef&lt;/code&gt; API&lt;/a&gt; as a solution.  Libraries can use this to allow end users to put a &lt;code&gt;ref&lt;/code&gt; on the HOC, but actually get back the real wrapped component instance.&lt;/p&gt;

&lt;p&gt;We&#39;ve added that in v6, which means that the old &lt;code&gt;withRef&lt;/code&gt; option is no longer needed.  Since this does add an additional layer of wrapping (and therefore a bit more work for React to do), it&#39;s still opt-in via the new &lt;code&gt;{forwardRef : true}&lt;/code&gt; option.&lt;/p&gt;

&lt;h4 id=&#34;no-more-store-as-a-prop&#34;&gt;No More &lt;code&gt;store&lt;/code&gt; as a Prop&lt;/h4&gt;

&lt;p&gt;This was a consequence of changing from individual subscriptions per component, to a single subscription in &lt;code&gt;&amp;lt;Provider&amp;gt;&lt;/code&gt;.  Since the components no longer subscribe, passing a store directly as a prop was meaningless, and so it was removed.&lt;/p&gt;

&lt;p&gt;As mentioned earlier, the two main use cases for this were avoiding rendering &lt;code&gt;&amp;lt;Provider&amp;gt;&lt;/code&gt; in tests, and allowing portions of the component tree to read from another store.  The unit test use case was something that did require changes in your codebase, for folks who were actually rendering connected components in their unit tests.  For the &amp;quot;alternate store&amp;quot; use case, we added the ability to pass your own custom context object as a prop to &lt;code&gt;&amp;lt;Provider&amp;gt;&lt;/code&gt; and connected components, allowing them to read from a different store if desired, hoping that would be a sufficient alternative.&lt;/p&gt;

&lt;p&gt;(I originally intended the API to involve passing a &lt;code&gt;Context.Provider&lt;/code&gt; as a prop to &lt;code&gt;&amp;lt;Provider&amp;gt;&lt;/code&gt; and passing a &lt;code&gt;Context.Consumer&lt;/code&gt; as a prop to a connected component.  However, the &lt;code&gt;useContext()&lt;/code&gt; hook requires an entire context object, not just a consumer, despite my requests to the React team to allow it to work with just a consumer.  So, the thought was that if we ever switched to using hooks internally to read from context, we&#39;d need the whole context object in the wrapper component, so best to just require that as a prop now.)&lt;/p&gt;

&lt;h4 id=&#34;accessing-the-store-via-context-has-changed&#34;&gt;Accessing the Store via Context Has Changed&lt;/h4&gt;

&lt;p&gt;While it&#39;s never been part of our public API, it&#39;s common knowledge that any component could get a reference to the Redux store by declaring the appropriate &lt;code&gt;contextTypes&lt;/code&gt; and using &lt;code&gt;this.context.store&lt;/code&gt;.  Many community libraries took advantage of this.  For example, &lt;code&gt;connected-react-router&lt;/code&gt; &lt;a href=&#34;https://github.com/supasate/connected-react-router/blob/b197430be6315eb8c70f98be96ff67825653add5/src/ConnectedRouter.js#L23-L47&#34;&gt;adds an extra subscription to handle location changes&lt;/a&gt;, while &lt;code&gt;react-redux-subspace&lt;/code&gt; &lt;a href=&#34;https://github.com/ioof-holdings/redux-subspace/blob/d4c95fbf50fc93e4abfa2bcff742a51f249f0ad7/packages/react-redux-subspace/src/components/SubspaceProvider.js#L15-L21&#34;&gt;intercepts the store and passes down a wrapped-up version that presents an altered view of the state&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Obviously, this is unsupported, and any library that does this kind of thing is risking things breaking... and in v6, that all broke because we weren&#39;t using legacy context any more.  However, we wanted to allow the community the ability to build customized solutions on top of React-Redux if desired.&lt;/p&gt;

&lt;p&gt;Each connected component needs the current store state, &lt;em&gt;and&lt;/em&gt; a reference to the store&#39;s &lt;code&gt;dispatch&lt;/code&gt; function so that it can implement &lt;code&gt;mapDispatch&lt;/code&gt; correctly.  In one early PR, I had the &lt;code&gt;&amp;lt;Provider&amp;gt;&lt;/code&gt; putting &lt;code&gt;{storeState, dispatch}&lt;/code&gt; into context to handle that.&lt;/p&gt;

&lt;p&gt;However, in v6 final, we actually put both the &lt;em&gt;store state&lt;/em&gt; and the &lt;em&gt;store instance&lt;/em&gt; into context, so the context value actually looks like &lt;code&gt;{storeState, store}&lt;/code&gt;.  That way, the components could reference &lt;code&gt;store.dispatch&lt;/code&gt;.  In addition, we&#39;re exporting our default instance of &lt;code&gt;ReactReduxContext&lt;/code&gt;.  &lt;em&gt;If&lt;/em&gt; someone wants to, they can render that context consumer, retrieve the store instance, and do something with it.&lt;/p&gt;

&lt;p&gt;Again, it wasn&#39;t an official API, but the goal was to make it possible for folks to build on that if needed.&lt;/p&gt;

&lt;h3 id=&#34;performance-implications&#34;&gt;Performance Implications&lt;/h3&gt;

&lt;p&gt;When we were working on the attempt to fix the initial failed 5.1.0 version, we ran some benchmarks to see how the altered version compared to 5.0.7.  The large perf slowdown was a big reason why we abandoned that attempt.&lt;/p&gt;

&lt;p&gt;In response, &lt;a href=&#34;https://github.com/reduxjs/react-redux-benchmarks&#34;&gt;I set up a benchmarks repo that could compare multiple versions of React-Redux together&lt;/a&gt;.  We used that throughout the development of v6, comparing our various WIP builds against each other and v6.&lt;/p&gt;

&lt;p&gt;Based on those benchmarks, &lt;strong&gt;we expected that React-Redux v6 would be sufficiently fast enough for almost all real-world apps&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Having said that, there&#39;s some caveats.&lt;/p&gt;

&lt;p&gt;When I first envisioned switching over to &lt;code&gt;createContext&lt;/code&gt;, I had hoped that it would be a potential boost to performance.  After all, we would be going from N subscriber calls on every action down to just 1.  Unfortunately, that isn&#39;t the case.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;In &lt;em&gt;artificial stress test benchmarks&lt;/em&gt;, v6 was generally slower than v5.... but the amount varies, and the reasons are complex.&lt;/strong&gt;&lt;/p&gt;

&lt;h4 id=&#34;understanding-the-performance-differences&#34;&gt;Understanding the Performance Differences&lt;/h4&gt;

&lt;p&gt;In v5, a dispatched action would result in N subscriber callbacks executing.  But, thanks to the heavily memoized selector functions used with &lt;code&gt;connect&lt;/code&gt;, only wrapper components whose data had changed would actually call &lt;code&gt;this.setState()&lt;/code&gt; to trigger a re-render.  That meant that React only got involved when updates were needed.&lt;/p&gt;

&lt;p&gt;In v6, &lt;code&gt;&amp;lt;Provider&amp;gt;&lt;/code&gt; has the only subscriber callback.  However, in order to safely handle state changes, it immediately calls &lt;code&gt;setState()&lt;/code&gt; using the functional updater form:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-js&#34;&gt;    this.unsubscribe = store.subscribe(() =&amp;gt; {
      const newStoreState = store.getState()

      if (!this._isMounted) {
        return
      }

      this.setState(providerState =&amp;gt; {
        // If the value is the same, skip the unnecessary state update.
        if (providerState.storeState === newStoreState) {
          return null
        }

        return { storeState: newStoreState }
      })
    })
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It does try to optimize some by skipping any further work if the store state hasn&#39;t changed, but this means that &lt;strong&gt;React will immediately and always get involved after each dispatched action.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The next issue is that &lt;strong&gt;React has to trace through the component tree to find all of the matching context consumers&lt;/strong&gt;.  In a simple app structure, React would sort of do this automatically anyway, because calling &lt;code&gt;setState()&lt;/code&gt; in the root component would recursively cause the entire component tree to be re-rendered.&lt;/p&gt;

&lt;p&gt;However, many components in the tree may be blocking updates, whether it be manually-implemented &lt;code&gt;shouldComponentUpdate -&amp;gt; false&lt;/code&gt;, instances of &lt;code&gt;PureComponent&lt;/code&gt; or &lt;code&gt;React.memo()&lt;/code&gt;, or &lt;code&gt;connect&lt;/code&gt; wrappers that are skipping re-renders of their children.  Let&#39;s assume for sake of the example that the topmost &lt;code&gt;&amp;lt;App&amp;gt;&lt;/code&gt; component simply has &lt;code&gt;shouldComponentUpdate -&amp;gt; false&lt;/code&gt;, thus blocking updates further down when &lt;code&gt;&amp;lt;Provider&amp;gt;&lt;/code&gt; calls &lt;code&gt;setState()&lt;/code&gt;.  In this case, React still has to traverse the entire rendered component tree to find all the consumers.&lt;/p&gt;

&lt;p&gt;React is fast, but that work does take time.  The speed of context updates affects more than just React-Redux.  The maintainer of &lt;code&gt;react-beautiful-dnd&lt;/code&gt; opened up &lt;strong&gt;&lt;a href=&#34;https://github.com/facebook/react/issues/13739&#34;&gt;React issue #13739: React Context value propagation performance&lt;/a&gt;&lt;/strong&gt; to discuss some of the perf implications.  In that thread, Dan and Dominic suggested that the current handling of nested context updates is somewhat naive, and could potentially be optimized further down the road.&lt;/p&gt;

&lt;h4 id=&#34;performance-benchmarks&#34;&gt;Performance Benchmarks&lt;/h4&gt;

&lt;p&gt;When I finished cleanup and optimization on the PR that became v6 beta, I did a final set of runs against our benchmarks.  &lt;a href=&#34;https://github.com/reduxjs/react-redux/pull/1000#issuecomment-436140264&#34;&gt;You can view those benchmark results here&lt;/a&gt;.  Summarizing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Both an earlier WIP v6 iteration and the final version of the v6 PR were slower than v5, in all benchmark scenarios&lt;/li&gt;
&lt;li&gt;That said, the final v6 build was by far the fastest of the v6 versions&lt;/li&gt;
&lt;li&gt;The amount of relative slowdown varied based on the benchmark scenario.  It was most pronounced with a totally flat tree of rapidly-updating components (~20% slower), much less so with deeper trees and other update patterns (2% slower).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I&#39;d like to re-emphasize that &lt;strong&gt;these are totally artificial stress-test benchmarks!&lt;/strong&gt;.  We needed some way to objectively compare different builds for performance, and so we set up scenarios that deliberately cranked up the numbers of components and frequency of dispatched actions until all the builds began slowing down.&lt;/p&gt;

&lt;p&gt;(Note: I&#39;d happily accept more help from the community in fleshing out the benchmarks suite, to help us come up with some more realistic scenarios.  Also, anyone ought to be able to clone the benchmarks repo, drop in a particular build of React-Redux, and replicate the approximate results on your own machine.)&lt;/p&gt;

&lt;h2 id=&#34;v7-0&#34;&gt;v7.0&lt;/h2&gt;

&lt;h3 id=&#34;motivations-1&#34;&gt;Motivations&lt;/h3&gt;

&lt;p&gt;I&#39;ve observed a number of times that the single best way to get feedback on a piece of software is to release it as a final version.  Doesn&#39;t matter how much you advertise alphas and betas, and beg people to try them out, A) most people won&#39;t try them out, and B) the few folks who do simply can&#39;t match the breadth of ways that people are using your code.&lt;/p&gt;

&lt;p&gt;v6 fit that pattern to a T.  Soon after we released it, folks began filing issues listing various issues they encountered trying to upgrade.  The most common issue was actually with third-party libraries that were trying (and now failing) to access the store directly.  Notable examples included &lt;code&gt;connected-react-router&lt;/code&gt;, &lt;code&gt;react-redux-firebase&lt;/code&gt;, &lt;code&gt;react-redux-subspace&lt;/code&gt;, and even &lt;code&gt;redux-form&lt;/code&gt;.  We couldn&#39;t do anything about that, beyond poke maintainers and offer some suggestions on an upgrade path.&lt;/p&gt;

&lt;p&gt;Other issues, however, were more concerning.  The biggest one was performance.  Despite my hopes that v6 would be &amp;quot;fast enough&amp;quot; in real-world apps, several users &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/1164&#34;&gt;complained of noticeable slowdowns in various scenarios&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Another major issue was that our use of context turned out to be a bad foundation for eventually creating a hooks-based API.  There was a giant React discussion issue on &lt;a href=&#34;https://github.com/facebook/react/issues/14110&#34;&gt;potential ways to bail out of updates caused by context in function components&lt;/a&gt;.  Despite some early promising comments, it ultimately resulted in the React team saying that they weren&#39;t going to address that particular use case any time soon.  In addition, Sebastian Markbage specifically described new context as &lt;a href=&#34;https://github.com/facebook/react/issues/14110#issuecomment-448074060&#34;&gt;&amp;quot;not meant to be used for Flux-like state propagation&amp;quot;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Finally, a few specific (but vocal) users raised concerns about &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/1161&#34;&gt;the removal of &lt;code&gt;store&lt;/code&gt; as a prop&lt;/a&gt;.  The combination of Enzyme&#39;s implementation and limitations, and our use of context, effectively made it impossible for them to continue shallow-testing connected components.&lt;/p&gt;

&lt;p&gt;In response, in early February 2019 I filed &lt;strong&gt;&lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/1177&#34;&gt;issue #1177: React-Redux Roadmap: v6, Context, Subscriptions, and Hooks&lt;/a&gt;&lt;/strong&gt;.  It&#39;s a monster post, laying out those concerns in greater detail, and trying to establish a direction for what a potential v7 might look like that would solve those issues.  Rather than duplicate it here, please read through it to understand the challenges and how the process evolved.&lt;/p&gt;

&lt;p&gt;In particular, the React team (and specifically Dan Abramov and Sebastian Markbage) encouraged us to move back to using direct store subscriptions in components to improve performance.  Dan also encouraged us to make use of React&#39;s &lt;code&gt;unstable_batchedUpdates()&lt;/code&gt; API as well.&lt;/p&gt;

&lt;h3 id=&#34;development&#34;&gt;Development&lt;/h3&gt;

&lt;p&gt;When I filed that roadmap issue, I didn&#39;t have any specific ideas on how we were going to reimplement &lt;code&gt;connect&lt;/code&gt; to achieve them.  Fortunately, I had some free time on my hands, and jumped right into experimenting with ideas.&lt;/p&gt;

&lt;p&gt;Given the constraints we&#39;d seen with accessing context in class component lifecycles, &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/1177#issuecomment-461185008&#34;&gt;I opted to try a brand-new implementation using React&#39;s new hooks APIs&lt;/a&gt;.  I ended up bringing back the custom &lt;code&gt;Subscription&lt;/code&gt; class from v5, but the &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/1177#issuecomment-461678923&#34;&gt;initial benchmark results weren&#39;t promising&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A day later, though, I made a breakthrough: &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/1177#issuecomment-461699799&#34;&gt;wrapping &lt;code&gt;connect&lt;/code&gt; in &lt;code&gt;React.memo()&lt;/code&gt;&lt;/a&gt; drastically improved performance!  Comparisons showed it was at &lt;em&gt;least&lt;/em&gt; as fast as v5, and even faster in some scenarios.&lt;/p&gt;

&lt;p&gt;I began publishing alphas for people to play with.  Over the next few weeks, the community poked and prodded, and found several issues that we fixed.  At one point, I wrote &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/1177#issuecomment-468959889&#34;&gt;an insanely detailed step-by-step data flow analysis comparing how v5, v6, v7-alpha.1, and v7-alpha.2 process updates and re-renders&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The mile-long issue thread had a number of digressions and debates on various topics, including the need for tiered subscriptions, if a class component approach could still work, whether peer dependency bumps require a new major version of this package, and much more.&lt;/p&gt;

&lt;p&gt;Finally, in early April, we published &lt;strong&gt;&lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v7.0.1&#34;&gt;React-Redux v7.0&lt;/a&gt;&lt;/strong&gt; as final.  The reception has been universally positive.  Folks who were seeing slowdowns with v6 reported that v7 was vastly faster across the board.&lt;/p&gt;

&lt;h3 id=&#34;implementation-notes-2&#34;&gt;Implementation Notes&lt;/h3&gt;

&lt;h4 id=&#34;connect-is-implemented-using-hooks&#34;&gt;&lt;code&gt;connect&lt;/code&gt; Is Implemented Using Hooks&lt;/h4&gt;

&lt;p&gt;The &lt;code&gt;connect&lt;/code&gt; wrapper component had always been a class component.  As of v7, &lt;a href=&#34;https://github.com/reduxjs/react-redux/blob/5c69baf817527ee9a742c9dc4d541945cb7d1719/src/components/connectAdvanced.js#L158&#34;&gt;&lt;code&gt;connect&lt;/code&gt; is now a function component that uses hooks inside&lt;/a&gt;.  This made some aspects simpler (access to values from context, easy memoization of child elements), but complicated others (timing of effect callbacks).&lt;/p&gt;

&lt;p&gt;We initially executed subscriptions in &lt;code&gt;useEffect()&lt;/code&gt;, but later concluded we needed to use &lt;code&gt;useLayoutEffect()&lt;/code&gt; to ensure they&#39;re added synchronously.  Unfortunately, the React team chose to &lt;a href=&#34;https://github.com/facebook/react/issues/14927&#34;&gt;print warnings when &lt;code&gt;useLayoutEffect()&lt;/code&gt; is used in an SSR environment&lt;/a&gt;.  We had to do &lt;a href=&#34;https://github.com/reduxjs/react-redux/blob/01966db91e33aca533bb62f9f7a69ccd16ba6282/src/components/connectAdvanced.js#L35-L45&#34;&gt;some hacky environment detection  and call &lt;code&gt;useEffect()&lt;/code&gt; in SSR instead&lt;/a&gt;.  Neither of them run, but at least &lt;code&gt;useEffect()&lt;/code&gt; doesn&#39;t warn.&lt;/p&gt;

&lt;h4 id=&#34;the-return-of-direct-component-subscriptions&#34;&gt;The Return of Direct Component Subscriptions&lt;/h4&gt;

&lt;p&gt;As with v5 and earlier, v7 wrapper components all subscribe to the store directly, and only get React involved when the selector logic determines that the wrapper component needs to re-render.  This was the first key step in bringing performance back to the level of v5.&lt;/p&gt;

&lt;h4 id=&#34;use-of-react-s-batched-updates-api&#34;&gt;Use of React&#39;s Batched Updates API&lt;/h4&gt;

&lt;p&gt;React has always had an API called &lt;code&gt;unstable_batchedUpdates()&lt;/code&gt;.  Internally, React wraps all your event handlers inside of that, which is what allows React to batch together multiple state updates from one event tick into a single render pass.&lt;/p&gt;

&lt;p&gt;The React team urged us to use &lt;code&gt;unstable_batchedUpdates()&lt;/code&gt; directly in React-Redux.  This was tricky, because it&#39;s actually exported from renderers like ReactDOM and React Native, not the core React package.  React-Redux &lt;em&gt;should&lt;/em&gt; work with any React renderer, so we couldn&#39;t add a direct dependency on either of those.  We had to write some different wrapper files so that the &lt;code&gt;&amp;quot;react-dom&amp;quot;&lt;/code&gt; import would get loaded in a web environment, and the &lt;code&gt;&amp;quot;react-native&amp;quot;&lt;/code&gt; import when used with RN.  For apps that might be using React-Redux with an alternate renderer, we added an additional entry point that falls back to a dummy batching implementation.&lt;/p&gt;

&lt;p&gt;There have been &lt;a href=&#34;https://github.com/tappleby/redux-batched-subscribe&#34;&gt;other Redux addons that make use of batched updates&lt;/a&gt;.  I didn&#39;t want to dictate anything about what enhancers and store setup were needed.  Instead, I was able to
&lt;a href=&#34;https://github.com/reduxjs/react-redux/blob/5c69baf817527ee9a742c9dc4d541945cb7d1719/src/utils/Subscription.js#L25-L299&#34;&gt;use the batching inside our custom &lt;code&gt;Subscription&lt;/code&gt; class&lt;/a&gt;, and &lt;a href=&#34;https://github.com/reduxjs/react-redux/blob/5c69baf817527ee9a742c9dc4d541945cb7d1719/src/components/Provider.js#L13&#34;&gt;updated &lt;code&gt;&amp;lt;Provider&amp;gt;&lt;/code&gt; to create a root subscription&lt;/a&gt;.&lt;/p&gt;

&lt;h4 id=&#34;use-of-react-memo-for-prop-optimizations&#34;&gt;Use of &lt;code&gt;React.memo()&lt;/code&gt; for Prop Optimizations&lt;/h4&gt;

&lt;p&gt;&lt;code&gt;connect&lt;/code&gt; has always implemented optimizations similar to what &lt;code&gt;React.PureComponent&lt;/code&gt; now does, but more extensive.  It does checks on incoming props from the parent component, but ultimately only renders if the &lt;em&gt;merged&lt;/em&gt; &lt;code&gt;stateProps + dispatchProps + ownProps&lt;/code&gt; have changed.&lt;/p&gt;

&lt;p&gt;React 16.6 introduced &lt;a href=&#34;https://reactjs.org/docs/react-api.html#reactmemo&#34;&gt;&lt;code&gt;React.memo()&lt;/code&gt;&lt;/a&gt; as an alternative to use of &lt;code&gt;shouldComponentUpdate&lt;/code&gt; or &lt;code&gt;PureComponent&lt;/code&gt;.  Like &lt;code&gt;PureComponent&lt;/code&gt;, it checks to see if updates are necessary by doing a shallow comparison of previous and current props.  Unlike &lt;code&gt;PureComponent&lt;/code&gt;, which is an alternate base class component, &lt;code&gt;React.memo()&lt;/code&gt; is a new component type that can wrap around either class or function components.  In addition, it returns a very special object that looks like &lt;code&gt;{$$typeof: REACT_MEMO_TYPE, type : WrappedComponent, compareFunction}&lt;/code&gt; (&lt;a href=&#34;https://github.com/facebook/react/blob/769b1f270e1251d9dbdce0fcbd9e92e502d059b8/packages/react/src/memo.js#L27-L31&#34;&gt;see implementation reference&lt;/a&gt;).  This is interesting, because up until now all React components have been functions of some kind (as JS classes are actually functions).  For the first time, a React component type may actually be an object instead, and so code that tries to determine if a value is a component by seeing if it&#39;s a function is now wrong.&lt;/p&gt;

&lt;p&gt;Naturally, this meant that once we released v7, we began getting issues saying that people&#39;s code had broken because there were checks expecting all components are functions.&lt;/p&gt;

&lt;h3 id=&#34;api-changes-1&#34;&gt;API Changes&lt;/h3&gt;

&lt;h4 id=&#34;return-of-store-as-a-prop&#34;&gt;Return of &lt;code&gt;store&lt;/code&gt; as a Prop&lt;/h4&gt;

&lt;p&gt;Now that components are subscribing to the store themselves again, it was easy to re-add the ability for connected components to accept &lt;code&gt;store&lt;/code&gt; as a prop once more.  That resolved the issues from it being removed.&lt;/p&gt;

&lt;h4 id=&#34;new-batch-api&#34;&gt;New &lt;code&gt;batch()&lt;/code&gt; API&lt;/h4&gt;

&lt;p&gt;Since we&#39;d already gone to the trouble of ensuring that we could import &lt;code&gt;unstable_batchedUpdates()&lt;/code&gt; in both web and RN environments, we decided to re-export it as a public API named &lt;code&gt;batch()&lt;/code&gt;.  This allows end users to wrap parts of their code that are triggering multiple state updates outside of React&#39;s event handlers (such as an async function or a thunk), and minimize the number of re-renders that occur.&lt;/p&gt;

&lt;h2 id=&#34;v7-1-hooks&#34;&gt;v7.1: Hooks?!?!&lt;/h2&gt;

&lt;h3 id=&#34;motivations-2&#34;&gt;Motivations&lt;/h3&gt;

&lt;p&gt;As soon as React hooks were announced, &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/1063&#34;&gt;people began asking when React-Redux would include a hooks-based public API&lt;/a&gt;.  (The React Hooks FAQ &lt;a href=&#34;https://reactjs.org/docs/hooks-faq.html#what-do-hooks-mean-for-popular-apis-like-redux-connect-and-react-router&#34;&gt;even mentioned &amp;quot;&lt;code&gt;useRedux()&amp;quot;&lt;/code&gt; as a hypothetical hook&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;By the time React hooks were officially released, there were already &lt;a href=&#34;https://twitter.com/adamklein500/status/1072457324932067329&#34;&gt;numerous third-party Redux hooks libraries&lt;/a&gt;.  (I later put together &lt;a href=&#34;https://docs.google.com/spreadsheets/d/1JfjcpaZkNjRLzA35uuPQpDLfKc-Z8LqSP7GJaUjH19o&#34;&gt;a spreadsheet comparing the various library APIs and their popularity&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;Clearly, it was a question of &lt;em&gt;when&lt;/em&gt; we would develop and publish a hooks API, not &amp;quot;if&amp;quot;.&lt;/p&gt;

&lt;h3 id=&#34;development-1&#34;&gt;Development&lt;/h3&gt;

&lt;p&gt;The v7.0 work derailed the hooks API discussions for a while.  As we found out in &lt;a href=&#34;https://github.com/facebook/react/issues/14110&#34;&gt;React #14110: Provide more ways to bail out inside Hooks&lt;/a&gt;, there&#39;s no way to stop updates caused by &lt;code&gt;useContext()&lt;/code&gt;.  That incredibly long discussion led to the React team advising us to switch back to direct subscriptions, and that meant that getting v7.0 out the door was a prerequisite for any kind of a hooks API.&lt;/p&gt;

&lt;p&gt;After the initial hooks discussion thread got derailed, I &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/1179&#34;&gt;opened up a new API discussion thread&lt;/a&gt; in February based on some of the v7 discussions.   The discussion continued there for a while, but I didn&#39;t pay much attention.  In fact, as of late March 2019, &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/1179#issuecomment-475722015&#34;&gt;I replied to an &amp;quot;ETA?&amp;quot; question saying I was busy, and it was unlikely to be any time soon&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;But, with v7 in beta and nearing release, my mind started poking at the hooks question.  About that time, I &lt;a href=&#34;https://twitter.com/acemarke/status/1109520804860051456&#34;&gt;published a Twitter poll asking what I should focus my time on next&lt;/a&gt;, and 82% selected &amp;quot;Hooks&amp;quot;.  Clearly, the people had spoken :)&lt;/p&gt;

&lt;p&gt;I started actively participating in the discussion thread, and we soon figured out there were some major issues we&#39;d have to deal with.  In particular, we couldn&#39;t enforce top-down updates in a hooks environment, because v7 relies on overriding context values to pass down nested &lt;code&gt;Subscription&lt;/code&gt; instances, and you can&#39;t render context values from a hook.  This meant users would potentially encounter the &amp;quot;zombie child&amp;quot; issue again.&lt;/p&gt;

&lt;p&gt;I finally spent a couple days doing some analysis of all the third-party hooks libs I&#39;d seen and the various approaches that had been offered, and wrote &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/1179#issuecomment-480547676&#34;&gt;a summary of how I thought we might be able to move forward&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There were some ensuing digressions on topics such as use of Proxies to track updates and whether we could use the v6 and v7 approaches in parallel.  After much extended debate, we concluded that we&#39;d basically just have to give up on a technical solution to the &amp;quot;zombie child&amp;quot; issue, document the potential concerns, and move on.&lt;/p&gt;

&lt;p&gt;A user named Jonathan Ziller had put together a package implementing his proposed set of hooks APIs, and &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/1179#issuecomment-484559515&#34;&gt;I finally suggested we should take that implementation as a PR&lt;/a&gt;.  After more bikeshedding over hook names, &lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v7.1.0-alpha.1&#34;&gt;we finally published our first alpha&lt;/a&gt;, which contained five hooks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;useSelector&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;useActions&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;useDispatch&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;useRedux&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;useStore&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The alpha cycle led to &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/1252&#34;&gt;another monster discussion thread (250 comments)&lt;/a&gt;.  During that process, we made three major changes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v7.1.0-alpha.3&#34;&gt;v7.1-alpha.3 dropped &lt;code&gt;useRedux&lt;/code&gt;&lt;/a&gt;, on the grounds that it didn&#39;t provide anything useful&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v7.1.0-alpha.4&#34;&gt;v7.1-alpha.4 dropped &lt;code&gt;useActions&lt;/code&gt;&lt;/a&gt;, after Dan Abramov strongly argued that it added too much complexity (including naming and variable scoping clashes)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v7.1.0-alpha.5&#34;&gt;v7.1-alpha.5 changed from shallow to reference equality for determining updates&lt;/a&gt;, under the idea that users would be more likely to select specific values rather than returning grouped objects&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After sitting in alpha for a couple months, we finally zoomed through the RC stage and put out &lt;strong&gt;&lt;a href=&#34;https://github.com/reduxjs/react-redux/releases/tag/v7.1.0&#34;&gt;React-Redux v7.1.0&lt;/a&gt;&lt;/strong&gt; in early June.  (I was about to give &lt;a href=&#34;https://blog.isquaredsoftware.com/2019/06/presentation-react-redux-deep-dive/&#34;&gt;a talk based on this post at ReactNext&lt;/a&gt;, so we ended up publishing v7.1 the night before the talk so I could announce it was live.)&lt;/p&gt;

&lt;h3 id=&#34;api-changes-2&#34;&gt;API Changes&lt;/h3&gt;

&lt;h5 id=&#34;hooks&#34;&gt;Hooks!&lt;/h5&gt;

&lt;p&gt;As mentioned, we ultimately wound up shipping three hooks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;useSelector&lt;/code&gt;: subscribes to the store and returns the selected value&lt;/li&gt;
&lt;li&gt;&lt;code&gt;useDispatch&lt;/code&gt;: returns the store&#39;s &lt;code&gt;dispatch&lt;/code&gt; function&lt;/li&gt;
&lt;li&gt;&lt;code&gt;useStore&lt;/code&gt;: returns the store instance itself&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Due to the lack of top-down subscription enforcement, we made sure to &lt;a href=&#34;https://react-redux.js.org/api/hooks#usage-warnings&#34;&gt;document potential edge cases&lt;/a&gt; so that people are aware of those issues.&lt;/p&gt;

&lt;p&gt;We also ended up adding &lt;a href=&#34;https://react-redux.js.org/api/hooks#hooks-recipes&#34;&gt;copy-pasteable recipes for &lt;code&gt;useActions&lt;/code&gt; and &lt;code&gt;useShallowEqualSelector&lt;/code&gt;&lt;/a&gt; to the docs as well.&lt;/p&gt;

&lt;h2 id=&#34;the-future&#34;&gt;The Future&lt;/h2&gt;

&lt;p&gt;The existing &lt;code&gt;connect&lt;/code&gt; API has been incredibly successful overall, and there&#39;s hundreds of thousands of apps using it.  Our hooks API is new and certainly not as battle-tested, but we iterated on it sufficiently that I&#39;m confident in how it works.&lt;/p&gt;

&lt;p&gt;I&#39;m truly hoping that React-Redux has stabilized after all the v6/v7 churn.  I&#39;m thankful that we managed to keep the public APIs consistent, since that meant that most folks were able to upgrade v5-&amp;gt;v6-&amp;gt;v7 without any real breaking changes.  Still, I dislike that we&#39;ve had to bump through a couple major versions, and hopefully we can leave things alone for a while.&lt;/p&gt;

&lt;p&gt;But, a maintainer&#39;s work is never done.  Some possible future considerations:&lt;/p&gt;

&lt;h3 id=&#34;alternate-apis&#34;&gt;Alternate APIs&lt;/h3&gt;

&lt;p&gt;Prior to the announcement of hooks, we were frequently asked to provide  &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/799&#34;&gt;a &amp;quot;render props&amp;quot; form of &lt;code&gt;connect&lt;/code&gt;&lt;/a&gt;.  Now that hooks are a thing, that&#39;s unlikely to ever happen.&lt;/p&gt;

&lt;p&gt;Beyond that, perhaps there&#39;s some alternative API approach that would be easier to use and work better with concurrent React down the road, and we just haven&#39;t thought of it yet.&lt;/p&gt;

&lt;h3 id=&#34;concurrent-react&#34;&gt;Concurrent React&lt;/h3&gt;

&lt;p&gt;The React world has been eagerly awaiting the release of React&#39;s &amp;quot;Concurrent Mode&amp;quot; since Dan helped publicize it in his &lt;a href=&#34;https://reactjs.org/blog/2018/03/01/sneak-peek-beyond-react-16.html&#34;&gt;JSConf Iceland 2018 talk &amp;quot;Beyond React 16&amp;quot;&lt;/a&gt;.  The React team published &lt;a href=&#34;https://reactjs.org/blog/2018/11/27/react-16-roadmap.html&#34;&gt;a roadmap in late 2018&lt;/a&gt; suggesting they hoped to have it out by mid-2019, but as of June that hasn&#39;t happened yet, and recent comments indicate it&#39;ll still be a while.&lt;/p&gt;

&lt;p&gt;Flarnie Marchan (formerly on the React core team) did a great talk at ReactNext in June entitled &lt;a href=&#34;https://youtu.be/V1Ly-8Z1wQA&#34;&gt;&amp;quot;Ready for Concurrent Mode?&amp;quot;&lt;/a&gt;, where she laid how a summary of how Concurrent Mode works and some potential issues with existing code.  It&#39;s very worth watching.&lt;/p&gt;

&lt;p&gt;Long-term, we don&#39;t know how React-Redux will be able to fully interact with Concurrent Mode, largely because it isn&#39;t out and documented yet for us to be able to understand it.  Someone just filed &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/1351&#34;&gt;an issue asking about our Concurrent Mode compat status&lt;/a&gt;, and the answer is: &amp;quot;we dunno, we&#39;ll figure it out down the road&amp;quot;.  Keep an eye on that issue for future discussions.&lt;/p&gt;

&lt;h3 id=&#34;future-context-improvements&#34;&gt;Future Context Improvements?&lt;/h3&gt;

&lt;p&gt;The most disappointing thing about v6 is that it &lt;em&gt;worked&lt;/em&gt;, it just wasn&#39;t fast enough for real-world usage.  It&#39;s possible that React might someday make changes to the context API that would allow us to reconsider context-based state propagation as a viable approach again.&lt;/p&gt;

&lt;p&gt;As a potential example, Josh Story just filed React RFCs describing two potential rewrites of context:  &lt;a href=&#34;https://github.com/reactjs/rfcs/pull/118&#34;&gt;lazy context propagation&lt;/a&gt; for faster updates with less overhead, and &lt;a href=&#34;https://github.com/reactjs/rfcs/pull/119&#34;&gt;context selectors&lt;/a&gt; to determine if contexts should update, as a replacement for &lt;code&gt;observedBits&lt;/code&gt;.  He also filed a proof-of-concept React-Redux PR &lt;a href=&#34;https://github.com/reduxjs/react-redux/pull/1350&#34;&gt;to rewrite &lt;code&gt;connect&lt;/code&gt; to use that context selectors implementation&lt;/a&gt;.  Obviously, a lot would have to happen before we could ever actually use that (RFCs accepted, changes merged into React, new versions published), and it would require a new major version of React-Redux, but there&#39;s some potential there.&lt;/p&gt;

&lt;h3 id=&#34;magic&#34;&gt;Magic?&lt;/h3&gt;

&lt;p&gt;Back when v6 was in development, I wrote a long post on ways we could potentially use Proxies for tracking state dependencies and optimize context updates based on that info: &lt;a href=&#34;https://github.com/reduxjs/react-redux/issues/1018&#34;&gt;React-Redux issue #1018: Investigate use of context + observedBits for performance optimization&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Since then, Daishi Kato has been experimenting with various similar approaches, and currently has a small library called &lt;a href=&#34;https://github.com/dai-shi/reactive-react-redux&#34;&gt;&lt;code&gt;reactive-react-redux&lt;/code&gt;&lt;/a&gt; that implements a Proxy-based &lt;code&gt;useTrackedState()&lt;/code&gt; hook as an alternative to React-Redux.  Long-term, that kind of approach is very intriguing.&lt;/p&gt;

&lt;p&gt;I&#39;d certainly love to hear feedback from the community on what forms of &amp;quot;magic&amp;quot; are acceptable, especially around optimizing component updates.&lt;/p&gt;

&lt;h2 id=&#34;final-thoughts&#34;&gt;Final Thoughts&lt;/h2&gt;

&lt;p&gt;Hopefully this journey through time and release notes has been informative.  As you&#39;ve seen, &lt;strong&gt;React-Redux has never been &amp;quot;magic&amp;quot; - just smart about implementing optimizations so you don&#39;t have to&lt;/strong&gt;.  For all the internal complexity, it&#39;s still just a matter of subscribing to the store, checking to see what data your component needs, and re-rendering it when necessary.  The implementations have changed, but the goals haven&#39;t.&lt;/p&gt;

&lt;p&gt;This should also help explain &lt;strong&gt;why you should use React-Redux instead of trying to write subscription logic yourself in your components&lt;/strong&gt;.  The Redux team has put countless hours into optimizing performance, handling edge cases, and dealing with changes in the ecosystem.  You should take advantage of all the hard work that&#39;s gone into this API! :)&lt;/p&gt;

&lt;p&gt;As always, if you&#39;ve got questions, please leave a comment, file an issue, or ping me &lt;strong&gt;@acemarke&lt;/strong&gt; on Reactiflux and Twitter.&lt;/p&gt;

&lt;h2 id=&#34;further-information&#34;&gt;Further Information&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://blog.isquaredsoftware.com/2019/06/presentation-react-redux-deep-dive/&#34;&gt;ReactNext 2019 talk: A Deep Dive into React_Redux&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
    <item>
      <title>Rewriting Your Git History and JS Source for Fun and Profit</title>
      <link>https://blog.isquaredsoftware.com/2018/11/git-js-history-rewriting/</link>
      <pubDate>Sat, 17 Nov 2018 20:00:00 -0500</pubDate>
      
      <guid>https://blog.isquaredsoftware.com/2018/11/git-js-history-rewriting/</guid>
      <description>&lt;p&gt;&lt;/p&gt;

&lt;h2 id=&#34;intro&#34;&gt;Intro&lt;/h2&gt;

&lt;p&gt;I just completed a large-scale rewrite and cleanup of our team&#39;s Git repository.  I learned a lot working on this task and came up with some nifty and useful techniques in the process, so I&#39;d like to share what I&#39;ve learned.&lt;/p&gt;

&lt;p&gt;In order to keep this post from getting any longer that it already is, I&#39;ll be &lt;strong&gt;&lt;a href=&#34;#further-information&#34;&gt;referencing a bunch of external articles&lt;/a&gt;&lt;/strong&gt; and assuming that you, the reader, have taken the time to read them and understand most of the concepts involved.  That way I can go into more detail on the stuff I actually did.&lt;/p&gt;

&lt;p&gt;To summarize the rest of the cleanup task:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;I filtered out junk files from the repo&#39;s history, shrinking the base repo size by over 70%&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;I automatically rewrote our ES5 Javascript source files to ES6 syntax throughout the entire history, as if they had &amp;quot;always been written that way&amp;quot;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wrote a bunch of scripts and code for this task.  &lt;a href=&#34;https://github.com/markerikson/git-js-repo-history-conversion-utils&#34;&gt;&lt;strong&gt;I&#39;ve created a repo with slightly cleaned-up copies of these scripts for reference&lt;/strong&gt;&lt;/a&gt; .  I&#39;ll show some code snippets in this post, but point to that repo for the full details.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: This post is absurdly technical and deep, even for me :)  Hopefully people find this info useful, but I also don&#39;t expect it to be widely read.  This is mostly a chance for me to publicly document all the stuff I did, as a public service.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4 id=&#34;table-of-contents&#34;&gt;Table of Contents&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#background&#34;&gt;Background&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#filtering-junk-files-from-history&#34;&gt;Filtering Junk Files from History&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#rewriting-js-source-with-codemods&#34;&gt;Rewriting JS Source with Codemods&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#iterating-through-git-history&#34;&gt;Iterating through Git History&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#optimizing-the-transformation-process&#34;&gt;Optimizing the Transformation Process&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#handling-transform-problems&#34;&gt;Handling Transform Problems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#running-the-conversion&#34;&gt;Running the Conversion&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#conversion-results&#34;&gt;Conversion Results&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#final-thoughts&#34;&gt;Final Thoughts&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#further-information&#34;&gt;Further Information&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&#34;background&#34;&gt;Background&lt;/h2&gt;

&lt;h3 id=&#34;why-rewrite-history&#34;&gt;Why Rewrite History?&lt;/h3&gt;

&lt;p&gt;My current project got started about six years ago.  We used Mercurial for the first year, then migrated to Git.  The repo&#39;s &lt;code&gt;.git&lt;/code&gt; folder currently takes up about 2.15GB, with about 15,000 commits.  There&#39;s several reasons for that.  We&#39;ve historically &amp;quot;vendored&amp;quot; third-party libs by committing them directly to the repo, including a lot of Java libraries.  We&#39;ve also had some random junk files that were accidentally committed (like a 135MB JAR file full of test images).&lt;/p&gt;

&lt;p&gt;Unfortunately, &lt;strong&gt;because of how Git works, any file that exists in the historical commits has to be kept around permanently, as long as at least one commit references that file&lt;/strong&gt;.  That means that if you accidentally commit a large file, merge that commit to &lt;code&gt;master&lt;/code&gt;, and then merge a commit that deletes the file, Git still keeps the file&#39;s contents around.&lt;/p&gt;

&lt;p&gt;So, we had junk files in the history that should never have been committed, and we had old libraries and other binaries that were not going to be needed for future development.  We just wrapped up a major development cycle, and I wanted to clean up the repo in preparation for the next dev cycle.  That way everyone&#39;s clones would be smaller, which would also help with CI jobs.&lt;/p&gt;

&lt;h3 id=&#34;dealing-with-history-changes&#34;&gt;Dealing with History Changes&lt;/h3&gt;

&lt;p&gt;However, Git commits form an immutable history.  Every commit references its parents by their hashes. Every commit references its file tree by a hash.  Every file tree references its files by the hashes of their contents.  That means that &lt;strong&gt;if you literally change a single bit in one file at the start of the repo&#39;s history, &lt;em&gt;every&lt;/em&gt; commit after that would have a different hash, and thus effectively form an &amp;quot;alternate history&amp;quot; line that has no relation to the original history&lt;/strong&gt;.  (This is one of the reasons why you should never rebase branches that have already been pushed - it creates a new history chain, and someone else might be relying on the existing history.)&lt;/p&gt;

&lt;p&gt;My plan was to create a fresh clone of our repo, and rewrite its history to filter out the files we didn&#39;t need for future work.  We&#39;d archive the old repo, and when the next dev cycle starts, everyone would clone the new repo and use that for development going forward.&lt;/p&gt;

&lt;h3 id=&#34;the-codebase&#34;&gt;The Codebase&lt;/h3&gt;

&lt;p&gt;Our repo has two separate JS client codebases which talk to the same set of services.  The services are written in a mixture of Python and Java.&lt;/p&gt;

&lt;p&gt;The older JS client codebase, which I&#39;ll call &amp;quot;App1&amp;quot;, started in 2013, and the initial dev cycle resulted in a tangle of jQuery spaghetti and global script tags.  I was able to convert those global scripts to AMD modules about halfway through that first dev cycle, and spent the second half of the year refactoring the codebase to use Backbone.  We continued to use Backbone for new features until early 2017, &lt;a href=&#34;https://blog.isquaredsoftware.com/2017/07/react-redux-backbone-integration/&#34;&gt;when we began adding new features in React+Redux, and refactoring existing features from Backbone to React&lt;/a&gt;.  We didn&#39;t have a true &amp;quot;compile&amp;quot; step in our build process, so we were limited in what JS syntax we could use based on our target browser environment.  I finally upgraded the build system from Require.js to Webpack+Babel in late 2017, and that allowed us to finally start using ES6 modules and ES6+ syntax.  Since then, all of our new files have been written as ES6 modules, and we&#39;ve had to do back-and-forth imports between files in AMD format and files in ES6 module format.&lt;/p&gt;

&lt;p&gt;&amp;quot;App2&amp;quot; was originally written using Google Web Toolkit (GWT), a Java-to-JS compiler.  We completed a ground-up rewrite of that client in React+Redux during this dev cycle (and I took great joy in deleting the GWT codebase, particularly since I&#39;d written almost all of that myself).  This codebase was written using Wepack, Babel, and ES6+ from day 1.&lt;/p&gt;

&lt;p&gt;Because of its longer and varied dev history, App1&#39;s codebase is a classic example of the &lt;a href=&#34;http://mikehadlow.blogspot.com/2014/12/the-lava-layer-anti-pattern.html&#34;&gt;&amp;quot;lava layer anti-pattern&amp;quot;&lt;/a&gt; (and I will freely admit that I&#39;m responsible for most of those layers).  It&#39;s currently about 80% Backbone and 20% React+Redux, and we hope to finish rewriting all the remaining Backbone code to React over the next year or two.  In the meantime, the mixture of AMD and ES6 modules is a bit of a pain.  Webpack will let you use both, but you have to do some annoying workarounds when importing and exporting between files in different module formats (like adding &lt;code&gt;SomeDefaultImport.default&lt;/code&gt; when using an ES6 default export in an AMD file)&lt;/p&gt;

&lt;h3 id=&#34;the-plan-grows&#34;&gt;The Plan Grows&lt;/h3&gt;

&lt;p&gt;Our team hasn&#39;t exactly been consistent with our code styling.  In theory we have a formatting guide we ought to be following, but in practice... eh, whatever :)&lt;/p&gt;

&lt;p&gt;I&#39;ve been planning to set up automatic formatting tools like Prettier for our JS code and Black for our Python code.  However, the downside of adding a code formatter to an existing codebase is that you inevitably wind up with a &amp;quot;big bang&amp;quot; commit that touches almost every line and obscures the actual change history of a given file.  If you do a &lt;code&gt;git blame&lt;/code&gt; (or &amp;quot;annotate&amp;quot;), at some point every line was last changed by &amp;quot;Mark: REFORMATTED ALL THE THINGS&amp;quot;, which isn&#39;t helpful.  There&#39;s ways to skip past that, but it&#39;s annoying.&lt;/p&gt;

&lt;p&gt;At some point I realized that &lt;strong&gt;if I was going to be rewriting the entire commit history anyway by filtering out junk files, then I could &lt;em&gt;also&lt;/em&gt;  apply auto-formatting of the code at every step in the history&lt;/strong&gt;, to make it look as if all our code had &amp;quot;&lt;em&gt;always&lt;/em&gt; been formatted correctly&amp;quot;.  That led me to another bigger realization: &lt;strong&gt;I could do more than just &lt;em&gt;reformat&lt;/em&gt; the code - I could &lt;em&gt;rewrite&lt;/em&gt; the code!&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I&#39;d seen mentions of &amp;quot;codemods&amp;quot; before - automated tools that look for specific patterns in your code and transform them into other patterns.  The React team is especially fond of these, and has provided codemods for things like renaming &lt;code&gt;componentWillReceiveProps&lt;/code&gt; to &lt;code&gt;UNSAFE_componentWillReceiveProps&lt;/code&gt; across an entire codebase.&lt;/p&gt;

&lt;p&gt;it occurred to me that &lt;strong&gt;I could automatically rewrite all of our AMD modules to ES6 modules, and upgrade other syntax to ES6 as well&lt;/strong&gt;.  And, as with the formatting, &lt;strong&gt;I could do this for the &lt;em&gt;entire&lt;/em&gt; Git history, as if the files had been written that way since the beginning&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Naturally, I ran into a bunch of complications along the way, but in the end I accomplished what I set out to do (yay!).  Here&#39;s the details of how I did it.&lt;/p&gt;

&lt;h2 id=&#34;filtering-junk-files-from-history&#34;&gt;Filtering Junk Files from History&lt;/h2&gt;

&lt;p&gt;Short answer: use &lt;a href=&#34;https://rtyley.github.io/bfg-repo-cleaner/&#34;&gt;&lt;strong&gt;The BFG Repo-Cleaner&lt;/strong&gt;&lt;/a&gt;.  Done.&lt;/p&gt;

&lt;p&gt;Slightly longer answer: it does take work to figure out which files and folders you want to delete, and set up a command for the BFG to do its work.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: most of these commands are Bash-based and require a Unix-type environment.  Fortunately, Git Bash will suffice on Windows.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3 id=&#34;finding-files-to-delete&#34;&gt;Finding Files to Delete&lt;/h3&gt;

&lt;p&gt;There&#39;s a couple ways to approach this.&lt;/p&gt;

&lt;p&gt;The first is to look for specific large files in the history.  &lt;a href=&#34;https://stackoverflow.com/a/42544963/62937&#34;&gt;Per this Stack Overflow answer&lt;/a&gt;, here&#39;s a Bash script that will spit out a list of the largest files and their sizes:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;git rev-list --objects --all \
| git cat-file --batch-check=&#39;%(objecttype) %(objectname) %(objectsize) %(rest)&#39; \
| sed -n &#39;s/^blob //p&#39; \
| awk &#39;$2 &amp;gt;= 2^20&#39; \
| sort --numeric-sort --key=2 \
| cut -c 1-12,41- \
| numfmt --field=2 --to=iec-i --suffix=B --padding=7 --round=nearest
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;2^20&lt;/code&gt; searches for files larger than 1MB, and can be adjusted to look for other sizes.&lt;/p&gt;

&lt;p&gt;Anoher approach is to look at the names of every file path that has ever existed in the repo,  to get an idea what might not be relevant any more.  &lt;a href=&#34;https://stackoverflow.com/a/543426/62937&#34;&gt;Thanks again to Stack Overflow for this answer&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;git log --pretty=format: --name-only --diff-filter=A | sort -u &amp;gt; allFilesInRepoHistory.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Skimming through the list of all files turned up a bunch of junk from early in the development history that wasn&#39;t in our current tree, and could safely be removed.&lt;/p&gt;

&lt;h3 id=&#34;preparing-the-filtering-command&#34;&gt;Preparing the Filtering Command&lt;/h3&gt;

&lt;p&gt;The BFG Repo-Cleaner supports deleting top-level folders by name, but not nested folders.  For that, I had to write a script that looked for all files matching a given folder/path prefix, and write all matching blob hashes to a file that could be read by the BFG.  (Pretty sure this started from another SO answer, but can&#39;t find which one atm.)&lt;/p&gt;

&lt;p&gt;First, write a text file called &lt;code&gt;nestedFoldersToRemove.txt&lt;/code&gt; with each path prefix to delete on a separate line:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ParentFolder1/nestedFolder1/
ParentFolder2/nestedFolder2/nestedFolder2a/
ParentFolder3/someFilePrefix
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Then, run this script inside a repo to generate a file containing just the blob IDs that match those prefixes&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;readarray -t folders &amp;lt;  &amp;quot;../nestedFilesToRemove.txt&amp;quot;

for f in &amp;quot;${folders[@]}&amp;quot;
do
    echo &amp;quot;Finding blobs for ${f}...&amp;quot;
    git rev-list --all --objects | grep -P &amp;quot;^\w+ ${f}*&amp;quot; | cut -d&amp;quot; &amp;quot; -f1 &amp;gt;&amp;gt; ../foundFilesToDelete.txt
done
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;If you want to see &lt;em&gt;which&lt;/em&gt; files are getting deleted, remove the &lt;code&gt;| cut -d&amp;quot; &amp;quot; -f1&lt;/code&gt; portion to generate lines like &lt;code&gt;ABCD1234 Path/to/some/file.ext&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Finally, put together a list of the top-level folders you want deleted as well.&lt;/p&gt;

&lt;p&gt;In some cases, I wanted to nuke all the old files in a folder, and only keep what was in there currently.  In those cases I went ahead and specified the whole folder as a search path, because the BFG by default will preserve all files in the current HEAD.&lt;/p&gt;

&lt;h3 id=&#34;running-the-bfg&#34;&gt;Running the BFG&lt;/h3&gt;

&lt;p&gt;Once you know all the files you want cleaned up, you need to make sure that your original repo does not have those in the tip of its history.  If any of them still exist, add commits that delete those files.&lt;/p&gt;

&lt;p&gt;Once that&#39;s done, it&#39;s time to nuke stuff!&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;# Clone the existing repo, without checking out files
git clone --bare originalRepoPath filteredRepo

# Run the BFG, deleting specific top-level folders and nested folders/files
java -jar bfg-1.13.0.jar --delete-folders &amp;quot;{TopLevelFolder1,TopLevelFolder2}&amp;quot; --strip-blobs-with-ids ./fileIdsToDelete.txt filteredRepo
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After the BFG has rewritten the filtered repo, you need to have Git remove any blobs that are no longer referenced:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;git reflog expire --expire=now --all &amp;amp;&amp;amp; git gc --prune=now --aggressive
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You should now have a much smaller repo with the same commit authors and times, but a different line of history.&lt;/p&gt;

&lt;h2 id=&#34;rewriting-js-source-with-codemods&#34;&gt;Rewriting JS Source with Codemods&lt;/h2&gt;

&lt;h3 id=&#34;codemods-for-converting-to-es6&#34;&gt;Codemods for Converting to ES6&lt;/h3&gt;

&lt;p&gt;There&#39;s plenty of tools out there for &lt;a href=&#34;#js-codemods&#34;&gt;rewriting JS source code automatically&lt;/a&gt;.  My main concern was finding codemod transforms to do what I needed: convert our AMD modules to ES6 modules, and then fix up a few more bits of ES6 syntax on top of that.&lt;/p&gt;

&lt;p&gt;I found most of what I needed in two repos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/5to6/5to6-codemod&#34;&gt;5to6/5o6-codemod&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;amd&lt;/code&gt;: converts AMD module syntax to ES6 module syntax&lt;/li&gt;
&lt;li&gt;&lt;code&gt;named-export-generation&lt;/code&gt;: Adds named exports corresponding to default export object keys. Only valid for ES6 modules exporting an object as the default export.&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/cpojer/js-codemod&#34;&gt;cpojer/jscodemod&lt;/a&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;no-vars&lt;/code&gt;: Conservatively converts &lt;code&gt;var&lt;/code&gt; to &lt;code&gt;const&lt;/code&gt; or &lt;code&gt;let&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;object-shorthand&lt;/code&gt;: Transforms object literals to use ES6 shorthand for properties and methods.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;trailing-commas&lt;/code&gt;: Adds trailing commas to array and object literals&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There&#39;s many other transforms I could have used, but this was sufficient for what I wanted to do.&lt;/p&gt;

&lt;h3 id=&#34;writing-a-custom-babel-based-codemod&#34;&gt;Writing a Custom Babel-Based Codemod&lt;/h3&gt;

&lt;p&gt;I mentioned that we had some funkiness in the JS code as a result of cross-importing between AMD and ES6 modules.  One common pattern was that an AMD module would do:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-js&#34;&gt;define([&amp;quot;./someEs6Module&amp;quot;], 
function(someEs6Module) {
    const {named1, named2} = someEs6Module;
});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Transformed into ES6, this would be:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-js&#34;&gt;import someEs6Module from &amp;quot;./someEs6Module&amp;quot;;

const {named1, named2} = someEs6Module;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;However, the ES6 module in question might actually only have named exports, and no default export.  This only worked because of Webpack magic.&lt;/p&gt;

&lt;p&gt;When I tried running the transformed code, Webpack gave me a bunch of errors saying that these imports didn&#39;t exist.  So, I opted to write a codemod that found all named exports, and if there was no default export, generated a fake default export object containing those, as a compatibility hack.&lt;/p&gt;

&lt;p&gt;I couldn&#39;t find anything related to this that worked with &lt;code&gt;jscodeshift&lt;/code&gt;.  However, I did find &lt;a href=&#34;https://github.com/jfeldstein/babel-plugin-export-default-module-exports&#34;&gt;jfeldstein/babel-plugin-export-default-module-exports&lt;/a&gt;, which &lt;em&gt;almost&lt;/em&gt; did what I wanted.  I figured I could hack together some custom changes to it.  Since it was a Babel plugin, I needed a different tool to run that codemod.  Fortunately, &lt;a href=&#34;https://github.com/square/babel-codemod&#34;&gt;square/babel-codemod&lt;/a&gt; lets you run Babel plugins as codemods.&lt;/p&gt;

&lt;p&gt;Thanks to the &lt;a href=&#34;https://astexplorer.net/&#34;&gt;AST Explorer&lt;/a&gt; tool and &lt;a href=&#34;https://twitter.com/acemarke/status/1058047882639613952&#34;&gt;some assistance from Twitter&lt;/a&gt;, I was able to hack together a plugin that did what I needed.&lt;/p&gt;

&lt;h3 id=&#34;initial-conversion-testing&#34;&gt;Initial Conversion Testing&lt;/h3&gt;

&lt;p&gt;I started off by trying to run each of these transforms as a separate step.  I created a shell script that called &lt;code&gt;jscodeshift&lt;/code&gt; multiple times, each with the path to a single transform file.  I also called Prettier to do some formatting.&lt;/p&gt;

&lt;p&gt;While doing that, I ran across some issues with Babel not recognizing the dynamic &lt;code&gt;import()&lt;/code&gt; syntax, so I added a couple &lt;code&gt;sed&lt;/code&gt; commands to rewrite those temporarily:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-bash&#34;&gt;# Before anything else, replace uses of dynamic import
sed -i s/import/require.ensure/g App1/src/entryPoint.js

# Do other transforms
yarn jscodeshift -t path/to/some-transform.js App1/src

yarn codemod -p my-custom-babel-plugin.js App1/src

# Format the code
yarn prettier --config .prettierrc --write &amp;quot;App1/src/**/*.{js,jsx}&amp;quot;

# Undo replacement
sed -i s/require.ensure/import/g App1/src/entryPoint.js
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Using this script, I was able to process a current checkout of our codebase automatically.&lt;/p&gt;

&lt;h3 id=&#34;formatting-python-code&#34;&gt;Formatting Python Code&lt;/h3&gt;

&lt;p&gt;While the majority of my focus was on our JS code, we&#39;ve also got a bunch of Python code on our backend.  I figured I&#39;d take this chance to do some auto-formatting on that as well.  I reviewed the available tools, and settled on &lt;a href=&#34;https://github.com/ambv/black&#34;&gt;Black&lt;/a&gt;, largely because its highly-opinionated style is almost identical to how we were writing our Python anyway.&lt;/p&gt;

&lt;h2 id=&#34;iterating-through-git-history&#34;&gt;Iterating through Git History&lt;/h2&gt;

&lt;p&gt;My ultimate goal was to iterate through every commit in the history of the already-filtered Git repo, find any relevant JS and Python files, transform the versions of the files as they existed in that commit, and create new commits with the same metadata but updated file trees containing the transformed files.&lt;/p&gt;

&lt;p&gt;I&#39;d done some prior research and read through a bunch of articles.  The most relevant was &lt;strong&gt;&lt;a href=&#34;https://wincent.com/blog/filter-branch&#34;&gt;A tale of three filter-branches&lt;/a&gt;&lt;/strong&gt;, which compared three different ways to iterate using the &lt;code&gt;git filter-branch&lt;/code&gt; command, and showed that the third way was the fastest.&lt;/p&gt;

&lt;h3 id=&#34;understanding-the-index-filter-logic&#34;&gt;Understanding the Index Filter Logic&lt;/h3&gt;

&lt;p&gt;In general, &lt;code&gt;git filter-branch&lt;/code&gt; will iterate over the commit history, and run whatever additional commands you want at each commit.  These could be &amp;quot;inline&amp;quot; shell commands, or separate scripts / tools.&lt;/p&gt;

&lt;p&gt;The third approach shown in that post involved using &lt;code&gt;git filter-branch --index-filter&lt;/code&gt;, and checking each commit to see which files had actually been added/changed/deleted.  Fortunately, the author of that post &lt;a href=&#34;https://github.com/wincent/masochist/blob/605eee357f410c842f58cc1774fb957172ad122a/scripts/wiki-to-markdown-filter#L132-L202&#34;&gt;chose to write the per-commit logic as a Ruby script&lt;/a&gt;.  Reading that was extremely helpful in understanding what was going on.&lt;/p&gt;

&lt;p&gt;I&#39;ll summarize the steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Retrieve the current commit ID from the &lt;code&gt;filter-branch&lt;/code&gt; environment&lt;/li&gt;
&lt;li&gt;Look up the original parent commit ID&lt;/li&gt;
&lt;li&gt;Look up the ID for the rewritten form of the parent commit&lt;/li&gt;
&lt;li&gt;Reset the Git index to the tree contents of the rewritten parent commit&lt;/li&gt;
&lt;li&gt;Diff the original parent tree and original commit tree to see which files changed&lt;/li&gt;
&lt;li&gt;For each added/changed/removed file:

&lt;ul&gt;
&lt;li&gt;If it&#39;s a file we&#39;re interested in, transform it, and add the transformed version to the Git index&lt;/li&gt;
&lt;li&gt;Any other added/changed files we don&#39;t care about should just be added to the index as-is&lt;/li&gt;
&lt;li&gt;If it was removed, delete it from the index&lt;/li&gt;
&lt;/ul&gt;&lt;/li&gt;
&lt;li&gt;Create a new commit with the original metadata and the transformed tree&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that the Ruby script was specifically interacting with Git via low-level &amp;quot;plumbing&amp;quot; commands like &lt;code&gt;git cat-file blob&lt;/code&gt; and &lt;code&gt;git update-index&lt;/code&gt;.  In addition, note that it was shelling out to call Git&#39;s commands as external binaries.&lt;/p&gt;

&lt;h3 id=&#34;speeding-up-the-filtering-process-iterating-commits-in-python&#34;&gt;Speeding Up the Filtering Process: Iterating Commits in Python&lt;/h3&gt;

&lt;p&gt;I started by trying to port some of the Ruby script&#39;s logic to Python.  My first attempt was just to run the same Git commands, capture the list of changed files, filter them based on the source paths of the JS and Python files I was interested in, and print those.  I used the great &lt;a href=&#34;https://github.com/tomerfiliba/plumbum&#34;&gt;&lt;code&gt;plumbum&lt;/code&gt;&lt;/a&gt; toolkit to let me easily call external binaries from Python.&lt;/p&gt;

&lt;p&gt;When I tried running &lt;code&gt;git filter-branch --index-filter myScript.py&lt;/code&gt;, it worked.  But, Git estimated that it would take upwards of 16 hours just to iterate through 15K commits and print the list of changed files.  My guess was that a large part of that had to do with kicking off so many external processes (especially since I was doing this in Git Bash on Windows 10).&lt;/p&gt;

&lt;p&gt;I knew that the &lt;a href=&#34;https://libgit2.org/&#34;&gt;&lt;code&gt;libgit2&lt;/code&gt; library&lt;/a&gt; existed, and that there were &lt;a href=&#34;https://www.pygit2.org/&#34;&gt;Python bindings for libgit2&lt;/a&gt;.  I figured the process would run faster if I could somehow do all of the Git commands in a single process, using pygit2 to iterate over the history.&lt;/p&gt;

&lt;p&gt;I experimented with pygit2 and figured out how to iterate over commits using commands like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;for commit in repo.walk(repo.head.target, GIT_SORT_TOPOLOGICAL | GIT_SORT_REVERSE):
    # do something with each commit
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Since pygit2 also has APIs to manipulate the index, I was able to put together a script that replicated the logic from the Ruby script, but all done in-process.  I think the initial script I wrote was able to loop over the history and print every JS/Python file that matched my criteria, in about 30 minutes or so.  Clearly a huge improvement.&lt;/p&gt;

&lt;h3 id=&#34;speeding-up-the-filtering-process-using-pylter-branch&#34;&gt;Speeding Up the Filtering Process: Using &lt;code&gt;pylter-branch&lt;/code&gt;&lt;/h3&gt;

&lt;p&gt;I was curious if anyone else had done something like this already.  I dug through Github, and came across &lt;a href=&#34;https://github.com/sergelevin/pylter-branch&#34;&gt;&lt;code&gt;sergelevin/pylter-branch&lt;/code&gt;&lt;/a&gt;.  Happily, it already did what I wanted in terms of iterating over commits, doing some kind of rewrite step, and saving the results, and provided a base &amp;quot;repo transformation&amp;quot; class that could be subclassed to define the actual transformation step.&lt;/p&gt;

&lt;p&gt;I switched over to using that, and it actually seemed to iterate a bit faster.&lt;/p&gt;

&lt;h2 id=&#34;optimizing-the-transformation-process&#34;&gt;Optimizing the Transformation Process&lt;/h2&gt;

&lt;p&gt;My original plan for the rewrite was to run these steps for each commit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Filter the list of added/changed files for the JS and Python files I was interested in&lt;/li&gt;
&lt;li&gt;Write each original file blob to disk in a temp folder, with names like &lt;code&gt;ABCD1234_actualFilename.js&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Run all of the JS codemods and Python formatting on all files in that folder&lt;/li&gt;
&lt;li&gt;Write the changed files to the Git index and commit&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, I knew that all of the file access and external commands would slow things down, so I began trying to find ways to optimize this process.&lt;/p&gt;

&lt;h3 id=&#34;speeding-up-js-transforms-combining-transforms&#34;&gt;Speeding Up JS Transforms: Combining Transforms&lt;/h3&gt;

&lt;p&gt;I had six different JS codemods I wanted to run.  Five of them required &lt;code&gt;jscodeshift&lt;/code&gt;, the other required &lt;code&gt;babel-codemod&lt;/code&gt;.  Originally, this would have required six separate external processes being kicked off for every commit.&lt;/p&gt;

&lt;p&gt;A comment in the &lt;code&gt;jscodeshift&lt;/code&gt; repo pointed out that &lt;a href=&#34;https://github.com/facebook/jscodeshift/issues/148#issuecomment-282026897&#34;&gt;you could write a custom transform that just imported the others and called them each in sequence&lt;/a&gt;.  Using that idea, I was able to run all five &lt;code&gt;jscodeshift&lt;/code&gt; transforms in one step.&lt;/p&gt;

&lt;p&gt;That left the one Babel plugin-based transform as the outlier.  There was &lt;a href=&#34;https://github.com/facebook/jscodeshift/issues/168#issue-188036301&#34;&gt;a &lt;code&gt;jscodeshift&lt;/code&gt; issue discussing how to use Babel plugins as transforms&lt;/a&gt;, and I was able to adapt Henry&#39;s example to run my plugin inside of &lt;code&gt;jscodeshift&lt;/code&gt;.  That meant all six transforms could run in a single step.&lt;/p&gt;

&lt;p&gt;I ultimately copied the transform files locally so I didn&#39;t have to try installing them as separate dependencies.&lt;/p&gt;

&lt;h3 id=&#34;speeding-up-python-formatting&#34;&gt;Speeding Up Python Formatting&lt;/h3&gt;

&lt;p&gt;That cut down on a lot of the external processes, but I was still writing files to disk for every commit.  Since my script was written in Python, and the Black formatter is also Python, I realized I could probably just call it directly.&lt;/p&gt;

&lt;p&gt;I set up some logic to put all matching Python files into an array that looked like &lt;code&gt;[ {&amp;quot;name&amp;quot; : &amp;quot;ABCD1234_someFile.py&amp;quot;, &amp;quot;source&amp;quot; : &amp;quot;actual source here}]&lt;/code&gt;, and just directly call Black&#39;s &lt;code&gt;format_str()&lt;/code&gt; function on each source string.  That eliminated the need to write any Python file to disk - I could read the source blobs, format them, and write the formatted blobs back to the repo, all in memory without ever writing any temp files to disk.&lt;/p&gt;

&lt;h3 id=&#34;speeding-up-js-transforms-creating-a-persistent-js-transform-server&#34;&gt;Speeding Up JS Transforms: Creating a Persistent JS Transform Server&lt;/h3&gt;

&lt;p&gt;Since the JS transforms were all done using tools written in JS, calling that code directly wasn&#39;t an option.  To solve that, I threw together a tiny Express server that accepted the same kind of file sources array as a POST, directly called the &lt;code&gt;jscodeshift&lt;/code&gt; and &lt;code&gt;prettier&lt;/code&gt; APIs to transform each file in memory, and returned the transformed array.  This meant I didn&#39;t have to have &lt;em&gt;any&lt;/em&gt; temp files written to disk.  It also meant there were no other external processes starting up for every commit.  All I had to do was start the JS transfom server, and kick off the commit iteration script.&lt;/p&gt;

&lt;p&gt;I later realized I could speed up things even further by parallelizing the JS transforms step to handle multiple files at once.  The &lt;a href=&#34;https://github.com/josdejong/workerpool&#34;&gt;&lt;code&gt;workerpool&lt;/code&gt; library&lt;/a&gt; made that trivial to add.  I set up the pool of workers, and for every request, mapped the array to transform calls that returned promises, and did &lt;code&gt;await Promise.all(fileTransforms)&lt;/code&gt;.  This was another great improvement.&lt;/p&gt;

&lt;h2 id=&#34;handling-transform-problems&#34;&gt;Handling Transform Problems&lt;/h2&gt;

&lt;p&gt;I ran into a bunch of problems along the way.  Here&#39;s some of the problems I found and the solutions I settled on.&lt;/p&gt;

&lt;h3 id=&#34;python-string-conversions&#34;&gt;Python String Conversions&lt;/h3&gt;

&lt;p&gt;Both Black and &lt;code&gt;pylter-branch&lt;/code&gt; required Python 3.6, so I was using that.  pygit2 reads blobs as bytes, but some of the work I needed to do required strings.  I also found a few files that had some kind of a &amp;quot;non-breaking space&amp;quot; character instead of actual ASCII spaces.  Fixing this required doing some unicode normalization:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-python&#34;&gt;def normalizeEntry(fileEntry):
    newText = normalize(&amp;quot;NFKD&amp;quot;, str(fileEntry[&amp;quot;source&amp;quot;], &#39;utf-8&#39;, &#39;ignore&#39;))
    return update(fileEntry, {&amp;quot;source&amp;quot;: newText})
&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id=&#34;handling-js-syntax-errors&#34;&gt;Handling JS Syntax Errors&lt;/h3&gt;

&lt;p&gt;Turns out our team had made numerous commits over the years with invalid JS syntax.  This included things like missing closing curly braces, extra parentheses, wrong variable names, Git conflict markers, and more.  Because the JS transforms are all parser-based, both &lt;code&gt;jscodeshift&lt;/code&gt; and &lt;code&gt;prettier&lt;/code&gt; could throw errors if they ran across bad syntax, causing the transforms for that file to fail.&lt;/p&gt;

&lt;p&gt;I first had to know which files were broken, at which commits.  I added error handling to the JS transform server to catch any errors, return the original (untransformed) source, and continue onwards.  I then added handling to write both the current string contents and the error message to disk, like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;- /js-transform-errors
    - /some-commit-id
        - ABCD1234_someFile.js    // bad source file contents
        - ABCD1234_someFile.json  // serialized error message
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I&#39;d run the conversion script for a while, let it write a bunch of errors, then kill it and review them.&lt;/p&gt;

&lt;p&gt;I wound up writing dozens of hand-tested regular expressions to try to fix those files whenever they came up.  Using an interactive Python interpeter (in my case, &lt;a href=&#34;http://www.dreampie.org/&#34;&gt;Dreampie&lt;/a&gt;), I&#39;d read the original blob into a string, fiddle with regexes until I got something that matched the problematic source, create a substitution that fixed the issue, and then paste the search regex and the replacement into a search table in my conversion script.  The conversion logic would then check to see if any file in a given commit matched the bad file paths, and run each provided regex in sequence on the source in memory.  This would fix up the source to be syntactically valid before it was sent to the JS transform server, allowing it to be transformed correctly.&lt;/p&gt;

&lt;p&gt;I eventually gave up on fixing &lt;em&gt;every&lt;/em&gt; last issue.  So, a few files in the history wound up with commit sequences like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;FIXED_SOURCE_C    // ES6 syntax
BROKEN_SOURCE_B   // original AMD syntax
FIXED_SOURCE_A    // ES6 syntax
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Fortunately, most of those were far enough back in the history to not really cause issues with the blames.&lt;/p&gt;

&lt;p&gt;This was probably the most annoying part of the whole task.&lt;/p&gt;

&lt;h3 id=&#34;mistaken-optimization-of-es6-files&#34;&gt;Mistaken Optimization of ES6 Files&lt;/h3&gt;

&lt;p&gt;All of the source files for App2 were already ES6 modules, and about 20% of App1&#39;s files were also ES6.  Five of the six codemods were about converting AMD/ES5 to ES6, so I figured I could speed things up by not running those on files that were already ES6.&lt;/p&gt;

&lt;p&gt;I modified the JS transform server to accept a &lt;code&gt;{formatOnly : true}&lt;/code&gt; flag in the file entries, in which case it would skip the transforms and just run Prettier on the source.  That was fine.&lt;/p&gt;

&lt;p&gt;I then tried to have the Python script detect which files were already ES6, and did so by checking to see if the strings &lt;code&gt;&amp;quot;import &amp;quot;&lt;/code&gt; or &lt;code&gt;&amp;quot;export&lt;/code&gt;&amp;quot; were in the JS source.  That turned out to be a mistake, as we had a bunch of AMD files with those words in comments or source already.  I did one conversion run that I thought would be &amp;quot;final&amp;quot;, but realized afterwards that many files hadn&#39;t been transformed at all.&lt;/p&gt;

&lt;p&gt;I eventually settled for just checking to see if the file was part of App2&#39;s source, and ran the complete transform process on everything in App1.&lt;/p&gt;

&lt;h2 id=&#34;running-the-conversion&#34;&gt;Running the Conversion&lt;/h2&gt;

&lt;p&gt;I did lots of partial and complete trial runs to iron out the issues.  The actual final conversion run, with all of the transforms and formatting, took right about 5 hours to complete.  That&#39;s certainly a huge improvement over the base &lt;code&gt;git filter-branch&lt;/code&gt; command, which probably would have taken upwards of 20-some hours.  (This proved to be particularly helpful when I realized that I&#39;d screwed up a &amp;quot;final&amp;quot; run with the bad &amp;quot;skip ES6&amp;quot; optimization, and had to re-run the whole process again.)&lt;/p&gt;

&lt;p&gt;I had added a bunch of logging to the conversion script, including running values of elapsed time, time per processed commit, and estimated time remaining.  This was really useful, and it was &lt;em&gt;extremely&lt;/em&gt; satisfying to watch the commit details fly by in the terminal.  (Fun side note: a couple hours after kicked off the actual final conversion run in the background, a popup window informed me that IT had pushed through a forced Windows reboot due to updates.  That meant it was a race for the conversion to complete before the reboot, and at one point it was 3.5 hours remaining for the conversion, 3 hours left until the reboot.  Fortunately, the conversion sped up considerably about halfway through thanks to smaller files to process.)&lt;/p&gt;

&lt;p&gt;However, we were still doing some fixes and work in our existing repo, and had made several commits since I made the clone to start the file filtering process.  Those needed to get ported to the new repo, and that turned out to be trickier than I expected.&lt;/p&gt;

&lt;h3 id=&#34;attempt-1-bundles&#34;&gt;Attempt #1: Bundles&lt;/h3&gt;

&lt;p&gt;I&#39;ve used Git &amp;quot;bundles&amp;quot; before, which let you export a series of commits as a single file.  That file can then be transferred to another machine, and used as a source for cloning or pulling commits into another repo.&lt;/p&gt;

&lt;p&gt;I had assumed I could export the latest commits into a bundle and pull those directly into the newly-rewritten repo.  I was wrong :(  Turns out that &lt;code&gt;git bundle&lt;/code&gt; always verifies that the target repo already has the parent commit before the first commit in the bundle, and of course since the rewritten repo had a completely different history line, that specific parent commit ID didn&#39;t exist in the new repo.&lt;/p&gt;

&lt;p&gt;I poked at various forms of pulling, cloning, and banging my head against a wall before giving up on this approach.&lt;/p&gt;

&lt;h3 id=&#34;attempt-2-cherry-picking&#34;&gt;Attempt #2: Cherry-Picking&lt;/h3&gt;

&lt;p&gt;I then figured I could add the original repo as a remote, &lt;code&gt;git fetch&lt;/code&gt; the original commits into the new repo, and cherry-pick them over into the new history.  Didn&#39;t go as I planned.&lt;/p&gt;

&lt;p&gt;First, the new repo had to copy over &lt;em&gt;every&lt;/em&gt; old blob and commit into itself.  Then, when I tried cherry-picking the first &amp;quot;new&amp;quot; commit, it brought along not just the changed files from that commit, but the old versions of every other file in the old commit&#39;s file tree.&lt;/p&gt;

&lt;p&gt;I probably could have done some kind of surgery to make that work, but I gave up.&lt;/p&gt;

&lt;h3 id=&#34;attempt-3-patch-files&#34;&gt;Attempt #3: Patch Files&lt;/h3&gt;

&lt;p&gt;Git was originally intended for use with an email-based workflow, since that&#39;s what the Linux kernel team does.  It has built-in commands for generating patch files, writing emails with those patches, and applying patches from emails.&lt;/p&gt;

&lt;p&gt;I was able to generate a series of patch files with &lt;code&gt;git format-patch COMMIT_BEFORE_FIRST_I_WANT..LAST_COMMIT_I_WANT&lt;/code&gt;.  I then copied those to the new repo, and tried to apply them.&lt;/p&gt;

&lt;p&gt;Git has two related commands.  &lt;code&gt;git apply&lt;/code&gt; takes a single standalone patch file and tries to update your working copy.  &lt;code&gt;git am&lt;/code&gt; reads an email-formatted patch file, applies the diff, and then creates a new commit using the metadata that was encoded in the email header.&lt;/p&gt;

&lt;p&gt;When I tried to use &lt;code&gt;git am&lt;/code&gt;, it failed.  The generated patch files have lines like &lt;code&gt;index  OLD_BLOB_HASH  NEW_BLOB_HASH&lt;/code&gt; for each changed file, and those lines caused Git to try to find the old file blob IDs in the new repo.  Again, those didn&#39;t exist.&lt;/p&gt;

&lt;p&gt;I finally resorted to manually deleting those &lt;code&gt;index&lt;/code&gt; lines from each patch file, then running &lt;code&gt;git am --reject --ignore-whitespace --committer-date-is-author-date *.patch&lt;/code&gt;.  Git would try to apply a patch file, and if any hunks failed to apply correctly, write them to disk as &lt;code&gt;SomeFile.js.rej&lt;/code&gt; and pause.  I could then do manual hand-fixes to match the changes in the patch, and run &lt;code&gt;git am --reject --ignore-whitespace --committer-date-is-author-date  --continue&lt;/code&gt;, and it would pick up where it left off.&lt;/p&gt;

&lt;p&gt;So, patch files aren&#39;t ideal, but they at least allow copying over newer changes semi-automatically while reusing the commit metadata.  I probably could have found other ways to do this programmatically, but oh well.&lt;/p&gt;

&lt;h2 id=&#34;conversion-results&#34;&gt;Conversion Results&lt;/h2&gt;

&lt;p&gt;Nuking unneeded files from the repo history knocked the new repo down from 2.15GB as a baseline to &amp;quot;only&amp;quot; 600MB, a savings of 1.5GB.  We still unfortunately have a bunch of vendored libs with the current codebase, but that&#39;s still a significant improvement.  (Yeah, yeah, we&#39;ll look at maybe using something like Git-LFS down the road.)&lt;/p&gt;

&lt;p&gt;The JS transformation process worked out exactly as I&#39;d hoped.  All of the versions of the JS files in our history were transformed and formatted, as if they&#39;d originally been written using ES6 module syntax and consistent formatting from day 1.  This meant that each commit retained the original metadata and relative diffs to its parent.&lt;/p&gt;

&lt;p&gt;As an example, App1&#39;s entry point was initially a global script, but a couple months into development I converted it into an AMD module.  The original diff looked like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-diff&#34;&gt;+define([&amp;quot;a&amp;quot;, &amp;quot;b&amp;quot;],
+function(a, b) {

// Actual app setup code here

+   return {
+       export1 : variable1,
+       export2 : function2
+   }
+});
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Afterwards, the equivalent commit was still by me, still on the same day, but the diff looked like:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&#34;language-diff&#34;&gt;+import a from &amp;quot;a&amp;quot;;
+import b from &amp;quot;b&amp;quot;;

// Actual app setup code here

+export {export1 : variable1, export2 : function2};
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I did have to do a few hand-fix commits after the conversion process was done, mostly around our mixed use of AMD/ES6 modules (like removing any of use of &lt;code&gt;SomeDefaultImport.default&lt;/code&gt;).  Once I did that, the code ran just fine.&lt;/p&gt;

&lt;h2 id=&#34;final-thoughts&#34;&gt;Final Thoughts&lt;/h2&gt;

&lt;p&gt;As I said, that was incredibly technical, but hopefully it was informative.&lt;/p&gt;

&lt;p&gt;I had a fairly good grasp on how Git worked and how it stored data before this task began, but this really solidified my understanding.&lt;/p&gt;

&lt;p&gt;I suspect there may have been some other approaches I could have used, particularly &lt;a href=&#34;https://www.bitleaks.net/blog/large-scale-git-history-rewrites/&#34;&gt;rewriting each file blob in parallel&lt;/a&gt;.  I&#39;m pretty happy with how this worked out, though.&lt;/p&gt;

&lt;p&gt;The &lt;strong&gt;&lt;a href=&#34;https://github.com/markerikson/git-js-repo-history-conversion-utils&#34;&gt;sanitized conversion scripts are available on Github&lt;/a&gt;&lt;/strong&gt;.  If you&#39;ve got questions, leave a comment or ping me &lt;strong&gt;@acemarke&lt;/strong&gt; on Twitter or Reactiflux.&lt;/p&gt;

&lt;h2 id=&#34;further-information&#34;&gt;Further Information&lt;/h2&gt;

&lt;h4 id=&#34;git-internal-data-structures-blobs-trees-commits-and-hashes&#34;&gt;Git internal data structures: blobs, trees, commits, and hashes&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://codewords.recurse.com/issues/two/git-from-the-inside-out&#34;&gt;Git from the Inside Out&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://jwiegley.github.io/git-from-the-bottom-up/&#34;&gt;Git from the Bottom Up&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://git-scm.com/book/en/v1/Git-Branching-What-a-Branch-Is&#34;&gt;Git - What a Branch Is&lt;/a&gt; (good diagram showing how commits point to prior commits and file trees)&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.tigraine.at/2016/10/22/git-isnt-magic&#34;&gt;Git isn&#39;t magic&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;git-history-rewriting&#34;&gt;Git history rewriting&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://manishearth.github.io/blog/2017/03/05/understanding-git-filter-branch/&#34;&gt;Understanding Git Filter-branch and the Git Storage Model&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.bitleaks.net/blog/large-scale-git-history-rewrites/&#34;&gt;Large scale Git history rewrites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://web.archive.org/web/20141018113456/http://devsector.wordpress.com/2014/10/05/advanced-git-branch-filtering/&#34;&gt;Advanced Git Branch Filtering&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://wincent.com/blog/filter-branch&#34;&gt;A tale of three filter-branches&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://medium.com/millennial-falcon-technology/reformatting-your-code-base-using-prettier-or-eslint-without-destroying-git-history-35052f3d853e&#34;&gt;Reformatting your codebase using prettier or eslint without destroying git history&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;http://elliot.land/post/reformatting-your-codebase-with-git-filter-branch&#34;&gt;Reformatting Your Codebase with git filter-branch&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://rtyley.github.io/bfg-repo-cleaner/&#34;&gt;BFG Repo-Cleaner&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/sergelevin/pylter-branch&#34;&gt;&lt;code&gt;sergelevin/pylter-branch&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;js-codemods&#34;&gt;JS Codemods&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/facebook/codemod&#34;&gt;&lt;code&gt;facebook/codemod&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/facebook/jscodeshift&#34;&gt;&lt;code&gt;jscodeshift&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/sejoker/awesome-jscodeshift&#34;&gt;awesome-jscodeshift&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/cpojer/js-codemod&#34;&gt;&lt;code&gt;cpojer/jscodemod&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/5to6/5to6-codemod&#34;&gt;&lt;code&gt;5o6-codemod&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/square/babel-codemod&#34;&gt;&lt;code&gt;babel-codemod&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://github.com/lebab/lebab&#34;&gt;&lt;code&gt;lebab&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://astexplorer.net/&#34;&gt;AST Explorer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://prettier.io/&#34;&gt;Prettier&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h4 id=&#34;git-commit-transfers&#34;&gt;Git Commit Transfers&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://git-scm.com/docs/git-bundle&#34;&gt;&lt;code&gt;git bundle&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://git-scm.com/docs/git-cherry-pick&#34;&gt;&lt;code&gt;git cherry-pick&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://git-scm.com/docs/git-format-patch&#34;&gt;&lt;code&gt;git format-patch&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://git-scm.com/docs/git-am&#34;&gt;&lt;code&gt;git am&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
    </item>
    
  </channel>
</rss>