<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>strboul blog</title><link href="https://blog.strboul.com/" rel="alternate"></link><link href="https://blog.strboul.com/feeds/rss.xml" rel="self"></link><id>https://blog.strboul.com/</id><updated>2025-08-24T00:00:00+02:00</updated><entry><title>Best git habits worth doing</title><link href="https://blog.strboul.com/posts/best-git-habits/" rel="alternate"></link><published>2025-08-24T00:00:00+02:00</published><updated>2025-08-24T00:00:00+02:00</updated><author><name>Metin Yazici</name></author><id>tag:blog.strboul.com,2025-08-24:/posts/best-git-habits/</id><summary type="html">&lt;div class="toc"&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#use-a-client"&gt;Use a client&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#make-atomic-commits"&gt;Make atomic commits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#sign-your-commits"&gt;Sign your commits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#set-up-commit-hooks"&gt;Set up commit hooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#use-force-with-lease-instead-of-force"&gt;Use force-with-lease instead of force&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;Over the years, I've tried many workflows, shortcuts, and team conventions
while working with git.
No two teams worked the same way, but I found a handful of habits that
consistently made …&lt;/p&gt;</summary><content type="html">&lt;div class="toc"&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="#use-a-client"&gt;Use a client&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#make-atomic-commits"&gt;Make atomic commits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#sign-your-commits"&gt;Sign your commits&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#set-up-commit-hooks"&gt;Set up commit hooks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="#use-force-with-lease-instead-of-force"&gt;Use force-with-lease instead of force&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;Over the years, I've tried many workflows, shortcuts, and team conventions
while working with git.
No two teams worked the same way, but I found a handful of habits that
consistently made my life easier.
In this post, I'll share the habits and tools that are worth doing.
These aren't strict rules or universal standards, just practical lessons
learned from real-world projects.&lt;/p&gt;
&lt;h2 id="use-a-client"&gt;Use a client&lt;/h2&gt;
&lt;p&gt;git was designed to work as a backend system.
UX is not git's forte.
Using a client makes your work easier and more visual.&lt;/p&gt;
&lt;p&gt;My favorite client is &lt;a href="https://github.com/jesseduffield/lazygit"&gt;lazygit&lt;/a&gt;.
It allows me to perform many git operations through a simple interface and it
runs on the terminal so that's very universal.&lt;/p&gt;
&lt;h2 id="make-atomic-commits"&gt;Make atomic commits&lt;/h2&gt;
&lt;p&gt;Atomic commits mean that each commit should represent one logical change. Avoid
making a change in one commit and then overwriting that change in another
commit on the same branch. This approach makes several things easier:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Code reviews become simpler&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Debugging with &lt;code&gt;git bisect&lt;/code&gt; works better&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Reverting changes is straightforward&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It's up to you if you amend commits manually and rebase or use fixup commits.
Fixup commits are better choice before finishing the process, because it lets
you see what you overwrite and easily revert changes if needed.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;git commit --fixup &amp;lt;commit-sha-you-want-to-fixup&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can also use a tool like
&lt;a href="https://github.com/tummychow/git-absorb"&gt;git-absorb&lt;/a&gt; creating atomic commits
automatically.&lt;/p&gt;
&lt;p&gt;Also, if you use &lt;a href="https://github.com/jesseduffield/lazygit"&gt;lazygit&lt;/a&gt; client,
you can easily amend commits or create fixups through the interface.&lt;/p&gt;
&lt;h2 id="sign-your-commits"&gt;Sign your commits&lt;/h2&gt;
&lt;p&gt;Signing commits is important for public repositories.
git identities are not protected by security measures.
Anyone can pretend to be someone else by using their name and email.&lt;/p&gt;
&lt;p&gt;You can sign commits in two ways: GPG and SSH.&lt;/p&gt;
&lt;p&gt;GPG was the first way to sign commits.
However, I no longer recommend it because managing GPG is a complex process.
Of course, it's still a valid choice.&lt;/p&gt;
&lt;p&gt;SSH signature verification is available since the version 2.34.
This works well if you already use SSH to connect to git repositories.&lt;/p&gt;
&lt;p&gt;Add your SSH private key to the local repository:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;git config --local user.signingkey &amp;lt;path-to-private-key&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add your public key to the allowed signers file:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;echo &amp;quot;$(git config --get user.email) namespaces=\&amp;quot;git\&amp;quot; $(cat ~/.ssh/&amp;lt;git-ssh-key&amp;gt;.pub)&amp;quot; &amp;gt;&amp;gt; ~/.config/git/allowed_signers
git config gpg.ssh.allowedSignersFile &amp;quot;~/.config/git/allowed_signers&amp;quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;View signature status for commits:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;git log --show-signature
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Turn off signing for a specific repository if needed:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;git config --local commit.gpgsign false
&lt;/code&gt;&lt;/pre&gt;
&lt;h2 id="set-up-commit-hooks"&gt;Set up commit hooks&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://github.com/pre-commit/pre-commit"&gt;pre-commit&lt;/a&gt; is the most popular tool
for managing commit hooks.
You can also create custom hooks by placing them in the &lt;code&gt;.git/hooks&lt;/code&gt; folder.&lt;/p&gt;
&lt;p&gt;My only advice here is that when setting up hooks, focus on getting the best
value for your time. You do not need to automate everything to the full.&lt;/p&gt;
&lt;h2 id="use-force-with-lease-instead-of-force"&gt;Use force-with-lease instead of force&lt;/h2&gt;
&lt;p&gt;When you need to rewrite shared history, use &lt;code&gt;--force-with-lease&lt;/code&gt; instead of
&lt;code&gt;--force&lt;/code&gt;. This option prevents you from overwriting other people's commits
that you have not seen yet.&lt;/p&gt;</content><category term="posts"></category><category term="git"></category></entry><entry><title>Spaces of learning</title><link href="https://blog.strboul.com/posts/spaces-of-learning/" rel="alternate"></link><published>2025-06-01T00:00:00+02:00</published><updated>2025-06-01T00:00:00+02:00</updated><author><name>Metin Yazici</name></author><id>tag:blog.strboul.com,2025-06-01:/posts/spaces-of-learning/</id><summary type="html">&lt;p&gt;I still remember exactly where I was when I learned certain topics. When I
first studied BFS and DFS, it was King's Day in the Netherlands and I had gone
to the university library. The library was closed, so I had to roam on the
streets and took breaks to …&lt;/p&gt;</summary><content type="html">&lt;p&gt;I still remember exactly where I was when I learned certain topics. When I
first studied BFS and DFS, it was King's Day in the Netherlands and I had gone
to the university library. The library was closed, so I had to roam on the
streets and took breaks to read.&lt;/p&gt;
&lt;p&gt;Another time, when I was learning about heaps, I was on a train, sunlight
shining in through the window. Those little details stuck with me, and now I
can't separate the concepts from the moments in which I learned them.&lt;/p&gt;
&lt;p&gt;I've also noticed how much mood matters. When you're trying to learn something,
it helps to be calm and not agitated, and to create an environment where
distractions are blocked out.&lt;/p&gt;
&lt;p&gt;Actually, blocking distractions is a whole topic of its own. That's for another
time.&lt;/p&gt;</content><category term="posts"></category><category term="meta"></category><category term="learning"></category></entry><entry><title>Direnv supports .env files</title><link href="https://blog.strboul.com/posts/direnv-dot/" rel="alternate"></link><published>2025-02-08T00:00:00+01:00</published><updated>2025-02-08T00:00:00+01:00</updated><author><name>Metin Yazici</name></author><id>tag:blog.strboul.com,2025-02-08:/posts/direnv-dot/</id><summary type="html">&lt;p&gt;&lt;a href="https://direnv.net/"&gt;direnv&lt;/a&gt; is a fantastic tool that automatically loads
environment variables when you switch directories.&lt;/p&gt;
&lt;p&gt;By default, direnv works with &lt;code&gt;.envrc&lt;/code&gt; files, but it can also load .env files
automatically.
This feature isn’t prominently documented,
but thanks to &lt;a href="https://github.com/direnv/direnv/issues/284#issuecomment-1517901600"&gt;this GitHub comment&lt;/a&gt;,
there's a simple way to do it.&lt;/p&gt;
&lt;p&gt;Add the …&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://direnv.net/"&gt;direnv&lt;/a&gt; is a fantastic tool that automatically loads
environment variables when you switch directories.&lt;/p&gt;
&lt;p&gt;By default, direnv works with &lt;code&gt;.envrc&lt;/code&gt; files, but it can also load .env files
automatically.
This feature isn’t prominently documented,
but thanks to &lt;a href="https://github.com/direnv/direnv/issues/284#issuecomment-1517901600"&gt;this GitHub comment&lt;/a&gt;,
there's a simple way to do it.&lt;/p&gt;
&lt;p&gt;Add the following line to your &lt;code&gt;.envrc&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;dotenv_if_exists .env
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, allow direnv to apply the changes:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;direnv allow
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, whenever you enter the directory, direnv will automatically load the &lt;code&gt;.env&lt;/code&gt;.&lt;/p&gt;</content><category term="posts"></category><category term="direnv"></category></entry><entry><title>Multithreading in Python</title><link href="https://blog.strboul.com/posts/python-threading/" rel="alternate"></link><published>2024-03-12T00:00:00+01:00</published><updated>2024-03-12T00:00:00+01:00</updated><author><name>Metin Yazici</name></author><id>tag:blog.strboul.com,2024-03-12:/posts/python-threading/</id><summary type="html">&lt;p&gt;Python threads are useful for isolating programs and performing background
tasks.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-py"&gt;import threading
import subprocess
import time

def calculate_sum(sleep, which_thread):
    time.sleep(sleep)
    result = 2 + 2
    print(f&amp;quot;{which_thread}: 2 + 2 = {result}&amp;quot;)

def sleep(time, which_thread):
    process = subprocess.Popen(
        [&amp;quot;sleep&amp;quot;, str(time)], stdout=subprocess.PIPE, stderr=subprocess.PIPE
    )
    exit_code …&lt;/code&gt;&lt;/pre&gt;</summary><content type="html">&lt;p&gt;Python threads are useful for isolating programs and performing background
tasks.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-py"&gt;import threading
import subprocess
import time

def calculate_sum(sleep, which_thread):
    time.sleep(sleep)
    result = 2 + 2
    print(f&amp;quot;{which_thread}: 2 + 2 = {result}&amp;quot;)

def sleep(time, which_thread):
    process = subprocess.Popen(
        [&amp;quot;sleep&amp;quot;, str(time)], stdout=subprocess.PIPE, stderr=subprocess.PIPE
    )
    exit_code = process.wait()
    status = &amp;quot;finished&amp;quot; if exit_code == 0 else &amp;quot;failed&amp;quot;
    print(f&amp;quot;{which_thread}: sleep '{time}' {status}. exit code: {exit_code}&amp;quot;)

if __name__ == &amp;quot;__main__&amp;quot;:
    threads = [
        threading.Thread(target=calculate_sum, args=(0, &amp;quot;Thread 1&amp;quot;,)),
        threading.Thread(target=calculate_sum, args=(1, &amp;quot;Thread 2&amp;quot;,)),
        threading.Thread(target=sleep, args=(5, &amp;quot;Thread 3&amp;quot;,)),
        threading.Thread(target=sleep, args=(&amp;quot;fail&amp;quot;, &amp;quot;Thread 4&amp;quot;,)),
    ]
    # Start threads
    for thread in threads:
        thread.start()
    # Wait for both threads to finish
    for thread in threads:
        thread.join()
    # The program will continue once both threads have finished
    print(&amp;quot;Program completed.&amp;quot;)

# Thread 1: 2 + 2 = 4
# Thread 4: sleep 'fail' failed. exit code: 1
# Thread 2: 2 + 2 = 4
# Thread 3: sleep '5' finished. exit code: 0
# Program completed.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Yet, threading in Python doesn't always inherently enhance performance.
CPU-intensive executions may not fully exploit threading due to the GIL
constraint but I/O-bound operations can still get some degree of benefit.
There's some work on CPython that GIL may be removed in the future versions of
Python (currently 3.12+ is the latest one).&lt;/p&gt;</content><category term="posts"></category><category term="python"></category></entry><entry><title>How to stop auditd service</title><link href="https://blog.strboul.com/posts/stop-auditd/" rel="alternate"></link><published>2023-05-07T00:00:00+02:00</published><updated>2023-05-07T00:00:00+02:00</updated><author><name>Metin Yazici</name></author><id>tag:blog.strboul.com,2023-05-07:/posts/stop-auditd/</id><summary type="html">&lt;p&gt;You may sometimes want to stop the &lt;code&gt;auditd&lt;/code&gt; service (hopefully temporarily!).
Here the solution to overcome that error message that stops you in your tracks.&lt;/p&gt;
&lt;p&gt;You command to stop the service and you get this weird error message:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;sudo systemctl stop auditd.service
# Failed to stop auditd.service: Operation refused …&lt;/code&gt;&lt;/pre&gt;</summary><content type="html">&lt;p&gt;You may sometimes want to stop the &lt;code&gt;auditd&lt;/code&gt; service (hopefully temporarily!).
Here the solution to overcome that error message that stops you in your tracks.&lt;/p&gt;
&lt;p&gt;You command to stop the service and you get this weird error message:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;sudo systemctl stop auditd.service
# Failed to stop auditd.service: Operation refused, unit auditd.service may be
# requested by dependency only (it is configured to refuse manual start/stop).
# See system logs and 'systemctl status auditd.service' for details.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Edit the &lt;code&gt;auditd&lt;/code&gt; service configuration &lt;em&gt;(Pick your favorite &lt;code&gt;EDITOR&lt;/code&gt;)&lt;/em&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;sudo EDITOR=vim systemctl edit auditd.service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then add the following lines at the top of the file, between the override
remarks. That's how systemd service files are edited.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;### Editing /etc/systemd/system/auditd.service.d/override.conf
### Anything between here and the comment below will become the contents of the drop-in file

[Unit]
RefuseManualStop=no

# ...

### Edits below this comment will be discarded
# ...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Reload the daemon and then you are able to start/stop the service as you want.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;sudo systemctl daemon-reload
sudo systemctl stop auditd
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then there's no more frustrating error messages preventing you from stopping
&lt;code&gt;auditd&lt;/code&gt; (or any kind of systemd service).&lt;/p&gt;</content><category term="posts"></category><category term="auditd"></category><category term="systemd"></category></entry></feed>