<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: BHFock</title>
    <description>The latest articles on DEV Community by BHFock (@bhfock).</description>
    <link>https://dev.to/bhfock</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3774191%2Fa37edcf2-0b13-453f-9582-6adc0535a6a4.jpeg</url>
      <title>DEV Community: BHFock</title>
      <link>https://dev.to/bhfock</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/bhfock"/>
    <language>en</language>
    <item>
      <title>Organise Before You Stage: Changelists for Git</title>
      <dc:creator>BHFock</dc:creator>
      <pubDate>Sat, 16 May 2026 19:58:06 +0000</pubDate>
      <link>https://dev.to/bhfock/organise-before-you-stage-changelists-for-git-59ep</link>
      <guid>https://dev.to/bhfock/organise-before-you-stage-changelists-for-git-59ep</guid>
      <description>&lt;p&gt;Real development is rarely linear. You're mid-feature when you spot a typo in the README, or a stray debug statement left over from last week. Before long your working directory is a pile of loosely related edits, and the staging area gives you exactly one place to put them.&lt;/p&gt;

&lt;p&gt;I ran into this problem when my team migrated from Subversion to Git. SVN had changelists: named groups of files you could organise before committing. I had changelists like &lt;code&gt;ready_to_commit&lt;/code&gt; and &lt;code&gt;do_not_commit&lt;/code&gt;, and the clarity they gave me was something I immediately missed in Git.&lt;/p&gt;

&lt;p&gt;So I built &lt;a href="https://github.com/BHFock/git-cl" rel="noopener noreferrer"&gt;git-cl&lt;/a&gt;, a Git subcommand that adds changelists to your workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's a changelist, exactly?
&lt;/h2&gt;

&lt;p&gt;Think of changelists as sticky notes for your working directory. You group modified files under a name before deciding what to stage or commit. Nothing is staged until you say so, and you can have as many changelists as you like, all at once.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl7ue4jaoi55dv9n9rqph.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl7ue4jaoi55dv9n9rqph.gif" alt="git-cl demo: creating changelists, viewing status, and branching"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Changelists sit between your working directory and Git's staging area. They don't touch Git's index or history until you explicitly stage or commit. They're stored locally in &lt;code&gt;.git/cl.json&lt;/code&gt;, private to your workspace and never committed.&lt;/p&gt;

&lt;p&gt;Install with:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;git-changelists
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Workflow 1: Named staging areas
&lt;/h2&gt;

&lt;p&gt;Git gives you one staging area. Everything you &lt;code&gt;git add&lt;/code&gt; lands there together, waiting for a single commit. That works fine when your changes all belong together, but less well when you're mid-feature and notice something unrelated that needs fixing.&lt;/p&gt;

&lt;p&gt;Say you're implementing a feature and notice a typo in the README along the way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git cl add feature src/core.py src/helpers.py tests/test_core.py
git cl add typo-fix README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;git cl status&lt;/code&gt; shows you what's grouped where:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;feature:
  [ M] src/core.py
  [ M] src/helpers.py
  [ M] tests/test_core.py

typo-fix:
  [ M] README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;All of it lives in your working directory at once. You can run tests, keep editing, see the full picture. When you're ready, commit one changelist at a time:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git cl commit feature &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Implement core feature"&lt;/span&gt;
git cl commit typo-fix &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Fix typo in README"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Two focused commits, clean history, without ever touching a branch or juggling the staging area manually.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workflow 2: Changelists as review stages
&lt;/h2&gt;

&lt;p&gt;Here's where it gets more interesting. Changelists don't have to represent &lt;em&gt;what&lt;/em&gt; you changed; they can represent &lt;em&gt;where each file is in your review process&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;Instead of grouping by feature, you group by stage. Start by putting all modified files into an initial changelist:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git cl add to_review src/core.py src/utils.py tests/test_core.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run your linter. Files that pass move forward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git cl add linted src/core.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Moving a file to a new changelist removes it from the old one automatically. &lt;code&gt;git cl status&lt;/code&gt; becomes a dashboard of your review pipeline:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;to_review:
  [ M] src/utils.py

linted:
  [ M] tests/test_core.py

ready:
  [ M] src/core.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You decide what the stages mean: numbered (&lt;code&gt;review_1&lt;/code&gt;, &lt;code&gt;review_2&lt;/code&gt;), named after what's been checked (&lt;code&gt;linted&lt;/code&gt;, &lt;code&gt;tested&lt;/code&gt;, &lt;code&gt;profiled&lt;/code&gt;), or named after approvals (&lt;code&gt;self_review_ok&lt;/code&gt;, &lt;code&gt;ai_review_ok&lt;/code&gt;, &lt;code&gt;ready_to_commit&lt;/code&gt;). The pattern is the same: changelists as a lightweight state machine, with &lt;code&gt;git cl status&lt;/code&gt; as the dashboard.&lt;/p&gt;

&lt;h2&gt;
  
  
  Workflow 3: Late-binding branching
&lt;/h2&gt;

&lt;p&gt;Branches are Git's model for isolating parallel work, but they ask you to decide upfront. In practice, you often don't know something needs its own branch until you're already deep into it.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git cl branch&lt;/code&gt; lets you defer that decision. Say you've been improving a numerical solver alongside other unrelated work:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git cl add solver-opt src/solver.f90 src/utils_math.f90
git cl add config-fix config.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At some point the solver work has grown beyond the scope of your current branch. Rather than committing half-finished work, you promote it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git cl branch solver-opt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;git-cl stashes all active changelists, creates and checks out a new branch named &lt;code&gt;solver-opt&lt;/code&gt;, then restores only the &lt;code&gt;solver-opt&lt;/code&gt; changelist. Your other changelists stay stashed and can be recovered with &lt;code&gt;git cl unstash&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The result: you're on a dedicated feature branch with your changelist intact, ready to pick up exactly where you left off. The branch decision followed the code, not the other way around.&lt;/p&gt;

&lt;h2&gt;
  
  
  Quick start
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install &lt;/span&gt;git-changelists

&lt;span class="c"&gt;# Inside any Git repo:&lt;/span&gt;
git cl add my-feature file1.py file2.py
git cl status
git cl commit my-feature &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"Add feature"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Full documentation and a step-by-step tutorial are at &lt;a href="https://github.com/BHFock/git-cl" rel="noopener noreferrer"&gt;github.com/BHFock/git-cl&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Changelists aren't a replacement for branches. They're a layer that sits before them, a way to organise intent while work is still in motion. If your working directory often feels like a pile of loosely related edits, they might be worth a try.&lt;/p&gt;

</description>
      <category>git</category>
      <category>changelists</category>
      <category>devtools</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
