<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Code & Craft]]></title><description><![CDATA[Hey there! 👋 Welcome to Code &amp; Craft, my corner of the internet where I share everything I've learned (and am still learning) about building better softwar]]></description><link>https://drgos.com</link><image><url>https://cdn.hashnode.com/res/hashnode/image/upload/v1700860331837/bVIpvCVNi.png</url><title>Code &amp; Craft</title><link>https://drgos.com</link></image><generator>RSS for Node</generator><lastBuildDate>Tue, 21 Apr 2026 14:02:48 GMT</lastBuildDate><atom:link href="https://drgos.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[FileFusion: The Go-Powered CLI for Smart File Concatenation and LLM Optimization]]></title><description><![CDATA[I want to learn Go, and what better way to do it than building a couple of projects. Let’s start easy, with a CLI that does some parallel processing?" That was the thought that sparked FileFusion. Well, that and the realization that my LLM is perform...]]></description><link>https://drgos.com/filefusion-the-go-powered-cli-for-smart-file-concatenation-and-llm-optimization</link><guid isPermaLink="true">https://drgos.com/filefusion-the-go-powered-cli-for-smart-file-concatenation-and-llm-optimization</guid><category><![CDATA[Programming Blogs]]></category><category><![CDATA[Go Language]]></category><category><![CDATA[cli]]></category><category><![CDATA[Open Source]]></category><dc:creator><![CDATA[Dr. Gos]]></dc:creator><pubDate>Mon, 06 Jan 2025 11:08:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/XJXWbfSo2f0/upload/d4f619930fca67fcb9565caa08ebae12.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>I want to learn Go, and what better way to do it than building a couple of projects. Let’s start easy, with a CLI that does some parallel processing?" That was the thought that sparked FileFusion. Well, that and the realization that my LLM is performing way better when it has access to some of your code.</p>
<p>Presenting <a target="_blank" href="https://github.com/drgsn/filefusion">FileFusion</a>: <a target="_blank" href="https://github.com/drgsn/filefusion">https://github.com/drgsn/filefusion</a> - a powerful file concatenation tool designed specifically for Large Language Model.</p>
<h2 id="heading-the-problem-context-management-for-llms">The Problem: Context Management for LLMs</h2>
<p>Let's face it: working with LLMs is like trying to explain your code to a brilliant but extremely literal-minded colleague who hasn't had their morning coffee yet. They need context. Lots of context. And while IDE plugins are great, they sometimes fall short when you need comprehensive codebase understanding.</p>
<p>I found that using the project features in Claude and ChatGPT – where you can upload chunks of codebases – often yielded the best results. But there was a catch (isn't there always?): managing what code goes into your LLM context is crucial for getting meaningful responses, and keep it synced with the changes from git is a pain.</p>
<p>That's where FileFusion comes in, like a helpful barista serving up perfectly filtered code to our caffeine-deprived LLM friend.</p>
<h2 id="heading-how-llms-understand-code">How LLMs "Understand" Code</h2>
<p>Before diving into FileFusion's features, let's talk about how LLMs process code. You might think they read code like we do, but they're more like that friend who memorized the entire dictionary but still occasionally uses words in hilariously wrong contexts.</p>
<p>LLMs don't really "understand" code in the way human programmers do. Instead, they:</p>
<ol>
<li><p><strong>Process Code as Tokens</strong>: When you feed code to an LLM, it breaks it down into tokens - small chunks of text. For example, the line <code>function calculateTotal()</code> might be broken into tokens like <code>["function", "calculate", "Total", "(", ")"]</code>.</p>
</li>
<li><p><strong>Look for Patterns</strong>: LLMs have been trained on massive amounts of code, so they recognize patterns. They're like that senior developer who's seen so many codebases they can spot a design pattern from a mile away – except the LLM has seen millions of codebases.</p>
</li>
<li><p><strong>Use Statistical Relationships</strong>: The model understands relationships between different parts of code based on statistical patterns in its training data. It's similar to how you might guess what a function does based on its name and context, except the LLM is doing this based on probabilities learned from its training data.</p>
</li>
<li><p><strong>Context is Everything</strong>: LLMs rely heavily on context to generate meaningful responses. The more relevant context they have, the better they can understand and respond to questions about the code. It's like trying to debug a function – the more context you have about where and how it's used, the better you can understand what it's supposed to do.</p>
</li>
</ol>
<p>This is why cleaning and optimizing code for LLM consumption is so important. Comments might be helpful for humans, but they can actually confuse LLMs by adding noise to the statistical patterns they're looking for. Similarly, repetitive boilerplate code like getters and setters can dilute the meaningful patterns in the code.</p>
<details><summary>Smaller context is better context</summary><div data-type="detailsContent">From my trials and errors, if you provide only the code that is needed for context to the LLM and a good and clear prompt it will perform better than providing the whole codebase.</div></details><details><summary>TDD for the win</summary><div data-type="detailsContent">A test driven development approach to interacting with LLMs helps a lot with debugging the code. Ask the LLM to generate tests for you functionality, provide it some edge cases and method signature and when implementing the method it will do a better job.</div></details>

<h2 id="heading-smart-pattern-matching-with-glob-patterns">Smart Pattern Matching with Glob Patterns</h2>
<p>Now, let's talk about how FileFusion helps you select exactly what code to feed your LLM friend. It uses glob patterns, which are like regular expressions' more approachable cousin. You know, the one that doesn't make you question your life choices every time you use it.</p>
<pre><code class="lang-bash"><span class="hljs-comment"># Process only Python and JavaScript files</span>
filefusion --pattern <span class="hljs-string">"*.py,*.js"</span> /path/to/project

<span class="hljs-comment"># Exclude test files and vendor directories</span>
filefusion -e <span class="hljs-string">"**/*_test.go,vendor/**"</span> /path/to/project

<span class="hljs-comment"># Complex pattern matching (for when you're feeling adventurous)</span>
filefusion -p <span class="hljs-string">"src/**/{test,main}/*.{js,ts}"</span> -e <span class="hljs-string">"**/node_modules/**"</span>
</code></pre>
<p>The pattern matching is powered by the doublestar library, which is like filepath.Match after it went to the gym and got some serious upgrades:</p>
<ul>
<li><p><code>**</code> for recursive directory matching (because life's too short to list every subdirectory)</p>
</li>
<li><p>Brace expansion for alternatives, because you don’t want to type the same pattern with different extensions</p>
</li>
<li><p>Multiple patterns support (because sometimes one pattern just isn't enough)</p>
</li>
<li><p>Negative patterns with <code>!</code> (for when you need to tell your build artifacts to kindly see themselves out)</p>
</li>
</ul>
<h2 id="heading-the-cleaning-engine-tree-sitter-integration">The Cleaning Engine: Tree-sitter Integration</h2>
<p>Now for the really cool part: FileFusion uses tree-sitter to perform language-aware code optimization. If you're not familiar with tree-sitter, think of it as a really smart code parser that turns your code into a structured tree faster than you can say "abstract syntax tree" three times fast.</p>
<p>Here's how FileFusion puts tree-sitter to work:</p>
<ol>
<li><strong>Language Detection</strong>: First, we figure out what language we're dealing with (because trying to parse Python like it's Java would be... interesting):</li>
</ol>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(p *FileProcessor)</span> <span class="hljs-title">detectLanguage</span><span class="hljs-params">(path <span class="hljs-keyword">string</span>)</span> <span class="hljs-title">cleaner</span>.<span class="hljs-title">Language</span></span> {
    ext := strings.ToLower(filepath.Ext(path))
    <span class="hljs-keyword">switch</span> ext {
    <span class="hljs-keyword">case</span> <span class="hljs-string">".go"</span>:
        <span class="hljs-keyword">return</span> cleaner.LangGo
    <span class="hljs-keyword">case</span> <span class="hljs-string">".java"</span>:
        <span class="hljs-keyword">return</span> cleaner.LangJava
    <span class="hljs-comment">// ... more languages (because we're inclusive like that)</span>
    }
    <span class="hljs-keyword">return</span> <span class="hljs-string">""</span>
}
</code></pre>
<ol start="2">
<li><strong>Syntax Tree Analysis</strong>: The code gets parsed into a tree structure, kind of like a family tree for your code, but with less dramatic holiday dinners:</li>
</ol>
<pre><code class="lang-go">tree := parser.Parse(<span class="hljs-literal">nil</span>, input)
root := tree.RootNode()

<span class="hljs-comment">// Now we can traverse the tree and identify specific nodes</span>
<span class="hljs-keyword">if</span> node.Type() == <span class="hljs-string">"comment"</span> {
    <span class="hljs-comment">// Handle comments (or in some cases, show them the door)</span>
}
</code></pre>
<ol start="3">
<li><p><strong>Smart Cleaning</strong>: The cleaning engine can identify and remove:</p>
<ul>
<li><p>Comments (while preserving documentation if desired)</p>
</li>
<li><p>Getter/setter methods (because even LLMs don't need to see <code>getX()</code> returning <code>x</code> for the millionth time)</p>
</li>
<li><p>Logging statements (sorry, debug logs, it's not you, it's us)</p>
</li>
<li><p>Import statements (when they're not needed)</p>
</li>
<li><p>Empty lines and excess whitespace</p>
</li>
</ul>
</li>
</ol>
<h2 id="heading-concurrent-processing-for-performance">Concurrent Processing for Performance</h2>
<p>FileFusion processes files concurrently using Go's goroutines and channels, because I wanted to use goroutines. I’ve insisted on making my life hard, even though sequencial processing would’ve been probably fast enough:</p>
<pre><code class="lang-go"><span class="hljs-function"><span class="hljs-keyword">func</span> <span class="hljs-params">(p *FileProcessor)</span> <span class="hljs-title">ProcessFiles</span><span class="hljs-params">(paths []<span class="hljs-keyword">string</span>)</span> <span class="hljs-params">([]FileContent, error)</span></span> {
    numWorkers := min(<span class="hljs-built_in">len</span>(paths), <span class="hljs-number">10</span>)  <span class="hljs-comment">// Because 11 would be showing off</span>
    results := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> FileResult, <span class="hljs-built_in">len</span>(paths))
    jobs := <span class="hljs-built_in">make</span>(<span class="hljs-keyword">chan</span> <span class="hljs-keyword">string</span>, <span class="hljs-built_in">len</span>(paths))

    <span class="hljs-comment">// Start our worker pool (like a pool party, but for goroutines)</span>
    <span class="hljs-keyword">var</span> wg sync.WaitGroup
    <span class="hljs-keyword">for</span> i := <span class="hljs-number">0</span>; i &lt; numWorkers; i++ {
        wg.Add(<span class="hljs-number">1</span>)
        <span class="hljs-keyword">go</span> <span class="hljs-function"><span class="hljs-keyword">func</span><span class="hljs-params">()</span></span> {
            <span class="hljs-keyword">defer</span> wg.Done()
            <span class="hljs-keyword">for</span> path := <span class="hljs-keyword">range</span> jobs {
                result := p.processFile(path)
                results &lt;- result
            }
        }()
    }

    <span class="hljs-comment">// The rest of the concurrent processing magic...</span>
}
</code></pre>
<h2 id="heading-learning-go-challenges-and-insights">Learning Go: Challenges and Insights</h2>
<p>Building FileFusion was an excellent way to learn Go, though at times it felt like trying to learn juggling by starting with chainsaws. Some of the "fun" challenges included:</p>
<ol>
<li><p><strong>Goroutine Management</strong>: Ensuring proper synchronization and preventing goroutine leaks. It turns out "let them all run wild" is not a valid concurrent programming strategy.</p>
</li>
<li><p><strong>Error Handling</strong>: Getting used to Go's error handling patterns. Yes, you have to check every error. No, crossing your fingers isn't an acceptable error handling strategy.</p>
</li>
<li><p><strong>File System Operations</strong>: Working with filesystem operations concurrently required careful handling of race conditions. Because having multiple goroutines trying to access the same file is like having multiple people try to go through a revolving door at once – chaos ensues.</p>
</li>
<li><p><strong>Memory Management</strong>: Processing large files efficiently meant being mindful of memory usage. But if your code files are that big, then that’s on you, i don’t think i’ll optimize for it.</p>
</li>
</ol>
<h2 id="heading-conclusion">Conclusion</h2>
<p>FileFusion started as a "simple" learning project and turned into a full-fledged tool that makes preparing code for LLMs a breeze. While there were certainly moments where I questioned my life choices (particularly during concurrent file processing debugging sessions), the end result is something I'm proud of.</p>
<p>The tool fills a specific niche in the LLM workflow, helping developers prepare their code for LLM consumption by cleaning out unnecessary elements while preserving essential structure.</p>
<p>Future enhancements might additional cleaning options, and perhaps integration with popular LLM platforms to automate the process of creating and updating projects. The project remains open source and welcomes contributions from the community. Just please don't submit pull requests written fully by an LLM without proper testing.</p>
]]></content:encoded></item><item><title><![CDATA[Browser Quest: Finding the Perfect Alternative to Arc Browser]]></title><description><![CDATA[You know that feeling when you're ready for a change, but you're not quite sure what you want? That's where I found myself with Arc Browser. Don't get me wrong – Arc is innovative and beautiful, but sometimes you need to explore what else is out ther...]]></description><link>https://drgos.com/browser-quest-finding-the-perfect-alternative-to-arc-browser</link><guid isPermaLink="true">https://drgos.com/browser-quest-finding-the-perfect-alternative-to-arc-browser</guid><category><![CDATA[Browsers]]></category><category><![CDATA[Productivity]]></category><category><![CDATA[technology]]></category><category><![CDATA[privacy]]></category><category><![CDATA[Web Development]]></category><category><![CDATA[web]]></category><dc:creator><![CDATA[Dr. Gos]]></dc:creator><pubDate>Sun, 05 Jan 2025 22:07:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/eMemmpUojlw/upload/8383bc63b6b52fe110cc3e13c9a2c19d.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>You know that feeling when you're ready for a change, but you're not quite sure what you want? That's where I found myself with Arc Browser. Don't get me wrong – Arc is innovative and beautiful, but sometimes you need to explore what else is out there. So I embarked on a month-long browser-shopping spree that took me through some fascinating alternatives. Here's what I discovered.</p>
<h2 id="heading-the-browser-wishlist-more-than-just-pretty-tabs">The Browser Wishlist: More Than Just Pretty Tabs</h2>
<p>Before diving into alternatives, I sat down and really thought about what matters in a modern browser:</p>
<ul>
<li><p>Resource efficiency, I want to be able to browse the internet for a long time.</p>
</li>
<li><p>Vertical tabs that actually make sense (not just tacked on as an afterthought)</p>
</li>
<li><p>Rock-solid <strong>security</strong> and <strong>privacy</strong> features</p>
</li>
<li><p>Support for my essential extensions, my carefully curated collection of tools.</p>
</li>
<li><p>Smart workspace management because my brain works better with organized chaos</p>
</li>
<li><p>Native-feeling performance</p>
</li>
</ul>
<p>Sounds simple enough, right? Well, buckle up – this journey got interesting fast.</p>
<h2 id="heading-zen-browser-the-beautiful-but-complicated-date">Zen Browser: The Beautiful But Complicated Date</h2>
<p><a target="_blank" href="https://zen-browser.app"><img src="https://zen-browser.app/_astro/browsers.iOx7zS8P_Z2uWYk9.webp" alt="Zen browser" class="image--center mx-auto" /></a></p>
<p>First up was Zen Browser, which caught my eye with its stunning Firefox-based interface. It's like someone took Firefox to a design workshop and came back with a masterpiece.</p>
<p>What made me swoon:</p>
<ul>
<li><p>Those gorgeous design and vertical tabs that look stunning.</p>
</li>
<li><p>Workspaces that actually understand how people work</p>
</li>
<li><p>A split-view system that makes research feel natural</p>
</li>
<li><p>"Zen Glance" preview feature (goodbye, risky clicks!)</p>
</li>
<li><p>Powerful theming through "Zen Mods"</p>
</li>
<li><p>Firefox's battle-tested privacy features</p>
</li>
<li><p>A treasure trove of Firefox extensions</p>
</li>
</ul>
<p>But then reality hit. No DRM support meant saying goodbye to some streaming services, and Google Meet (a daily necessity) performed like it was running on a potato. It's like dating someone who looks perfect on paper but snores like a chainsaw – some deal-breakers you just can't ignore.</p>
<h2 id="heading-vivaldi-the-overly-customizable-ex">Vivaldi: The Overly Customizable Ex</h2>
<p><a target="_blank" href="https://vivaldi.com"><img src="https://vivaldi.com/wp-content/themes/vivaldicom-theme/img/home/vivaldi-7-hero-dark.png?v=6" alt class="image--center mx-auto" /></a></p>
<p>Remember that friend who got really into modding their car and now can't stop talking about torque ratios? That's Vivaldi. It's incredibly powerful, but sometimes power isn't everything.</p>
<p>I tried the custom CSS route with themes like <a target="_blank" href="https://github.com/tovifun/VivalArc">VivalArc</a> and <a target="_blank" href="https://github.com/HKayn/vivaldi-vh/">Vivaldi VH</a>. The results looked amazing, but maintaining custom CSS felt like adopting a high-maintenance pet – one that needs attention after every single update. It's the browser equivalent of dating someone who needs you to compliment their outfit five times before leaving the house.</p>
<p>Don’t get me wrong, the browser is great, it feature packed, and it was my main browser for a week. I even created <a target="_blank" href="https://homepage.drgos.com">homepage.drgos.com</a> to be my homepage for it. But i don’t want to tinker with it that often, that what i was feeling like, everyday making a small change.</p>
<p>Dear <strong>Vivaldi team</strong>: How about letting users share complete configurations? Reducing the barrier to entry for new users and letting existing users be your megaphone. Imagine clicking once to import someone's perfect setup instead of spending hours in settings menus. Do some competitions on X.com or Reddit and give some prices for the ones with the most votes. Just a thought!</p>
<h2 id="heading-sigmaos-the-productivity-guru-next-door">SigmaOS: The Productivity Guru Next Door</h2>
<p><a target="_blank" href="https://sigmaos.com"><img src="https://framerusercontent.com/images/E5353m4mh9q2JVJ9l2B0Bw6yqM0.png" alt class="image--center mx-auto" /></a></p>
<p>Walking into SigmaOS feels like entering a minimalist's dream office. Everything has its place, and there's a place for everything. It's not just another browser; it's a complete reimagining of how we should interact with the web.</p>
<p>The standout features read like a productivity wishlist:</p>
<ul>
<li><p>Workspaces that feel like well-organized rooms in a digital house</p>
</li>
<li><p>Airis AI assistant that i haven’t used, so i can’t say anything about it.</p>
</li>
<li><p>Breadcrumb navigation that maps your diving expeditions into Wikipedia</p>
</li>
<li><p>Universal "Lazy Search" that finds anything, anywhere (because who has time to remember where they saw that thing?)</p>
</li>
<li><p>Dynamic theming that plays nice with every website</p>
</li>
<li><p>Built-in ad blocking that doesn't break sites</p>
</li>
<li><p>Team collaboration tools that don't feel bolted on</p>
</li>
</ul>
<p>Using SigmaOS feels like having a personal assistant who organizes your digital life while you sleep. It's perfect for those who color-code their calendar and alphabetize their spice rack.</p>
<h2 id="heading-orion-browser-the-unexpected-perfect-match">Orion Browser: The Unexpected Perfect Match</h2>
<p><a target="_blank" href="https://kagi.com/orion/"><img src="https://kagi.com/orion/public/images/hero2.png" alt="Orion browser" class="image--center mx-auto" /></a></p>
<p>Sometimes the best things in life come from unexpected places. Enter Orion Browser, I discoverd it through a youtube video recommandation. It’s built on WebKit, similar to SigmaOS. It's like finding out that quiet person at work is actually the most interesting one there.</p>
<p>What makes Orion special:</p>
<ul>
<li><p>Speed - the browser feels really snappy and fast.</p>
</li>
<li><p>The holy grail of extension support Chrome AND Firefox. But some extensions might not work as expected. Luckly the 4 extentions that i use are compatible.</p>
</li>
<li><p>Vertical tabs that feel natural, not forced with breadcrumbs</p>
</li>
<li><p>Mac integration that feels like it came from Apple itself especially when in compact mode.</p>
</li>
<li><p>Transform websited into native apps.</p>
</li>
<li><p>Picture in picture when you want to watch youtube while working on that document.</p>
</li>
<li><p>Privacy features or at least they advertise that.</p>
</li>
<li><p>Dynamic theming - it’s more of a miss for me, but it’s not a deal breaker. SigmaOS dynamic theming is better.</p>
</li>
</ul>
<p>Even the Google Meet issue (no virtual backgrounds) had a simple fix using macOS features. It's these thoughtful solutions that make Orion feel like home.<br />Also i like a lot more the way share screen / tab looks on webkit than on Chromium.</p>
<h2 id="heading-a-surprising-discovery-the-search-engine-renaissance">A Surprising Discovery: The Search Engine Renaissance</h2>
<p>During this browser adventure, I stumbled into another rabbit hole – the world of alternative search engines. Turns out, while we've all been googling away, a whole ecosystem of innovative search tools has evolved.</p>
<p>There's Kagi (made by the Orion folks) with its privacy-first approach, <a target="_blank" href="http://You.com">You.com</a> with its AI-powered results, Perplexity for those who want ChatGPT-style answers to everything, Phind for developers who need technical answers fast, and even Brave Search building its own independent index and a lot more. I know that everyone knows DuckDuckGo, but there are a lot more search engines out there.</p>
<p>Each one brings something unique to the table. I’m not the biggest fan of Perplexity and You.com as main search engine, even though i use them from time to time. Especially when i want to buy some product and I want to compare multiple options.</p>
<p>Kagi caught my attention with its promise of unfiltered, ad-free results, so I'm giving it a trial run. Who knows? Maybe finding the right search engine is just as important as finding the right browser.</p>
<h2 id="heading-the-happy-ending">The Happy Ending</h2>
<p>After weeks of testing and probably confusing every website's tracking algorithms, I've settled into <strong>Orion Browser</strong>. It hits that sweet spot between innovation and stability, power and simplicity. It's like finding the perfect coffee shop – not too busy, not too quiet, with just the right amount of character.</p>
<p>I will keep SigmaOS installed so that i can give Airis AI a try.</p>
<h2 id="heading-key-takeaways">Key Takeaways</h2>
<ul>
<li><p>The perfect browser isn't about having every feature – it's about having the right features</p>
</li>
<li><p>Beautiful design needs to be backed by solid performance</p>
</li>
<li><p>Sometimes the best solution comes from the most unexpected place</p>
</li>
<li><p>Privacy and functionality aren't mutually exclusive</p>
</li>
<li><p>The browser market is more exciting than it's been in years. For a while i thought that everything will go Chromium, I’m exited to see that Firefox and WebKit hang in there.</p>
</li>
</ul>
<h2 id="heading-words-of-wisdom">Words of Wisdom</h2>
<p>Finding your ideal browser is like finding your favorite pair of jeans – what works perfectly for one person might be completely wrong for another. Don't be afraid to experiment, and remember that it's okay to change your mind as your needs evolve.</p>
<hr />
<p><em>P.S. Remember, the "perfect" browser today might not be perfect tomorrow. Technology evolves, our needs change, and that's okay. The joy is in the journey of discovery – and having a reliable browser to help you along the way!</em></p>
]]></content:encoded></item><item><title><![CDATA[The Anatomy of the Perfect Git Commit: A Guide to Best Practices]]></title><description><![CDATA[In the ever-evolving world of software development, the ability to effectively manage and track changes in code is crucial. This is where good Git hygiene comes into play. Git it's not just a tool; it's a fundamental part of modern software developme...]]></description><link>https://drgos.com/the-anatomy-of-the-perfect-git-commit-a-guide-to-best-practices</link><guid isPermaLink="true">https://drgos.com/the-anatomy-of-the-perfect-git-commit-a-guide-to-best-practices</guid><category><![CDATA[Git]]></category><category><![CDATA[commit messages]]></category><category><![CDATA[GitHub]]></category><category><![CDATA[commit]]></category><dc:creator><![CDATA[Dr. Gos]]></dc:creator><pubDate>Tue, 28 Nov 2023 22:41:28 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/842ofHC6MaI/upload/72b1dc8451838ae4c234e79f373a142e.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>In the ever-evolving world of software development, the ability to effectively manage and track changes in code is crucial. This is where good Git hygiene comes into play. Git it's not just a tool; it's a fundamental part of modern software development practices.</p>
<p>A <strong>commit</strong>, in its essence, is a snapshot of your project at a specific point in time, encapsulating all your changes and updates. It's more than just a mere save point.</p>
<h4 id="heading-the-significance-of-a-commit">The Significance of a Commit</h4>
<ul>
<li><p><strong>Building Blocks of Your Project:</strong> Commits are the building blocks of your development work. They represent incremental steps towards your project's completion, each with its own unique identity.</p>
</li>
<li><p><strong>Facilitating Collaboration:</strong> In a team environment, commits are pivotal. They allow multiple developers to contribute to the same project without overwriting each other's work. By committing changes and merging them, teams can seamlessly integrate their efforts.</p>
</li>
<li><p><strong>Rollback and Error Correction:</strong> One of the most powerful features of commits is the ability to roll back to a previous state. If a new code introduces a bug, you can revert to a previous commit, ensuring stability and reducing downtime.</p>
</li>
<li><p><strong>Branching and Merging:</strong> Commits are integral to branching and merging strategies in Git. They allow you to diverge from the main line of development, experiment, and then bring those changes back into the main project safely.</p>
</li>
</ul>
<h3 id="heading-decoding-the-components-of-a-git-commit-the-building-blocks-of-project-history"><strong>Decoding the Components of a Git Commit: The Building Blocks of Project History</strong></h3>
<p>When you create a commit in Git, you're doing much more than just saving your work. You're creating a comprehensive package that records the state of your project at a particular moment. Understanding the components of a commit is essential for leveraging Git's full potential. Let's break down these components to appreciate the detailed story each commit tells.</p>
<h3 id="heading-core-components-of-a-git-commit"><strong>Core Components of a Git Commit</strong></h3>
<ol>
<li><p><strong>Snapshot of Changes</strong></p>
<ul>
<li><p><strong>Files Changed:</strong> This includes modifications to existing files. Git tracks the differences (or 'diffs') from the previous commit, allowing you to see exactly what was altered.</p>
</li>
<li><p><strong>Files Added:</strong> New files that you've created and staged for the commit are listed here. They become part of the project's tracked files from this commit onwards.</p>
</li>
<li><p><strong>Files Removed:</strong> If you've deleted files from your project, this removal is also captured. These files are no longer tracked by Git after the commit.</p>
</li>
</ul>
</li>
<li><p><strong>Commit Message</strong></p>
<ul>
<li><p><strong>Essential for Communication:</strong> The commit message is where you describe what changes were made and, more importantly, why. Good commit messages are crucial for communicating with team members and your future self.</p>
</li>
<li><p><strong>Structure:</strong> A good commit message typically has a short, descriptive title, followed by a detailed body explaining the context and rationale for the changes.</p>
</li>
</ul>
</li>
<li><p><strong>Unique Identifier (SHA-1 Hash)</strong></p>
<p> <strong>Fingerprint of Your Commit:</strong> Every commit is assigned a unique SHA-1 hash, a 40-character string that acts as the commit's fingerprint. This identifier is crucial for Git's version control mechanism.</p>
</li>
<li><p><strong>Author and Committer Information</strong></p>
<p> <strong>Who Made the Changes:</strong> Git records the author's name and email address with each commit. This is typically the person who originally wrote the changes.</p>
</li>
<li><p><strong>Parent Commit Reference</strong></p>
<ul>
<li><p><strong>Linking the Project History:</strong> Every commit (except the initial one) in Git has a parent commit. This link forms a chain that Git uses to track the entire history of the project.</p>
</li>
<li><p><strong>Branching and Merging:</strong> Understanding parent commits is key when dealing with branches and merges, as it helps Git to correctly combine different streams of work.</p>
</li>
</ul>
</li>
</ol>
<h3 id="heading-the-essence-of-a-good-commit">The Essence of a Good Commit</h3>
<h4 id="heading-the-ideal-size-and-scope-of-a-commit"><strong>The Ideal Size and Scope of a Commit</strong></h4>
<ul>
<li><p><strong>Atomicity:</strong> A commit should represent a single logical change. Regular commits after small changes are easier to track and manage.</p>
</li>
<li><p><strong>Small Size:</strong> Smaller commits are preferable for ease of understanding and rollback. Group related changes into a single commit.</p>
</li>
<li><p><strong>Testing Before Committing:</strong> Ensure that the new code does not break existing functionality.</p>
</li>
<li><p><strong>Cleanup code:</strong> remove commented code, fix TODOs, remove unused imports, fix linting.</p>
</li>
<li><p><strong>Avoid Temporal Commits:</strong> Avoid commits like "End of day commit" or "Fixing typo.". You can use these as checkpoints while iterating on the implementation, but don't push them to remote. Soft reset the changes and write comprehensive commits and changes are final.</p>
</li>
<li><p><strong>Example:</strong> Adding a function is a good commit size; overhauling an entire module is not.</p>
</li>
</ul>
<p><strong>Writing Good Commit Messages</strong></p>
<ul>
<li><p><strong>Start with a concise subject line:</strong> Summarize the change in 50 characters or less.</p>
</li>
<li><p><strong>Add a detailed description (optional):</strong> Explain the 'what' and 'why', not the 'how'.</p>
</li>
<li><p><strong>Use the imperative mood:</strong> "Fix bug" rather than "Fixed bug" or "Fixes bug".</p>
</li>
</ul>
<h3 id="heading-examples-of-commit-messages">Examples of Commit Messages</h3>
<h4 id="heading-good-commit-messages"><strong>Good Commit Messages</strong></h4>
<ol>
<li><p><strong>Descriptive and Concise Title with Detailed Body:</strong></p>
<ul>
<li><p><strong>Title:</strong> "ISSUE_ID: Implement user authentication in login module"</p>
</li>
<li><p><strong>Body:</strong></p>
<ul>
<li><p>"Added JWT-based authentication mechanism."</p>
</li>
<li><p>"Included error handling for failed login attempts."</p>
</li>
<li><p>"Updated unit tests to cover new functionality."</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Clear and Specific, Explaining the 'Why':</strong></p>
<ul>
<li><p><strong>Title:</strong> "ISSUE_ID: Fix memory leak in image processing function"</p>
</li>
<li><p><strong>Body:</strong></p>
<ul>
<li><p>"Identified and resolved a memory leak issue where buffers weren't being freed."</p>
</li>
<li><p>"Refactored buffer management to improve performance and reliability."</p>
</li>
<li><p>"Added comments for clarity on buffer handling logic."</p>
</li>
</ul>
</li>
</ul>
</li>
<li><p><strong>Use of Imperative Mood, Reflecting Action Taken:</strong></p>
<ul>
<li><p><strong>Title:</strong> "ISSUE_ID: Refactor database query functions for scalability"</p>
</li>
<li><p><strong>Body:</strong></p>
<ul>
<li><p>"Revised SQL queries to use prepared statements, enhancing security and performance."</p>
</li>
<li><p>"Optimized query logic to reduce execution time for large datasets."</p>
</li>
<li><p>"Updated relevant documentation to reflect changes in query functions."</p>
</li>
</ul>
</li>
</ul>
</li>
</ol>
<blockquote>
<p>Most git providers provide integration with issue-tracking software. So it's a good idea to include the id of the task / issue for easy navigation between the issue and commit an vice-versa.</p>
</blockquote>
<p><strong>Bad Commit Messages</strong></p>
<ol>
<li><p><strong>Vague and Non-Informative:</strong></p>
<ul>
<li><p>"Fixed stuff"</p>
</li>
<li><p>"Updates"</p>
</li>
<li><p>"Made changes"</p>
</li>
</ul>
</li>
<li><p><strong>Too Broad, Lacking Specificity:</strong></p>
<ul>
<li><p>"Worked on app"</p>
</li>
<li><p>"Changes in code"</p>
</li>
<li><p>"Bug fixes"</p>
</li>
</ul>
</li>
<li><p><strong>Personal Messages Not Useful for the Team:</strong></p>
<ul>
<li><p>"Trying something out"</p>
</li>
<li><p>"Not sure if this will work"</p>
</li>
<li><p>"Committing so I can leave for the day"</p>
</li>
</ul>
</li>
<li><p><strong>No Explanation of 'Why':</strong></p>
<ul>
<li><p>"Changed login"</p>
</li>
<li><p>"Edited queries"</p>
</li>
<li><p>"Updated files"</p>
</li>
</ul>
</li>
</ol>
<blockquote>
<p>You can have temporary bad commit messages while you experiment but don't forget to soft reset the changes and replace the bad commits with good ones.</p>
<pre><code class="lang-bash"> git reset --soft $(git merge-base your_main_branch HEAD)
</code></pre>
<p>This will move the git history back to the head of your_main_branch and will allow you to push commit over that on your branch.</p>
</blockquote>
<h3 id="heading-key-takeaways-for-commit-messages"><strong>Key Takeaways for Commit Messages</strong></h3>
<ul>
<li><p><strong>Good Commit Messages:</strong> Are specific, informative, and explain not only what was changed but why. They follow a clear structure with a concise summary and an optional detailed description.</p>
</li>
<li><p><strong>Bad Commit Messages:</strong> Are vague, overly broad, or too personal. They lack the necessary information to understand the context and rationale behind the changes.</p>
</li>
<li><p><strong>A good commit</strong> is characterized foremost by its size; it should be small and focused, encompassing a single logical change. This granularity not only simplifies understanding and review but also eases the process of troubleshooting and reverting changes if needed. The changes within each commit should be logically grouped, ensuring that all modifications contribute cohesively to a specific functionality or fix. Before committing, it's imperative that the changes are thoroughly tested to maintain the stability and reliability of the codebase. Equally important is the cleanliness of the code in a good commit. It should be free from unused imports, commented-out code, and unresolved 'TODOs'</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Implementing Git Hook-Style functionality in Your Terminal]]></title><description><![CDATA[Introduction
The power of the terminal lies in its flexibility and the ability to customize it to fit our unique workflows. Drawing inspiration from Git hooks, a powerful feature in Git that triggers custom scripts at certain points in its execution ...]]></description><link>https://drgos.com/implementing-git-hook-style-functionality-in-your-terminal</link><guid isPermaLink="true">https://drgos.com/implementing-git-hook-style-functionality-in-your-terminal</guid><category><![CDATA[Git]]></category><category><![CDATA[terminal]]></category><category><![CDATA[git-hooks]]></category><category><![CDATA[Go Language]]></category><category><![CDATA[Bash]]></category><dc:creator><![CDATA[Dr. Gos]]></dc:creator><pubDate>Fri, 24 Nov 2023 20:55:55 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/stock/unsplash/Wgw0wwXMdk0/upload/d9bc470c54dd00cb3c70e0fce64bf0b4.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<h2 id="heading-introduction">Introduction</h2>
<p>The power of the terminal lies in its flexibility and the ability to customize it to fit our unique workflows. Drawing inspiration from Git hooks, a powerful feature in Git that triggers custom scripts at certain points in its execution flow, we can similarly extend the functionality of our terminal. This article delves into how I used this concept to streamline my workflow, not just limited to Go development, but applicable to a range of tasks in the terminal.</p>
<h2 id="heading-understanding-git-hooks">Understanding Git Hooks</h2>
<p>Git hooks are scripts that Git executes before or after events such as <code>commit</code>, <code>push</code>, and <code>pull</code>. They are a vital part of automating tasks in the software development process. This concept can be extrapolated to the terminal, where we often perform repetitive tasks that could benefit from automation. For example, I automated the <a target="_blank" href="https://gist.github.com/drgsn/d0e7e9a7b64e220ccdd5fafda712e35a">prefixing of each of my commit messages with the ticket id</a> and <a target="_blank" href="https://gist.github.com/drgsn/900559fc321b43d4a7ea14a8f4345c71">checks that I don't commit any secrets in my repos</a> (not that well optimized).</p>
<h2 id="heading-identifying-repetitive-tasks">Identifying Repetitive Tasks</h2>
<p>My journey began with recognizing a repetitive task: running <code>asdf reshim golang</code> every time after using <code>go install</code> or <code>go get</code>. This was necessary due to using <code>asdf</code> as a version manager for Go, but it was easy to forget. This scenario is just one example; think about your daily terminal use and identify similar repetitive commands.</p>
<h2 id="heading-implementing-the-hook">Implementing the hook</h2>
<p>To automate this, I created a bash script named <code>.go_install_hook.sh</code>:</p>
<pre><code class="lang-bash"><span class="hljs-meta">#!/bin/bash</span>
<span class="hljs-comment"># Display a custom pre-run message.</span>
<span class="hljs-built_in">echo</span> <span class="hljs-string">"Running a Go command..."</span>

<span class="hljs-comment"># Run the original 'go run' command.</span>
go <span class="hljs-string">"<span class="hljs-variable">$@</span>"</span>

<span class="hljs-comment"># Check if the command is 'go run' or 'go install'</span>
<span class="hljs-keyword">if</span> [[ <span class="hljs-string">"<span class="hljs-variable">$1</span>"</span> == <span class="hljs-string">"run"</span> ]] || [[ <span class="hljs-string">"<span class="hljs-variable">$1</span>"</span> == <span class="hljs-string">"install"</span> ]]; <span class="hljs-keyword">then</span>
  <span class="hljs-comment"># If it's 'go run' or 'go install', run 'asdf reshim golang'</span>
  <span class="hljs-built_in">echo</span> <span class="hljs-string">"it's 'go run' or 'go install', running 'asdf reshim golang'"</span>
  asdf reshim golang
<span class="hljs-keyword">fi</span>
</code></pre>
<p>This script acts as a wrapper around your intended command, in my case <code>go whatever</code> allowing you to execute additional logic before or after the main command.</p>
<p>In the example above I print a statement, this is more for debugging purposes, after that I run the intended <code>go</code> command and at the end I check if the command was <code>go run</code> or <code>go install</code> and run the reshim command.</p>
<h2 id="heading-integrating-with-the-terminal">Integrating with the Terminal</h2>
<p>The script was then integrated into my daily workflow by aliasing the original command in my bash configuration (<code>.zshrc</code> in my case):</p>
<pre><code class="lang-bash"><span class="hljs-built_in">alias</span> go=<span class="hljs-string">"~/.go_install_hook.sh"</span>
</code></pre>
<p>In my case, it was the <code>go</code> command, but this can be adapted to any command where you see a pattern of repetitive post-command actions.</p>
<h2 id="heading-expanding-beyond-go">Expanding Beyond Go</h2>
<p>While my initial use case was specific to <code>Go</code> and <code>asdf</code>, the principle applies universally. For instance, you could create a script that cleans up temporary files after compiling a program, or one that automatically pushes changes to a remote repository after a successful commit.</p>
<h2 id="heading-conclusion-a-world-of-possibilities">Conclusion: A World of Possibilities</h2>
<p>This approach opens up a world of possibilities in terminal automation. By emulating the functionality of Git hooks, we can create a more efficient, error-resistant, and customized command-line experience. This method's adaptability across various commands and workflows demonstrates the power of custom scripting in enhancing our daily interactions with the terminal.</p>
]]></content:encoded></item></channel></rss>