<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: David Ochiel</title>
    <description>The latest articles on Forem by David Ochiel (@nguonodave).</description>
    <link>https://forem.com/nguonodave</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%2F1498883%2F8445152b-cb19-423d-a15a-3be05434f235.jpeg</url>
      <title>Forem: David Ochiel</title>
      <link>https://forem.com/nguonodave</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/nguonodave"/>
    <language>en</language>
    <item>
      <title>Zero-Cost Abstractions in Go: A Practical Guide with Real-World Examples</title>
      <dc:creator>David Ochiel</dc:creator>
      <pubDate>Mon, 30 Jun 2025 18:29:50 +0000</pubDate>
      <link>https://forem.com/nguonodave/zero-cost-abstractions-in-go-a-practical-guide-with-real-world-examples-2be6</link>
      <guid>https://forem.com/nguonodave/zero-cost-abstractions-in-go-a-practical-guide-with-real-world-examples-2be6</guid>
      <description>&lt;p&gt;When I first started with Go, I assumed that writing clean, abstracted code meant sacrificing performance. Then I discovered &lt;strong&gt;zero-cost abstractions&lt;/strong&gt; - patterns that give you maintainability without runtime overhead.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Abstractions are only dangerous when they cost more than they’re worth. Rob Pike&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Go is often lauded for its simplicity, speed, and robust concurrency model. But beneath the minimalism lies a powerful capability: writing abstractions that don’t come with a performance price tag, what some languages call &lt;em&gt;zero-cost abstractions.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In this post, we’ll explore how to write idiomatic, abstracted Go code without sacrificing performance, complete with benchmarks, pitfalls, and real-world examples.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What are Zero-Cost Abstractions?&lt;/strong&gt;&lt;br&gt;
A zero-cost abstraction means the abstraction adds no overhead at runtime compared to writing equivalent low-level code manually.&lt;/p&gt;

&lt;p&gt;Think: reusable code that doesn't slow you down.&lt;/p&gt;

&lt;p&gt;While Go doesn’t use this terminology explicitly, it has patterns that achieve the same effect, especially when you're careful with allocations, interfaces, and function in-lining.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 1: Avoiding Interface Overhead in Performance-Critical Code&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;❌ Bad: Interface dispatch in hot paths&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;Processor&lt;/span&gt; &lt;span class="k"&gt;interface&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="n"&gt;Processor&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Problem:&lt;/strong&gt; Interface method calls involve dynamic dispatch (small runtime lookup).&lt;/p&gt;

&lt;p&gt;&lt;em&gt;✅ Good: Generics (Go 1.18+)&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;Execute&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="c"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Advantage:&lt;/strong&gt; The compiler generates optimized code for each type at compile time.&lt;/p&gt;

&lt;p&gt;Using a function parameter (which inlines easily) avoids the dynamic dispatch overhead of interfaces, especially important in high-frequency paths like parsing or encoding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Example 2: Allocation-Free Data Structures with Slices&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Go’s slice internals make it easy to reuse memory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;FilterInPlace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;predicate&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="k"&gt;range&lt;/span&gt; &lt;span class="n"&gt;nums&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;predicate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;out&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;out&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;out&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code reuses the underlying array, no allocation, no GC pressure. It’s effectively zero-cost, yet generic and readable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Benchmarking: How Much Do You Save?&lt;/strong&gt;&lt;br&gt;
Using &lt;code&gt;go test -bench&lt;/code&gt;, I compared a version of FilterInPlace that uses a new slice vs. reuses memory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;BenchmarkFilterNewSlice-8     10000000    200 ns/op
BenchmarkFilterInPlace-8      20000000    100 ns/op
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A 2x improvement just from a small change in memory usage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Concurrency Bonus: Channel-less Patterns&lt;/strong&gt;&lt;br&gt;
Instead of always reaching for channels, try function closures or &lt;code&gt;sync.Pool&lt;/code&gt; to build async-safe abstractions without the cost of blocking.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;WorkerPool&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;T&lt;/span&gt; &lt;span class="n"&gt;any&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="n"&gt;workers&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;work&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;ch&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="n"&gt;T&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;workers&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;work&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ch&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;}()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can keep abstractions modular and performant, especially in systems like log processing or real-time analytics.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Takeaways&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Abstractions in Go don’t have to cost you performance.&lt;/li&gt;
&lt;li&gt;Avoid heap allocations and interface dispatch in hot paths.&lt;/li&gt;
&lt;li&gt;Use slices, generics, and inlining-friendly patterns.&lt;/li&gt;
&lt;li&gt;Profile with &lt;code&gt;pprof&lt;/code&gt; and &lt;code&gt;go test -bench&lt;/code&gt; to confirm.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Time Traveling Through Your Repo: Git Reset vs. Revert</title>
      <dc:creator>David Ochiel</dc:creator>
      <pubDate>Fri, 31 May 2024 08:38:48 +0000</pubDate>
      <link>https://forem.com/nguonodave/time-traveling-through-your-repo-git-reset-vs-revert-1en4</link>
      <guid>https://forem.com/nguonodave/time-traveling-through-your-repo-git-reset-vs-revert-1en4</guid>
      <description>&lt;p&gt;Once upon a commit, in the mystical realm of version control... jokes aside 😅. Wassup fellow git adventurers! Today we'll be embarking on a journey through the mysterious realms of version control. We'll dive deep into the git universe to understand the mysterious powers of two commands: reset and revert. Buckle up, because this ride might get a bit bumpy, but fear not, for I shall guide you through with wit and wisdom!&lt;/p&gt;

&lt;h1&gt;
  
  
  The Maverick Reset
&lt;/h1&gt;

&lt;p&gt;Ah, the mighty &lt;strong&gt;git reset&lt;/strong&gt;, a command so potent, it can make your HEAD spin. But wait! What is this enigmatic "HEAD" in the realm of git?&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It's like the captain's chair of your spaceship. It points to the current position within your repository. Picture it as the guiding compass of your git repository, pointing to the very tip of your current branch. It's the nucleus around which your commits orbit, determining what snapshot of your project you're currently viewing or altering.&lt;/li&gt;
&lt;li&gt;If you are on the master branch, HEAD will point to the latest commit on that branch. So when you hear about "resetting HEAD," it's like repositioning captain git's chair to a different point in space-time, perhaps to a previous commit or even a different branch altogether.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Back to our friend reset. Imagine you're in a time machine, and you want to teleport back to a previous commit. Well, git reset is your &lt;a href="https://delorean.com/" rel="noopener noreferrer"&gt;DeLorean&lt;/a&gt;, ready to whisk you away to the past. But beware, fellow time travelers, for with great power comes great responsibility! Git reset without caution can lead to catastrophic consequences. One wrong move, and poof! Your commits vanish into the digital abyss faster than you can say "commitment issues." So, before you hit that reset button, remember to backup your work.&lt;/p&gt;

&lt;p&gt;Assuming the following is your commit history, let's talk about the responsibilities you'll have, going the maverick way:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C1 - C2 - C3 - C4 - C5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Types of Reset&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;&lt;u&gt;Soft Reset:&lt;/u&gt;&lt;/em&gt; It's akin to a cautious peek into the time-traveling toolbox of coding. You move HEAD to a previous commit, but your changes stay staged, as if hitting the pause button on your code's journey through time. From the commit history above, say you want go back to C2. Running &lt;code&gt;git reset --soft &amp;lt;hash-for-C2&amp;gt;&lt;/code&gt; or &lt;code&gt;git reset --soft HEAD~3&lt;/code&gt; will uncommit the changes from C3 to C5, but will keep them staged. To get the hash for your commit, run &lt;code&gt;git log&lt;/code&gt; then copy the desired hash. In &lt;strong&gt;HEAD~3&lt;/strong&gt;, 3 is the number of steps it takes to get to C2. Hopefully your "head" is not spinning though. Pick the convention that suits you. Let's look at an example.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Suppose you have the following in your working environment.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.gitignore
app1.py
app2.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You then decided to commit the two apps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git add app1.py app2.py
git commit -m "feat: add apps"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then later realized that you forgot to add the .gitignore file (meaning it is still unstaged), you can do the following.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# HEAD will get the very last commit
git reset --soft HEAD
git add .gitignore
git commit -m "feat: add apps and gitignore"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;u&gt;&lt;em&gt;Mixed Reset:&lt;/em&gt;&lt;/u&gt; Feeling a bit indecisive? This reset moves HEAD and resets the index to a previous commit, leaving your changes unstaged. Running &lt;code&gt;git reset &amp;lt;hash-for-C2&amp;gt;&lt;/code&gt; will keep the changes from C3 to C5 unstaged. With the files in the example above, after committing the two apps, run &lt;code&gt;git reset HEAD&lt;/code&gt;. Both the three files will then be unstaged, including the two that were initially committed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;NOTE&lt;/strong&gt; that with mixed reset, you do not have to include the &lt;code&gt;--mixed&lt;/code&gt; flag.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;u&gt;&lt;em&gt;Hard Reset:&lt;/em&gt;&lt;/u&gt; Ready to go all-in? Brace yourself, because this reset moves HEAD and resets both the index and working directory to a previous commit. It's like a cosmic eraser, wiping away your changes without mercy. Use with caution! To achieve it, run &lt;code&gt;git reset --hard &amp;lt;hash-commit-C2&amp;gt;&lt;/code&gt;. This will do away with all the changes after C2 from your repository.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Let's take a look at an example by adding some files to the previous working tree. Assuming you committed the three files, then added one file. The new file (README.md) will be in an untracked status. Run &lt;code&gt;git add .&lt;/code&gt; or &lt;code&gt;git add README.md&lt;/code&gt;, according to your preference, to add it to your staging area then commit the changes, say, &lt;code&gt;git commit -m "docs: add readme"&lt;/code&gt; Let's assume the hash for this commit will be 212w544. Your current working tree should now be as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.gitignore
app1.py
app2.py
README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now by running &lt;code&gt;git reset --hard &amp;lt;commit-hash-before-212w544&amp;gt;&lt;/code&gt; the commit 212w544 will be discarded together with it's file (README.md). Your working tree should now be as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.gitignore
app1.py
app2.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Ready to rewrite history?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;After traversing the depths of time with your hard reset, it's now the moment to rewrite history. To discard the contents in your remote repository like github, gitea, or gitlab, run &lt;code&gt;git push &amp;lt;remote-name&amp;gt; &amp;lt;branch-name&amp;gt; --force&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;This command will overwrite the history in the remote repository with the changes from your local repository, effectively discarding the unwanted changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;CAUTION!!!&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In case you were working on a project with collaborators, this can potentially cause issues for those who have pulled the changes. Make sure to communicate with your team before force pushing to avoid conflicts.&lt;/li&gt;
&lt;li&gt;Ensure you have a backup of the remote repository in case you need to revert the changes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  The Renegade Revert
&lt;/h1&gt;

&lt;p&gt;Now, let's talk about git revert - the rebel with a cause, the anti-hero of version control. Unlike reset, which rewrites history like a stealthy ninja, revert takes a different approach. It acknowledges the past but refuses to let it define the future. Basically it's used to undo changes introduced by a specific commit, creating a new commit that reflects the reversal. It maintains a clear and linear history by documenting the reversal as a new commit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Here is how it works&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Suppose the following is your commit history:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C1 - C2 - C3 - C4 - C5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We want to undo the changes introduced by commit C2. Check the hash for your commit by running &lt;code&gt;git log&lt;/code&gt;, then do the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git revert &amp;lt;hash-for-C2&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you use the HEAD convention, it will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git revert HEAD~3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If there are conflicts during the revert process, resolve them manually. Git will guide you through the conflict resolution process.&lt;/p&gt;

&lt;p&gt;After juggling with conflicts like a clumsy magician (sorry, what I mean is, after resolving all the conflicts), run &lt;code&gt;git revert --continue&lt;/code&gt; to continue with the revert process. This will finally create a new revert commit, C6, that undoes the changes introduced in C2, leading to the following history:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C1 - C2 - C3 - C4 - C5 - C6
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Revert a revert&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Some times you can find yourself in a git time loop, reverting a revert, undoing an undo.&lt;/li&gt;
&lt;li&gt;This often happens when you revert a commit only to realize it was a mistake, disrupting the fabric of your code continuum. But wait! Is that a glimmer of hope on the horizon? Yes, it's the git time machine offering you a chance to set things right.&lt;/li&gt;
&lt;li&gt;All you gotta do is &lt;code&gt;git log&lt;/code&gt; to find the hash for the revert commit, in our case it will be the hash for C6.&lt;/li&gt;
&lt;li&gt;After getting the hash, run &lt;code&gt;git revert &amp;lt;hash-for-C6&amp;gt;&lt;/code&gt;, which will create a new revert commit, C7, that undoes the undone changes introduced in C2, leading to the following history:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C1 - C2 - C3 - C4 - C5 - C6 - C7
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The contents of the above history will be like when it started, as below:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C1 - C2 - C3 - C4 - C5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When you are done with your revert(s), if need be, &lt;code&gt;git push&lt;/code&gt; the changes to your remote repository.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Choose Your Destiny&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Your mission, should you choose to accept any of these methods, is to rewrite history without causing a paradox. If any of your projects vanish or get tangled in a time loop, the keyboards responsible for this article will disavow any knowledge of your actions. This article will never self-destruct... well, unless a glitch in the space-time continuum intervenes. Good luck git adventurers. Some of you might get the humor after traveling "back to the future" 😅. Essentially though you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;use &lt;em&gt;git reset&lt;/em&gt; when:

&lt;ul&gt;
&lt;li&gt;you want to rewind the HEAD or branch pointer, and you're okay with completely discarding changes.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;use &lt;em&gt;git revert&lt;/em&gt; when:

&lt;ul&gt;
&lt;li&gt;you want to undo changes in a public branch without rewriting history,&lt;/li&gt;
&lt;li&gt;you want to maintaining a linear progression of commits,&lt;/li&gt;
&lt;li&gt;you want to selectively reverse specific files.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;So, which path will you choose? Whichever path you take, experiment, explore, but always tread carefully. Until next time, cheerio 😁.&lt;/p&gt;

</description>
      <category>git</category>
      <category>learning</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Push to Multiple Repositories Simultaneously Using Git Hooks</title>
      <dc:creator>David Ochiel</dc:creator>
      <pubDate>Wed, 15 May 2024 17:16:28 +0000</pubDate>
      <link>https://forem.com/nguonodave/push-to-multiple-repositories-simultaneously-using-git-hooks-4cmf</link>
      <guid>https://forem.com/nguonodave/push-to-multiple-repositories-simultaneously-using-git-hooks-4cmf</guid>
      <description>&lt;p&gt;Automating repetitive tasks is crucial in software development to enhance workflow efficiency. In this article, we'll dive into leveraging git hooks to automate actions after each commit, to push to two different repositories, one in github, and another in gitea.&lt;/p&gt;

&lt;h2&gt;
  
  
  What are hooks?
&lt;/h2&gt;

&lt;p&gt;Hooks are scripts that git executes in response to certain events. There are various types of hooks, including pre-commit, post-commit, pre-push, and more. In git, you can use hooks to perform tasks like sending notifications, triggering builds, or updating deployments automatically after each commit. Check out &lt;a href="https://git-scm.com/book/en/v2/Customizing-Git-Git-Hooks" rel="noopener noreferrer"&gt;this&lt;/a&gt; documentation for more on hooks.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up a Post-Commit Hook
&lt;/h2&gt;

&lt;p&gt;To set up a post-commit hook in your git repository, follow these steps:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create a directory, say, &lt;u&gt;myproject&lt;/u&gt; using &lt;code&gt;mkdir myproject&lt;/code&gt;, where you will place you project files and directories.&lt;/li&gt;
&lt;li&gt;Navigate to the directory using &lt;code&gt;cd myproject/&lt;/code&gt;, customize your development environment using the &lt;code&gt;git config --global&lt;/code&gt; convention, and initialize a git repository, &lt;code&gt;git init&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Create the remote repositories for both gitea and github. For github, you will need to have a &lt;a href="https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens" rel="noopener noreferrer"&gt;PAT&lt;/a&gt; for push authentication.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# gitea&lt;/span&gt;
git remote add gitea &amp;lt;repository-url&amp;gt;

&lt;span class="c"&gt;# github&lt;/span&gt;
git remote add github https://&amp;lt;your-token&amp;gt;@github.com/&amp;lt;username&amp;gt;/&amp;lt;repository-name&amp;gt;.git

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;After that, when you run, &lt;code&gt;git remote&lt;/code&gt; you should have the following as your remote repositories:
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;gitea
github
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Navigate to the .git directory and create a post-commit script in the hooks directory. Note that the post-commit script doesn't have to have an extension.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; .git/
nano hooks/post-commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The nano text editor will open as in the image below:&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%2Fowgomxqg2whbwyydxld2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fowgomxqg2whbwyydxld2.png" alt="Image description" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Write your desired actions or commands in the script. In this case, copy and paste the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Push changes to Gitea
git push gitea master

# Push changes to GitHub
git push github master
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The result should be as per the image below:&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%2Ff1ce6otva2w2ae0r1k5t.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ff1ce6otva2w2ae0r1k5t.png" alt="Image description" width="800" height="461"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To save your file, press &lt;strong&gt;CTRL+X&lt;/strong&gt;, then &lt;strong&gt;y&lt;/strong&gt;, then press &lt;strong&gt;ENTER&lt;/strong&gt; key.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Ensure the script has execute permissions.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod&lt;/span&gt; +x hooks/post-commit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Start working on your project
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# move back from the .git directory&lt;/span&gt;
&lt;span class="nb"&gt;cd&lt;/span&gt; ..

&lt;span class="c"&gt;# work on your project&lt;/span&gt;
&lt;span class="nb"&gt;touch &lt;/span&gt;README.md
git add &lt;span class="nb"&gt;.&lt;/span&gt;
git commit &lt;span class="nt"&gt;-m&lt;/span&gt; &lt;span class="s2"&gt;"first commit"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So why wait? Start using hooks today and take your development workflow to the next level!&lt;/p&gt;

&lt;p&gt;If you have any questions, concerns, or want to share your experiences with hooks, feel free to leave a comment below.&lt;/p&gt;

&lt;p&gt;Happy coding :)&lt;/p&gt;

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