<?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: Shyam</title>
    <description>The latest articles on DEV Community by Shyam (@sym-jay).</description>
    <link>https://dev.to/sym-jay</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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4204112%2Ffbc83469-9ee6-4e00-b1a4-0e0446d378d8.jpeg</url>
      <title>DEV Community: Shyam</title>
      <link>https://dev.to/sym-jay</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sym-jay"/>
    <language>en</language>
    <item>
      <title>git blame lied to me: the 2020 bug fix hiding behind a 2023 refactor</title>
      <dc:creator>Shyam</dc:creator>
      <pubDate>Sat, 24 Oct 2026 07:39:18 +0000</pubDate>
      <link>https://dev.to/sym-jay/git-blame-lied-to-me-the-2020-bug-fix-hiding-behind-a-2023-refactor-1101</link>
      <guid>https://dev.to/sym-jay/git-blame-lied-to-me-the-2020-bug-fix-hiding-behind-a-2023-refactor-1101</guid>
      <description>&lt;p&gt;This line is in Flask's &lt;code&gt;app.py&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;self_ref&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;weakref&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ref&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Looks over-engineered. Why not just &lt;code&gt;self&lt;/code&gt;?&lt;/p&gt;
&lt;h2&gt;
  
  
  git blame says 2023
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git blame -w -M -C -C -C -L355,355 src/flask/app.py
0ec7f713 (pgjones 2023-06-11)  self_ref = weakref.ref(self)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;&lt;em&gt;"Split the App and Blueprint into Sansio and IO parts."&lt;/em&gt; That commit only moved code. Blame tells you who &lt;strong&gt;last touched&lt;/strong&gt; a line, not why it &lt;strong&gt;exists&lt;/strong&gt;.&lt;/p&gt;
&lt;h2&gt;
  
  
  The real reason is from 2020
&lt;/h2&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ git log -S"weakref.ref(self)" --oneline
0ec7f713 Split the App and Blueprint into Sansio and IO parts
8efea0cc Break reference cycle created by default in Flask instances.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The weakref stops a memory leak (#3761). "Simplify" it and the leak is back. You'd only find this if you already suspected a story.&lt;/p&gt;
&lt;h2&gt;
  
  
  So I built Blot
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Sym-jay/Blot" rel="noopener noreferrer"&gt;Blot&lt;/a&gt; is a pre-commit hook that has read your git history. It warns when a commit:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;removes a fix&lt;/strong&gt;: edits a line a bug fix added&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;re-adds a bug&lt;/strong&gt;: brings back a line a fix removed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;forgets a related file&lt;/strong&gt;: changes &lt;code&gt;A&lt;/code&gt; but not &lt;code&gt;B&lt;/code&gt;, when they always change together&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F27dahmr49s7g4ju7dgeg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2F27dahmr49s7g4ju7dgeg.gif" alt="demo" width="800" height="430"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Or ask about any line. It skips commits that only moved code:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ blot why src/flask/app.py:355
  explained by  8efea0cc  2020-10-03  Break reference cycle ...  [bug fix]
  traced past   0ec7f713  2023-06-11  Split the App and Blueprint ...  [refactor]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Local, no AI, no account. Warns, never blocks.&lt;/p&gt;
&lt;h2&gt;
  
  
  Staying quiet was the hard part
&lt;/h2&gt;

&lt;p&gt;My first version gave Django &lt;strong&gt;26 warnings per 10 commits&lt;/strong&gt;. So I replayed the last 500 commits of 5 repos, read every warning, and turned each noise pattern into a rule.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Repo&lt;/th&gt;
&lt;th&gt;Before&lt;/th&gt;
&lt;th&gt;After&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Flask&lt;/td&gt;
&lt;td&gt;1.96&lt;/td&gt;
&lt;td&gt;0.10&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Express&lt;/td&gt;
&lt;td&gt;1.00&lt;/td&gt;
&lt;td&gt;0.18&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Django&lt;/td&gt;
&lt;td&gt;26.30&lt;/td&gt;
&lt;td&gt;1.29&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The replays also found real moments, like Express &lt;strong&gt;reverting the CVE-2024-51999 security patch&lt;/strong&gt;. Blot flagged it.&lt;/p&gt;
&lt;h2&gt;
  
  
  Try it
&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;blot-git
blot index
blot install-hook
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="ltag-github-readme-tag"&gt;
  &lt;div class="readme-overview"&gt;
    &lt;h2&gt;
      &lt;img src="https://assets.dev.to/assets/github-logo-5a155e1f9a670af7944dd5e12375bc76ed542ea80224905ecaf878b9157cdefc.svg" alt="GitHub logo"&gt;
      &lt;a href="https://github.com/Sym-jay" rel="noopener noreferrer"&gt;
        Sym-jay
      &lt;/a&gt; / &lt;a href="https://github.com/Sym-jay/Blot" rel="noopener noreferrer"&gt;
        Blot
      &lt;/a&gt;
    &lt;/h2&gt;
    &lt;h3&gt;
      A pre-commit check that has read your project's history. Sora the slime warns when a change removes a fix, re-adds a fixed bug, or forgets a file that always changes too.
    &lt;/h3&gt;
  &lt;/div&gt;
  &lt;div class="ltag-github-body"&gt;
    
&lt;div id="readme" class="md"&gt;&lt;div class="markdown-heading"&gt;
&lt;h1 class="heading-element"&gt;Blot&lt;/h1&gt;
&lt;/div&gt;

&lt;p&gt;&lt;a href="https://github.com/Sym-jay/Blot/actions/workflows/ci.yml" rel="noopener noreferrer"&gt;&lt;img src="https://github.com/Sym-jay/Blot/actions/workflows/ci.yml/badge.svg" alt="CI"&gt;&lt;/a&gt; &lt;a href="https://pypi.org/project/blot-git/" rel="nofollow noopener noreferrer"&gt;&lt;img src="https://camo.githubusercontent.com/4f65ebe8840c7cc4f26b90da33de133b9438a9ae460809fb711b9bb6b2f483e4/68747470733a2f2f696d672e736869656c64732e696f2f707970692f762f626c6f742d676974" alt="PyPI"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/Sym-jay/Blot/assets/sora/orange/walk.svg"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSym-jay%2FBlot%2FHEAD%2Fassets%2Fsora%2Forange%2Fwalk.svg" width="480" alt="Sora, the Blot slime, sliding back and forth"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;A pre-commit check that has read your project's history.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Meet &lt;strong&gt;Sora&lt;/strong&gt;, the slime who remembers every fix.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Don't take down a fence until you know why it was put up.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Blot warns you &lt;em&gt;before you commit&lt;/em&gt; when your change:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;removes a fix&lt;/strong&gt;: deletes or edits code that was added to fix a bug&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;re-adds a bug&lt;/strong&gt;: brings back a line that a bug fix deliberately removed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;forgets a related file&lt;/strong&gt;: changes &lt;code&gt;A&lt;/code&gt; but not &lt;code&gt;B&lt;/code&gt;, when the two almost always change together&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It runs locally, needs no account or AI, and stays quiet unless the history gives it a real reason to speak.&lt;/p&gt;

&lt;p&gt;&lt;a rel="noopener noreferrer" href="https://github.com/Sym-jay/Blot/assets/demo/demo.gif"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fraw.githubusercontent.com%2FSym-jay%2FBlot%2FHEAD%2Fassets%2Fdemo%2Fdemo.gif" width="760" alt="Blot catching a real Flask regression: simplifying self_ref = weakref.ref(self) triggers a removed-fix warning that traces past a 2023 refactor to the 2020 reference-cycle fix"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;A real run on Flask. Plain &lt;code&gt;git blame&lt;/code&gt; points to a 2023 commit that only moved this line; Blot traces past it to the 2020 fix that explains it. (Regenerate with &lt;code&gt;python assets/demo/make_demo.py&lt;/code&gt;.)&lt;/em&gt;&lt;/p&gt;


&lt;blockquote&gt;

&lt;p&gt;&lt;strong&gt;Status:&lt;/strong&gt; pre-alpha. Milestones M1 and M2 are…&lt;/p&gt;


&lt;/blockquote&gt;&lt;/div&gt;
&lt;br&gt;
  &lt;/div&gt;
&lt;br&gt;
  &lt;div class="gh-btn-container"&gt;&lt;a class="gh-btn" href="https://github.com/Sym-jay/Blot" rel="noopener noreferrer"&gt;View on GitHub&lt;/a&gt;&lt;/div&gt;
&lt;br&gt;
&lt;/div&gt;
&lt;br&gt;


&lt;p&gt;Pre-alpha. If it cries wolf on your repo, open an issue; that's exactly the feedback I need.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Built with help from Claude (of course, phew); every number here is from a real run.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>opensource</category>
      <category>git</category>
      <category>devtools</category>
    </item>
  </channel>
</rss>
