<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
  <!-- Source: https://optimizedbyotto.com/index.xml -->
  <channel>
    <title>Optimized by Otto</title>
    <link>https://siftrss.com/f/bJDq9J7YnK</link>
    <description>Recent content on Optimized by Otto</description>
    <generator>Hugo -- gohugo.io</generator>
    <language>en-us</language>
    <copyright>Otto Kekäläinen</copyright>
    <lastBuildDate>Thu, 19 Mar 2026 00:00:00 +0000</lastBuildDate>
    <atom:link href="https://siftrss.com/f/bJDq9J7YnK" rel="self" type="application/rss+xml"/>
    <item>
      <title>Automated security validation: How 7,000+ tests shaped MariaDB's new AppArmor profile</title>
      <link>https://optimizedbyotto.com/post/new-apparmor-profile-for-mariadb/</link>
      <pubDate>Thu, 19 Mar 2026 00:00:00 +0000</pubDate>
      <guid>https://optimizedbyotto.com/post/new-apparmor-profile-for-mariadb/</guid>
      <description>&lt;img src="https://optimizedbyotto.com/post/new-apparmor-profile-for-mariadb/mariadb-apparmor-profile-debian-ubuntu.jpg" alt="Featured image of post Automated security validation: How 7,000+ tests shaped MariaDB's new AppArmor profile" /&gt;&lt;p&gt;Linux kernel security modules provide a good additional layer of security around individual programs by restricting what they are allowed to do, and at best block and detect zero-day security vulnerabilities as soon as anyone tries to exploit them, long before they are widely known and reported. However, the challenge is &lt;strong&gt;how to create these security profiles without accidentally also blocking legitimate actions&lt;/strong&gt;. For MariaDB in Debian and Ubuntu, a new AppArmor profile was recently created by leveraging the extensive test suite with 7000+ tests, giving good confidence that AppArmor is unlikely to yield false positive alerts with it.&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://en.wikipedia.org/wiki/AppArmor" target="_blank" rel="noopener"
&gt;AppArmor&lt;/a&gt; is a Mandatory Access Control (MAC) system, meaning that each process controlled by AppArmor has a sort of an &amp;ldquo;allowlist&amp;rdquo; called &lt;em&gt;profile&lt;/em&gt; that defines all capabilities and file paths a program can access. If a program tries to do something not covered by the rules in its AppArmor profile, the action will be denied on the Linux kernel level and a warning logged in the system journal. This additional security layer is valuable because even if a malicious user found a security vulnerability some day in the future, the AppArmor profile severely restricts the ability to exploit it and gain access to the operating system.&lt;/p&gt;
&lt;p&gt;AppArmor was originally developed by Novell for use in &lt;a class="link" href="https://en.wikipedia.org/wiki/SUSE_Linux_Enterprise" target="_blank" rel="noopener"
&gt;SUSE Linux&lt;/a&gt;, but nowadays the main driver is Canonical and AppArmor is extensively used in &lt;a class="link" href="https://ubuntu.com/" target="_blank" rel="noopener"
&gt;Ubuntu&lt;/a&gt; and &lt;a class="link" href="https://www.debian.org/" target="_blank" rel="noopener"
&gt;Debian&lt;/a&gt;, and many of their derivatives (e.g. Linux Mint, Pop!_OS, Zorin OS) and in &lt;a class="link" href="https://wiki.archlinux.org/title/AppArmor" target="_blank" rel="noopener"
&gt;Arch&lt;/a&gt;. AppArmor&amp;rsquo;s benefit compared to the main alternative SELinux (used mainly in the RedHat/Fedora ecosystem) is that AppArmor is easier to manage. AppArmor continues to be actively developed, with new major version 5.0 expected to arrive soon.&lt;/p&gt;
&lt;p&gt;I also have some personal history contributing some notification handler scripts in Python and I also created the website that &lt;a class="link" href="https://apparmor.net/" target="_blank" rel="noopener"
&gt;AppArmor.net&lt;/a&gt; still runs.&lt;/p&gt;
&lt;h2 id="regular-review-of-denials-in-the-system-log-required"&gt;&lt;a href="#regular-review-of-denials-in-the-system-log-required" class="header-anchor"&gt;&lt;/a&gt;Regular review of denials in the system log required
&lt;/h2&gt;&lt;p&gt;Any system administrator using Debian/Ubuntu needs to know &lt;a class="link" href="https://manpages.ubuntu.com/manpages/resolute/en/man7/apparmor.7.html" target="_blank" rel="noopener"
&gt;how to check for AppArmor denials&lt;/a&gt;. &lt;strong&gt;The point of using AppArmor is kind of moot if nobody is checking the denials.&lt;/strong&gt; When AppArmor blocks an action, it logs the event to the system audit or kernel logs. Understanding these logs is crucial for troubleshooting custom configurations or identifying potential security incidents.&lt;/p&gt;
&lt;p&gt;To view recent denials, check &lt;code&gt;/var/log/audit/audit.log&lt;/code&gt; or run &lt;code&gt;journalctl -ke --grep=apparmor&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;A typical denial entry for MariaDB will look like this (split across multiple lines for legibility):&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-0"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-0" style="display:none;"&gt;msg=audit(1700000000.123:456): apparmor=&amp;#34;DENIED&amp;#34; operation=&amp;#34;open&amp;#34;
profile=&amp;#34;/usr/sbin/mariadbd&amp;#34; name=&amp;#34;/custom/data/path/test.ibd&amp;#34; pid=1234
comm=&amp;#34;mariadbd&amp;#34; requested_mask=&amp;#34;r&amp;#34; denied_mask=&amp;#34;r&amp;#34; fsuid=1000 ouid=0&lt;/code&gt;&lt;pre&gt;&lt;code&gt;msg=audit(1700000000.123:456): apparmor=&amp;#34;DENIED&amp;#34; operation=&amp;#34;open&amp;#34;
profile=&amp;#34;/usr/sbin/mariadbd&amp;#34; name=&amp;#34;/custom/data/path/test.ibd&amp;#34; pid=1234
comm=&amp;#34;mariadbd&amp;#34; requested_mask=&amp;#34;r&amp;#34; denied_mask=&amp;#34;r&amp;#34; fsuid=1000 ouid=0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;How to interpret this output:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;msg=audit(&amp;hellip;): The audit timestamp and event serial number.&lt;/li&gt;
&lt;li&gt;apparmor=&amp;ldquo;DENIED&amp;rdquo;: Indicates AppArmor blocked the action.&lt;/li&gt;
&lt;li&gt;operation: The action being attempted (e.g., &lt;code&gt;open&lt;/code&gt;, &lt;code&gt;mknod&lt;/code&gt;, &lt;code&gt;file_mmap&lt;/code&gt;, &lt;code&gt;file_perm&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;profile: The specific AppArmor profile that triggered the denial (in this case the &lt;code&gt;/usr/sbin/mariadbd&lt;/code&gt; profile).&lt;/li&gt;
&lt;li&gt;name: The file path or resource that was blocked. In the example above, a custom data path was denied access because it wasn&amp;rsquo;t defined in the profile&amp;rsquo;s allowed abstractions.&lt;/li&gt;
&lt;li&gt;comm: The command name that triggered the denial (here &lt;code&gt;mariadbd&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;requested_mask / denied_mask: Shows the permissions requested (e.g., &lt;code&gt;r&lt;/code&gt; for read, &lt;code&gt;w&lt;/code&gt; for write).&lt;/li&gt;
&lt;li&gt;pid: The process ID.&lt;/li&gt;
&lt;li&gt;fsuid: The user ID of the process attempting the action.&lt;/li&gt;
&lt;li&gt;ouid: The owner user ID of the target file.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If an action seems legit and should not be denied, the sysadmin needs to update the existing rules at &lt;code&gt;/etc/apparmor.d/&lt;/code&gt; or drop a local customization file in at &lt;code&gt;/etc/apparmor.d/local/&lt;/code&gt;. If the denied action looks malicious, the sysadmin should start a security investigation and if needed report a suspected zero-day vulnerability to the upstream software vendor (e.g. Ubuntu customers to Canonical, or MariaDB customers to MariaDB).&lt;/p&gt;
&lt;h2 id="apparmor-in-mariadb---not-a-novel-thing-and-not-easy-to-implement-well"&gt;&lt;a href="#apparmor-in-mariadb---not-a-novel-thing-and-not-easy-to-implement-well" class="header-anchor"&gt;&lt;/a&gt;AppArmor in MariaDB - not a novel thing, and not easy to implement well
&lt;/h2&gt;&lt;p&gt;Based on &lt;a class="link" href="https://jira.mariadb.org/issues/?jql=text%20~%20apparmor%20ORDER%20BY%20updated%20ASC" target="_blank" rel="noopener"
&gt;old bug reports&lt;/a&gt;, there was an AppArmor profile already back in 2011, but it was removed in MariaDB 5.1.56 due to backlash from users running into various issues. A new profile was created &lt;a class="link" href="https://github.com/MariaDB/server/commit/6050ab658696925f2a031b901eb398fff65fa92a" target="_blank" rel="noopener"
&gt;in 2015&lt;/a&gt;, but kept opt-in only due to the risk of side effects. It likely had very few users and saw minimal maintenance, getting only a handful of updates in the past 10 years.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The primary challenge in&lt;/strong&gt; using mandatory access control systems with MariaDB lies in &lt;strong&gt;the sheer breadth of MariaDB&amp;rsquo;s operational footprint&lt;/strong&gt; with diverse storage engines and plugins. Also the code base in MariaDB assumes that system calls to Linux always work – which they do under normal circumstances – and do not handle errors well if AppArmor suddenly denies a system call. MariaDB is also a large and complex piece of software to run and operate, and it can be very challenging for system administrators to root-cause that a misbehavior in their system was due to AppArmor blocking a single syscall.&lt;/p&gt;
&lt;p&gt;Ironically, AppArmor is most beneficial exactly due to the same reasons for MariaDB. The larger and more complex a software is, the larger are the odds of a security vulnerability arising between the various components. &lt;strong&gt;And AppArmor profile helps reduce this complexity down to a single access list.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Over the years there has been users requesting to get the AppArmor profile back, such as &lt;a class="link" href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=875890" target="_blank" rel="noopener"
&gt;Debian Bug#875890&lt;/a&gt; since 2017. The need was raised recently again by the Ubuntu security team during the &lt;a class="link" href="https://bugs.launchpad.net/ubuntu/&amp;#43;source/mariadb/&amp;#43;bug/2122095" target="_blank" rel="noopener"
&gt;MariaDB Ubuntu &amp;lsquo;main&amp;rsquo; inclusion review&lt;/a&gt; in 2025, which prompted a renewed effort by Debian/Ubuntu developers, mainly &lt;a class="link" href="https://salsa.debian.org/otto" target="_blank" rel="noopener"
&gt;myself&lt;/a&gt; and &lt;a class="link" href="https://salsa.debian.org/aquila" target="_blank" rel="noopener"
&gt;Aquila Macedo&lt;/a&gt;, with upstream MariaDB assistance from &lt;a class="link" href="https://salsa.debian.org/grooverdan" target="_blank" rel="noopener"
&gt;Daniel Black&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="a-fresh-approach-leverage-the-mariadb-test-suite-for-automated-testing-and-the-open-source-community-for-reviews"&gt;&lt;a href="#a-fresh-approach-leverage-the-mariadb-test-suite-for-automated-testing-and-the-open-source-community-for-reviews" class="header-anchor"&gt;&lt;/a&gt;A fresh approach: leverage the MariaDB test suite for automated testing and the open source community for reviews
&lt;/h2&gt;&lt;p&gt;The key to creating a robust AppArmor profile is the ability to know in detail what is expected and &lt;em&gt;normal&lt;/em&gt; behavior of the system. One could in theory read all of the source code in MariaDB, but with over two million lines, it is of course not feasible in practice. However, MariaDB does have a very extensive &lt;a class="link" href="https://optimizedbyotto.com/post/grokking-mariadb-test-run-mtr/" &gt;7000+ test suite&lt;/a&gt;, and running it should trigger most code paths in MariaDB. Utilizing the &lt;strong&gt;test suite was key in creating the new AppArmor profile for MariaDB&lt;/strong&gt;: we installed MariaDB on a Ubuntu system, enabled AppArmor in &lt;code&gt;complain&lt;/code&gt; mode and iterated on the &lt;em&gt;allowlist&lt;/em&gt; by running the full &lt;a class="link" href="https://mariadb.com/docs/server/clients-and-utilities/testing-tools/mariadb-test/mariadb-test-run-pl-options" target="_blank" rel="noopener"
&gt;&lt;code&gt;mariadb-test-run&lt;/code&gt;&lt;/a&gt; with all MariaDB plugins and features enabled until we had a comprehensive yet clean list of rules.&lt;/p&gt;
&lt;p&gt;To be extra diligent, we also reworked the &lt;a class="link" href="https://documentation.ubuntu.com/project/how-ubuntu-is-made/processes/automatic-package-testing-autopkgtest/" target="_blank" rel="noopener"
&gt;autopkgtest&lt;/a&gt; for MariaDB in Debian and Ubuntu CI systems to run with the AppArmor profile enabled and to print all AppArmor notices at the end of the run, making it easy to detect now and in the future if the MariaDB test suite triggers any AppArmor denials. If any test fails, the release would not get promoted further, protecting users from regressions.&lt;/p&gt;
&lt;p&gt;While developing and triggering manual test runs we used the maximal achievable test suite with 7177 tests. The test is however so extensive it takes over two hours to run, and it also has some brittle tests, so the standard test run in Debian and Ubuntu autopkgtest is limited just to MariaDB&amp;rsquo;s main suite with about 1000 tests. Having some tests fail while testing the AppArmor profile was not a problem, because we didn&amp;rsquo;t need all the tests to pass – we merely needed them to run as many code paths as possible to see if they run any system calls not accounted for in the AppArmor profile.&lt;/p&gt;
&lt;p&gt;Note that extending the profile was not just mechanical copying of log messages to the profile. For example, even though a couple of tests involve running the &lt;a class="link" href="https://manpages.debian.org/unstable/dash/dash.1.en.html" target="_blank" rel="noopener"
&gt;dash shell&lt;/a&gt;, we decided to not allow it, as it opens too much of a path for a potential exploit to access the operating system.&lt;/p&gt;
&lt;p&gt;The result of this effort is a modernized, robust profile that is now production-ready. Those interested in the exact technical details can read the &lt;a class="link" href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1130272" target="_blank" rel="noopener"
&gt;Debian Bug#1130272&lt;/a&gt; and the &lt;a class="link" href="https://salsa.debian.org/mariadb-team/mariadb-server/-/merge_requests/" target="_blank" rel="noopener"
&gt;Merge Request discussions at salsa.debian.org&lt;/a&gt;, which hosts the Debian packaging source code.&lt;/p&gt;
&lt;h2 id="now-available-in-debian-unstable-soon-ubuntu--feedback-welcome"&gt;&lt;a href="#now-available-in-debian-unstable-soon-ubuntu--feedback-welcome" class="header-anchor"&gt;&lt;/a&gt;Now available in Debian unstable, soon Ubuntu – feedback welcome!
&lt;/h2&gt;&lt;p&gt;Even though the &lt;a class="link" href="https://salsa.debian.org/mariadb-team/mariadb-server/-/blob/e32e833e7b505f1f65a6666e5499d9ea5843698c/debian/apparmor/mariadbd" target="_blank" rel="noopener"
&gt;file is just 200 lines long&lt;/a&gt;, the work to craft it spanned several weeks. To minimize risk we also did a gradual rollout by releasing the first new profile version in &lt;code&gt;complain&lt;/code&gt; mode, so AppArmor only logs would-be-denials without blocking anything. The AppArmor profile was switched to &lt;code&gt;enforce&lt;/code&gt; mode only in the very latest MariaDB revision 1:11.8.6-4 in Debian, and a NEWS item issued to help increase user awareness of this change. It is also slated for the upcoming Ubuntu 26.04 &amp;ldquo;Resolute Raccoon&amp;rdquo; release next month, providing out-of-the-box hardening for the wider ecosystem.&lt;/p&gt;
&lt;p&gt;While automated testing is extensive, it cannot simulate everything. Most notably various complicated replication topologies and all Galera setups are likely not covered. Thus, I am calling on the community to deploy this profile and monitor for any audit denials in the kernel logs. &lt;strong&gt;If you encounter unexpected behavior or legitimate denials, please submit a bug report via the &lt;a class="link" href="https://bugs.debian.org/" target="_blank" rel="noopener"
&gt;Debian Bug Tracking System&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To ensure you are running the latest MariaDB version, run &lt;code&gt;apt install --update --yes mariadb-server&lt;/code&gt;. To view the latest profile rules, run &lt;code&gt;cat /etc/apparmor.d/mariadbd&lt;/code&gt; and to see if it is enforced review the output of &lt;code&gt;aa-status&lt;/code&gt;. To quickly check if there were any AppArmor denials, simply run &lt;code&gt;journalctl -k | grep -i apparmor | grep -i mariadb&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="systemd-hardening-also-adopted-as-security-features-keep-evolving"&gt;&lt;a href="#systemd-hardening-also-adopted-as-security-features-keep-evolving" class="header-anchor"&gt;&lt;/a&gt;Systemd hardening also adopted as security features keep evolving
&lt;/h2&gt;&lt;p&gt;For those interested in &lt;a class="link" href="https://optimizedbyotto.com/post/zero-configuration-tls-mariadb-11.8/" &gt;MariaDB security hardening&lt;/a&gt;, note that also &lt;a class="link" href="https://salsa.debian.org/mariadb-team/mariadb-server/-/merge_requests/152" target="_blank" rel="noopener"
&gt;new systemd hardening options&lt;/a&gt; were rolled out in Debian/Ubuntu recently. Note that Debian and Ubuntu are mainly volunteer-driven open source developer communities, and if you find this topic interesting and you think you have the necessary skills, feel free to submit your improvement ideas as Merge Requests at &lt;a class="link" href="https://salsa.debian.org/mariadb-team/mariadb-server/-/merge_requests/" target="_blank" rel="noopener"
&gt;salsa.debian.org/mariadb-team&lt;/a&gt;. If your improvement suggestions are not Debian/Ubuntu specific, please submit them directly to upstream at &lt;a class="link" href="https://github.com/mariadb/server/" target="_blank" rel="noopener"
&gt;GitHub.com/MariaDB&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Stop using MySQL in 2026, it is not true open source</title>
      <link>https://optimizedbyotto.com/post/reasons-to-stop-using-mysql/</link>
      <pubDate>Sun, 11 Jan 2026 00:00:00 +0000</pubDate>
      <guid>https://optimizedbyotto.com/post/reasons-to-stop-using-mysql/</guid>
      <description>&lt;img src="https://optimizedbyotto.com/post/reasons-to-stop-using-mysql/featured-image.jpg" alt="Featured image of post Stop using MySQL in 2026, it is not true open source" /&gt;&lt;p&gt;&lt;strong&gt;If you care about supporting open source software, and still use MySQL in 2026, you should switch to MariaDB like so many others have already done.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The number of git commits on &lt;a class="link" href="https://github.com/mysql/mysql-server/graphs/commit-activity" target="_blank" rel="noopener"
&gt;github.com/mysql/mysql-server&lt;/a&gt; has been significantly declining in 2025. The screenshot below shows the state of git commits as of writing this in January 2026, and the picture should be alarming to anyone who cares about software being open source.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://optimizedbyotto.com/post/reasons-to-stop-using-mysql/mysql-github-commits-decreasing-2025.png"
width="927"
height="605"
srcset="https://optimizedbyotto.com/post/reasons-to-stop-using-mysql/mysql-github-commits-decreasing-2025_hu18319633465206198350.png 480w, https://optimizedbyotto.com/post/reasons-to-stop-using-mysql/mysql-github-commits-decreasing-2025.png 927w"
loading="lazy"
alt="MySQL GitHub commit activity decreasing drastically"
class="gallery-image"
data-flex-grow="153"
data-flex-basis="367px"
&gt;
&lt;/p&gt;
&lt;h2 id="this-is-not-surprising--oracle-should-not-be-trusted-as-the-steward-for-open-source-projects"&gt;&lt;a href="#this-is-not-surprising--oracle-should-not-be-trusted-as-the-steward-for-open-source-projects" class="header-anchor"&gt;&lt;/a&gt;This is not surprising – Oracle should not be trusted as the steward for open source projects
&lt;/h2&gt;&lt;p&gt;When Oracle acquired Sun Microsystems and MySQL along with it back in 2009, the European Commission almost blocked the deal due to concerns that Oracle&amp;rsquo;s goal was just to stifle competition. The deal went through as Oracle made a commitment to keep MySQL going and not kill it, but (to nobody&amp;rsquo;s surprise) Oracle has not been a good steward of MySQL as an open source project and the community around it has been withering away for years now. &lt;strong&gt;All development is done behind closed doors.&lt;/strong&gt; The publicly visible bug tracker is not the real one Oracle staff actually uses for MySQL development, and the few people who try to contribute to MySQL just see their Pull Requests and patch submissions marked as received with mostly no feedback and then those changes may or may not be in the next MySQL release, often rewritten, and with only Oracle staff in the git author/committer fields. The real author only gets a small mention in a blog post. When I was the engineering manager for the core team working on RDS MySQL and RDS MariaDB at Amazon Web Services, I oversaw my engineers&amp;rsquo; contributions to both &lt;a class="link" href="https://en.wikipedia.org/wiki/MySQL" target="_blank" rel="noopener"
&gt;MySQL&lt;/a&gt; and &lt;a class="link" href="https://en.wikipedia.org/wiki/MariaDB" target="_blank" rel="noopener"
&gt;MariaDB&lt;/a&gt; (the latter being a fork of MySQL by the original MySQL author, &lt;a class="link" href="https://en.wikipedia.org/wiki/Michael_Widenius" target="_blank" rel="noopener"
&gt;Michael Widenius&lt;/a&gt;). All the software developers in my org disliked submitting code to MySQL due to how bad the reception by Oracle was to their contributions.&lt;/p&gt;
&lt;p&gt;MariaDB is the stark opposite with all development taking place in real-time on &lt;a class="link" href="http://github.com/mariadb/server" target="_blank" rel="noopener"
&gt;github.com/mariadb/server&lt;/a&gt;, anyone being able to submit a Pull Request and get a review, all bugs being openly discussed at &lt;a class="link" href="http://jira.mariadb.org" target="_blank" rel="noopener"
&gt;jira.mariadb.org&lt;/a&gt; and so forth, just like one would expect from a true open source project. &lt;em&gt;MySQL is open source only by license&lt;/em&gt; (&lt;a class="link" href="https://github.com/mysql/mysql-server/blob/trunk/LICENSE" target="_blank" rel="noopener"
&gt;GPL v2&lt;/a&gt;), but not as a project.&lt;/p&gt;
&lt;h2 id="mysqls-technical-decline-in-recent-years"&gt;&lt;a href="#mysqls-technical-decline-in-recent-years" class="header-anchor"&gt;&lt;/a&gt;MySQL&amp;rsquo;s technical decline in recent years
&lt;/h2&gt;&lt;p&gt;Despite not being a good open source steward, Oracle should be given credit that it did keep the MySQL organization alive and allowed it to exist fairly independently and continue developing and releasing new MySQL versions well over a decade after the acquisition. I have no insight into how many customers they had, but I assume the MySQL business was fairly profitable and financially useful to Oracle, at least as long as it didn&amp;rsquo;t gain too many features to threaten Oracle&amp;rsquo;s own main database business.&lt;/p&gt;
&lt;p&gt;I don&amp;rsquo;t know why, perhaps because too many talented people had left the organization, but it seems that from a technical point of view MySQL clearly started to deteriorate from 2022 onward.&lt;/p&gt;
&lt;p&gt;When MySQL 8.0.29 was released with the default ALTER TABLE method switched to run &lt;em&gt;in-place&lt;/em&gt;, it had a lot of corner cases that didn&amp;rsquo;t work, causing the database to crash and data to corrupt for many users. The issue wasn&amp;rsquo;t fully fixed until a year later in MySQL 8.0.32. To many users annoyance Oracle announced the 8.0 series as &amp;ldquo;evergreen&amp;rdquo; and introduced features and changes in the minor releases, instead of just doing bugfixes and security fixes like users historically had learnt to expect from these x.y.Z maintenance releases.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;There was no new major MySQL version for six years.&lt;/strong&gt; After MySQL 8.0 in 2018 it wasn&amp;rsquo;t until 2023 when MySQL 8.1 was released, and it was just a short-term preview release. The first actual new major release MySQL 8.4 LTS was released in 2024. Even though it was a new major release, many users got disappointed as it had barely any new features.&lt;/p&gt;
&lt;p&gt;Many also reported degraded performance with newer MySQL versions, for example the benchmark by famous MySQL performance expert &lt;a class="link" href="https://smalldatum.blogspot.com/" target="_blank" rel="noopener"
&gt;Mark Callaghan&lt;/a&gt; below shows that on write-heavy workloads &lt;a class="link" href="https://smalldatum.blogspot.com/2025/12/performance-regressions-in-mysql-84-and.html" target="_blank" rel="noopener"
&gt;MySQL 9.5 throughput is typically 15% less than in 8.0&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://optimizedbyotto.com/post/reasons-to-stop-using-mysql/smalldatum-benchmark-mysql-new-versions-regressed.png"
width="640"
height="396"
srcset="https://optimizedbyotto.com/post/reasons-to-stop-using-mysql/smalldatum-benchmark-mysql-new-versions-regressed_hu4447823755907597961.png 480w, https://optimizedbyotto.com/post/reasons-to-stop-using-mysql/smalldatum-benchmark-mysql-new-versions-regressed.png 640w"
loading="lazy"
alt="Benchmark showing new MySQL versions being slower than the old"
class="gallery-image"
data-flex-grow="161"
data-flex-basis="387px"
&gt;
&lt;/p&gt;
&lt;p&gt;Due to newer MySQL versions deprecating many features, a lot of users also complained about &lt;strong&gt;significant struggles regarding both MySQL 5.7-&amp;gt;8.0 and 8.0-&amp;gt;8.4 upgrades&lt;/strong&gt;. With few new features and heavy focus on code base cleanup and feature deprecation, it became obvious to many that Oracle had decided to just keep MySQL barely alive, and put all new relevant features (e.g. vector search) into Heatwave, Oracle&amp;rsquo;s closed-source and cloud-only service for MySQL customers.&lt;/p&gt;
&lt;p&gt;As it was evident that Oracle isn&amp;rsquo;t investing in MySQL, Percona&amp;rsquo;s Peter Zaitsev wrote &lt;a class="link" href="https://www.percona.com/blog/is-oracle-finally-killing-mysql/" target="_blank" rel="noopener"
&gt;Is Oracle Finally Killing MySQL&lt;/a&gt; in June 2024. At this time MySQL&amp;rsquo;s popularity as ranked by &lt;a class="link" href="https://db-engines.com/en/ranking_trend" target="_blank" rel="noopener"
&gt;DB-Engines&lt;/a&gt; had also started to tank hard, a trend that likely accelerates in 2026.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://optimizedbyotto.com/post/reasons-to-stop-using-mysql/db-engines-ranking-mysql-going-down.png"
width="925"
height="541"
srcset="https://optimizedbyotto.com/post/reasons-to-stop-using-mysql/db-engines-ranking-mysql-going-down_hu705491425668804116.png 480w, https://optimizedbyotto.com/post/reasons-to-stop-using-mysql/db-engines-ranking-mysql-going-down.png 925w"
loading="lazy"
alt="MySQL dropping significantly in DB-Engines ranking"
class="gallery-image"
data-flex-grow="170"
data-flex-basis="410px"
&gt;
&lt;/p&gt;
&lt;p&gt;In September 2025 &lt;a class="link" href="https://www.theregister.com/2025/09/11/oracle_slammed_for_mysql_job/" target="_blank" rel="noopener"
&gt;news reported&lt;/a&gt; that Oracle was reducing its workforce and that the &lt;em&gt;MySQL staff was getting heavily reduced&lt;/em&gt;. Obviously this does not bode well for MySQL&amp;rsquo;s future, and Peter Zaitsev posted already in November stats showing that the &lt;a class="link" href="https://www.linkedin.com/posts/peterzaitsev_opensource-mysql-activity-7386744600893501440-lZ7I/" target="_blank" rel="noopener"
&gt;latest MySQL maintenance release contained fewer bug fixes&lt;/a&gt; than before.&lt;/p&gt;
&lt;h2 id="open-source-is-more-than-ideology-it-has-very-real-effects-on-software-security-and-sovereignty"&gt;&lt;a href="#open-source-is-more-than-ideology-it-has-very-real-effects-on-software-security-and-sovereignty" class="header-anchor"&gt;&lt;/a&gt;Open source is more than ideology: it has very real effects on software security and sovereignty
&lt;/h2&gt;&lt;p&gt;Some say they don&amp;rsquo;t care if MySQL is truly open source or not, or that they don&amp;rsquo;t care if it has a future in coming years, as long as it still works now. I am afraid people thinking so are taking a huge risk. The database is often the most critical part of a software application stack, and any flaw or problem in operations, let alone a security issue, will have immediate consequences, and &lt;em&gt;&amp;ldquo;not caring&amp;rdquo; will eventually get people fired or sued&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;In open source problems are discussed openly, and the bigger the problem, the more people and companies will contribute to fixing it. Open source as a development methodology is similar to the scientific method with free flow of ideas that are constantly contested and only the ones with the most compelling evidence win. &lt;em&gt;Not being open means more obscurity, more risk and more &amp;ldquo;just trust us bro&amp;rdquo; attitude.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This open vs. closed is very visible for example in how Oracle handles security issues. We can see that in 2025 alone &lt;strong&gt;MySQL published 123 CVEs&lt;/strong&gt; about security issues, while &lt;a class="link" href="https://mariadb.com/docs/server/security/securing-mariadb/security" target="_blank" rel="noopener"
&gt;MariaDB had 8&lt;/a&gt;. There were 117 CVEs that only affected MySQL and not MariaDB in 2025. I haven&amp;rsquo;t read them all, but typically the CVEs hardly contain any real details. As an example, the most recent one &lt;a class="link" href="https://www.cve.org/cverecord?id=cve-2025-53067" target="_blank" rel="noopener"
&gt;CVE-2025-53067&lt;/a&gt; states &lt;em&gt;&amp;ldquo;Easily exploitable vulnerability allows high privileged attacker with network access via multiple protocols to compromise MySQL Server.&amp;rdquo;&lt;/em&gt; There is &lt;strong&gt;no&lt;/strong&gt; information a security researcher or auditor could use to verify if any original issue actually existed, or if it was fixed, or if the fix was sufficient and fully mitigating the issue or not. MySQL users just have to take the word of Oracle that it is all good now. Handling security issues like this is in stark contrast to other open source projects, where all security issues and their code fixes are open for full scrutiny after the initial embargo is over and CVE made public.&lt;/p&gt;
&lt;p&gt;There is also various forms of &lt;a class="link" href="https://en.wikipedia.org/wiki/Enshittification" target="_blank" rel="noopener"
&gt;enshittification&lt;/a&gt; going on one would not see in a true open source project, and everything about MySQL as a software, documentation and website is pushing users to stop using the open source version and move to the closed MySQL versions, and in particular to Heatwave, which is not only closed-source but also results in Oracle fully controlling customer&amp;rsquo;s databases contents.&lt;/p&gt;
&lt;p&gt;Of course, some could say this is how Oracle makes money and is able to provide a better product. But stories on &lt;a class="link" href="https://www.reddit.com/r/mysql/comments/1o298er/oracle_rif_effects_on_mysql/" target="_blank" rel="noopener"
&gt;Reddit&lt;/a&gt; and elsewhere suggest that what is going on is more like Oracle milking hard the last remaining MySQL customers who are &lt;em&gt;forced to pay more and more for getting less and less&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="there-are-options-and-migrating-is-easy-just-do-it"&gt;&lt;a href="#there-are-options-and-migrating-is-easy-just-do-it" class="header-anchor"&gt;&lt;/a&gt;There are options and migrating is easy, just do it
&lt;/h2&gt;&lt;p&gt;A large part of MySQL users switched to MariaDB already in the mid-2010s, in particular everyone who had cared deeply about their database software staying truly open source. That included large installations such as Wikipedia, and Linux distributions such as Fedora and Debian. Because it&amp;rsquo;s open source and there is no centralized machine collecting statistics, nobody knows what the exact market shares look like. There are however some application specific stats, such as that &lt;a class="link" href="https://wordpress.org/about/stats/#mysql_version" target="_blank" rel="noopener"
&gt;57% of WordPress sites around the world run MariaDB&lt;/a&gt;, while the share for MySQL is 42%.&lt;/p&gt;
&lt;p&gt;For anyone running a classic &lt;a class="link" href="https://en.wikipedia.org/wiki/LAMP_%28software_bundle%29" target="_blank" rel="noopener"
&gt;LAMP stack&lt;/a&gt; application such as WordPress, Drupal, Mediawiki, Nextcloud, or Magento, switching the old MySQL database to MariaDB is be straightforward. As MariaDB is a &lt;a class="link" href="https://en.wikipedia.org/wiki/Fork_%28software_development%29" target="_blank" rel="noopener"
&gt;fork&lt;/a&gt; of MySQL and mostly backwards compatible with it, swapping out MySQL for MariaDB can be done without changing any of the existing connectors or database clients, as they will continue to work with MariaDB as if it was MySQL.&lt;/p&gt;
&lt;p&gt;For those running custom applications and who have the freedom to make changes to how and what database is used, there are tens of mature and well-functioning open source databases to choose from, with PostgreSQL being the most popular general database. If your application was built from the start for MySQL, switching to PostgreSQL may however require a lot of work, and the MySQL/MariaDB architecture and storage engine InnoDB &lt;a class="link" href="https://www.uber.com/en-ca/blog/postgres-to-mysql-migration/" target="_blank" rel="noopener"
&gt;may still offer an edge&lt;/a&gt; in e.g. online services where high performance, scalability and solid replication features are of highest priority. For a quick and easy migration MariaDB is probably the best option.&lt;/p&gt;
&lt;p&gt;Switching from MySQL to the Percona Server is also very easy, as it closely tracks all changes in MySQL and deviates from it only by a small number of improvements done by Percona. However, also precisely because of it being basically just a customized version of the MySQL Server, it&amp;rsquo;s not a viable long-term solution for those trying to fully ditch the dependency on Oracle.&lt;/p&gt;
&lt;p&gt;There are also several open source databases that have no common ancestry with MySQL, but strive to be MySQL-compatible. Thus most apps built for MySQL can simply switch to using them without needing SQL statements to be rewritten. One such database is &lt;a class="link" href="https://en.wikipedia.org/wiki/TiDB" target="_blank" rel="noopener"
&gt;TiDB&lt;/a&gt;, which has been designed from scratch specifically for highly scalable and large systems, and is so good that even Amazon&amp;rsquo;s latest database solution DSQL was built borrowing many ideas from TiDB. However, TiDB only really shines with larger distributed setups, so for the vast majority of regular small- and mid-scale applications currently using MySQL, the most practical solution is probably to just switch to MariaDB, which on most Linux distributions can simply be installed by running &lt;code&gt;apt/dnf/brew install mariadb-server&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Whatever you end up choosing, as long as it is &lt;strong&gt;not Oracle&lt;/strong&gt;, you will be better off.&lt;/p&gt;</description>
    </item>
    <item>
      <title>DEP-18: A proposal for Git-based collaboration in Debian</title>
      <link>https://optimizedbyotto.com/post/debian-collaboration-on-git/</link>
      <pubDate>Sun, 30 Nov 2025 00:00:00 +0000</pubDate>
      <guid>https://optimizedbyotto.com/post/debian-collaboration-on-git/</guid>
      <description>&lt;img src="https://optimizedbyotto.com/post/debian-collaboration-on-git/debian-git-collaboration.jpg" alt="Featured image of post DEP-18: A proposal for Git-based collaboration in Debian" /&gt;&lt;p&gt;I am a huge fan of Git, as I have witnessed how it has made software development so much more productive compared to the pre-2010s era. I wish all Debian source code were in Git to reap the full benefits.&lt;/p&gt;
&lt;p&gt;Git is not perfect, as it requires significant effort to learn properly, and the ecosystem is complex with even more things to learn ranging from cryptographic signatures and commit hooks to Git-assisted code review best practices, &amp;lsquo;forge&amp;rsquo; websites, and CI systems.&lt;/p&gt;
&lt;p&gt;Sure, there is still room to optimize its use, but Git certainly has proven itself and is now the industry standard. &lt;strong&gt;Thus, some readers might be surprised to learn that Debian development in 2025 is not actually based on Git.&lt;/strong&gt; In Debian, the version control is done by the Debian archive itself. Each &amp;lsquo;commit&amp;rsquo; is a new upload to the archive, and the &amp;lsquo;commit message&amp;rsquo; is the &lt;code&gt;debian/changelog&lt;/code&gt; entry. The &amp;lsquo;commit log&amp;rsquo; is available at &lt;a class="link" href="https://snapshot.debian.org/" target="_blank" rel="noopener"
&gt;snapshots.debian.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In practice, most Debian Developers (people who have the credentials to upload to the Debian archive) do use Git and host their packaging source code on &lt;a class="link" href="https://salsa.debian.org/" target="_blank" rel="noopener"
&gt;salsa.debian.org&lt;/a&gt; – the GitLab instance of Debian. This is, however, based on each DD&amp;rsquo;s personal preferences. &lt;strong&gt;The Debian project does not have any policy requiring that packages be hosted on salsa.debian.org or be in version control at all.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="is-collaborative-software-development-possible-without-git-and-version-control-software"&gt;&lt;a href="#is-collaborative-software-development-possible-without-git-and-version-control-software" class="header-anchor"&gt;&lt;/a&gt;Is collaborative software development possible without git and version control software?
&lt;/h2&gt;&lt;p&gt;Debian, however, has some peculiarities that may be surprising to people who have grown accustomed to GitHub, GitLab or various company-internal code review systems.&lt;/p&gt;
&lt;p&gt;In Debian:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The source code of the next upload is not public but resides only on the developer&amp;rsquo;s laptop.&lt;/li&gt;
&lt;li&gt;Code contributions are plain patch files, based on the latest revision released in the Debian archive (where the &lt;code&gt;unstable&lt;/code&gt; area is equivalent to the main development branch).&lt;/li&gt;
&lt;li&gt;These patches are submitted by email to a bug tracker that does no validation or testing whatsoever.&lt;/li&gt;
&lt;li&gt;Developers applying these patches typically have elaborate Mutt or Emacs setups to facilitate fetching patches from email.&lt;/li&gt;
&lt;li&gt;There is no public staging area, no concept of rebasing patches or withdrawing a patch and replacing it with a better version.&lt;/li&gt;
&lt;li&gt;The submitter won&amp;rsquo;t see any progress information until a notification email arrives after a new version has been uploaded to the Debian archive.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This system has served Debian for three decades. It is not broken, but using the package archive just feels&amp;hellip; well, &lt;em&gt;archaic&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;There is a more efficient way, and indeed the majority of Debian packages have a metadata field &lt;code&gt;Vcs-Git&lt;/code&gt; that advertises which version control repository the maintainer uses. However, newcomers to Debian are surprised to notice that not all packages are hosted on &lt;a class="link" href="https://salsa.debian.org/" target="_blank" rel="noopener"
&gt;salsa.debian.org&lt;/a&gt; but at various random places with their own account and code submission systems, and there is nothing enforcing or even warning if the code there is &lt;strong&gt;out of sync with what was uploaded to Debian&lt;/strong&gt;. Any Debian Developer can at any time upload a new package with whatever changes, bypassing the Git repository, even when the package advertised a Git repository. All PGP signed commits, Git tags and other information in the Git repository are &lt;em&gt;just extras&lt;/em&gt; currently, as the Debian archive does not enforce or validate anything about them.&lt;/p&gt;
&lt;p&gt;This also makes contributing to multiple packages in parallel hard. One can&amp;rsquo;t just go on &lt;a class="link" href="https://salsa.debian.org/" target="_blank" rel="noopener"
&gt;salsa.debian.org&lt;/a&gt; and fork a bunch of repositories and submit Merge Requests. Currently, the &lt;strong&gt;only reliable way is to download source packages from Debian unstable&lt;/strong&gt;, develop patches on top of them, and send the final version as a plain &lt;strong&gt;patch file by email to the Debian bug tracker&lt;/strong&gt;. To my knowledge, no system exists to facilitate working with the patches in the bug tracker, such as rebasing patches 6 months later to detect if they or equivalent changes were applied or if sending refreshed versions is needed.&lt;/p&gt;
&lt;p&gt;To newcomers in Debian, it is even more surprising that there are packages that &lt;em&gt;are&lt;/em&gt; on &lt;a class="link" href="https://salsa.debian.org/" target="_blank" rel="noopener"
&gt;salsa.debian.org&lt;/a&gt; but have the Merge Requests feature disabled. This is often because the maintainer does not want to receive notification emails about new Merge Requests, but rather just emails from &lt;a class="link" href="https://bugs.debian.org/" target="_blank" rel="noopener"
&gt;bugs.debian.org&lt;/a&gt;. This may sound arrogant, but keep in mind that these developers put in the effort to set up their Mutt/Emacs workflow for the existing Debian process, and extending it to work with GitLab notifications is not trivial. There are also purists who want to do everything via the command-line (without having to open a browser, run JavaScript and maintain a live Internet connection), and tools like &lt;a class="link" href="https://manpages.debian.org/unstable/glab/glab.1.en.html" target="_blank" rel="noopener"
&gt;glab&lt;/a&gt; are not convenient enough for the full workflow.&lt;/p&gt;
&lt;h2 id="inefficient-ways-of-working-prevent-debian-from-flourishing"&gt;&lt;a href="#inefficient-ways-of-working-prevent-debian-from-flourishing" class="header-anchor"&gt;&lt;/a&gt;Inefficient ways of working prevent Debian from flourishing
&lt;/h2&gt;&lt;p&gt;I would claim, based on my personal experiences from the past 10+ years as a Debian Developer, that &lt;strong&gt;the lack of high-quality and productive tooling is seriously harming Debian&lt;/strong&gt;. The current methods of collaboration are cumbersome for aspiring contributors to learn and suboptimal to use for both new and seasoned contributors.&lt;/p&gt;
&lt;p&gt;There are no exit interviews for contributors who left Debian, no comprehensive data on reasons to contribute or stop contributing, nor are there any metrics tracking how many people tried but failed to contribute to Debian. Some data points to support my concerns do exist:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The contributor database shows that the &lt;a class="link" href="https://salsa.debian.org/rafael/debian-contrib-years" target="_blank" rel="noopener"
&gt;number of contributors is growing slower&lt;/a&gt; than Debian&amp;rsquo;s popularity.&lt;/li&gt;
&lt;li&gt;Most packages are maintained by one person working alone (just pick any package at random and look at the upload history).&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="debian-should-embrace-git-but-decision-making-is-slow"&gt;&lt;a href="#debian-should-embrace-git-but-decision-making-is-slow" class="header-anchor"&gt;&lt;/a&gt;Debian should embrace git, but decision-making is slow
&lt;/h2&gt;&lt;p&gt;Debian is all about community and collaboration. One would assume that Debian prioritized above all making collaboration tools and processes simpler, faster and less error-prone, as it would help both current and future package maintainers. Yet, it isn&amp;rsquo;t so, due to some reasons unique to Debian.&lt;/p&gt;
&lt;p&gt;There is no single company or entity running Debian, and it has managed to operate as a pure &lt;strong&gt;meritocracy and do-cracy for over 30 years&lt;/strong&gt;. This is impressive and admirable. Unfortunately, some of the infrastructure and technical processes are also nearly 30 years old and very difficult to change for the same reason: the nature of Debian&amp;rsquo;s distributed decision-making process.&lt;/p&gt;
&lt;p&gt;As a software developer and manager with 25+ years of experience, I strongly feel that developing software collaboratively using Git is a major step forward that Debian needs to take, in one form or another, and I &lt;strong&gt;hope to see other DDs voice their support&lt;/strong&gt; if they agree.&lt;/p&gt;
&lt;h2 id="debian-enhancement-proposal-18"&gt;&lt;a href="#debian-enhancement-proposal-18" class="header-anchor"&gt;&lt;/a&gt;Debian Enhancement Proposal 18
&lt;/h2&gt;&lt;p&gt;Following how consensus is achieved in Debian, I started drafting &lt;a class="link" href="https://dep-team.pages.debian.net/deps/dep18/" target="_blank" rel="noopener"
&gt;DEP-18&lt;/a&gt; in 2024, and it is currently awaiting enough &lt;em&gt;thumbs up&lt;/em&gt; at &lt;a class="link" href="https://salsa.debian.org/dep-team/deps/-/merge_requests/21" target="_blank" rel="noopener"
&gt;https://salsa.debian.org/dep-team/deps/-/merge_requests/21&lt;/a&gt; to get into &lt;em&gt;CANDIDATE&lt;/em&gt; status next.&lt;/p&gt;
&lt;p&gt;In summary, the DEP-18 proposes that everyone keen on collaborating should:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Maintain Debian packaging sources in Git on Salsa.&lt;/li&gt;
&lt;li&gt;Use Merge Requests to show your work and to get reviews.&lt;/li&gt;
&lt;li&gt;Run Salsa CI before upload.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The principles above are not novel. According to stats at e.g. &lt;a class="link" href="https://trends.debian.net/#vcs-hosting" target="_blank" rel="noopener"
&gt;trends.debian.net&lt;/a&gt;, and &lt;a class="link" href="https://udd.debian.org/cgi-bin/dep14stats.cgi" target="_blank" rel="noopener"
&gt;UDD&lt;/a&gt;, ~93% of all Debian source packages are already hosted on &lt;a class="link" href="https://salsa.debian.org/" target="_blank" rel="noopener"
&gt;salsa.debian.org&lt;/a&gt;. As of June 1st, 2025, only 1640 source packages remain that are not hosted on Salsa. The purpose of DEP-18 is to state in writing what Debian is currently doing for most packages, and thus express what among others new contributors should be learning and doing, so basic collaboration is smooth and free from structural obstacles.&lt;/p&gt;
&lt;p&gt;Most packages are also already allowing Merge Requests and using Salsa CI, but there hasn&amp;rsquo;t been any written recommendation anywhere in Debian to do so. The &lt;a class="link" href="https://www.debian.org/doc/debian-policy/" target="_blank" rel="noopener"
&gt;Debian Policy (v.4.7.2)&lt;/a&gt; does not even mention the word &amp;ldquo;Salsa&amp;rdquo; a single time. The current &lt;a class="link" href="https://www.debian.org/doc/manuals/developers-reference/" target="_blank" rel="noopener"
&gt;process documentation&lt;/a&gt; on how to do non-maintainer uploads or salvaging packages are all based on uploading packages to the archive, without any consideration of using git-based collaboration such as posting a Merge Request first. Personally I feel &lt;strong&gt;posting a Merge Request would be a better approach&lt;/strong&gt;, as it would invite collaborators to discuss and provide code reviews. If there are no responses, the submitter can proceed to merge, but compared to direct uploads to the Debian archive, the Merge Request practice at least tries to offer a time and place for discussions and reviews to happen.&lt;/p&gt;
&lt;p&gt;It could very well be that in the future somebody comes up with a new packaging format that makes upstream source package management easier, or a monorepo with all packages, or some other future structures or processes. Having a DEP to state how to do things &lt;em&gt;now&lt;/em&gt; does not prevent people from experimenting and innovating if they intentionally want to do that. The DEP is merely an expression of the minimal common denominators in the packaging workflow that maintainers and contributors should follow, &lt;em&gt;unless they know better&lt;/em&gt;.&lt;/p&gt;
&lt;h2 id="transparency-and-collaboration"&gt;&lt;a href="#transparency-and-collaboration" class="header-anchor"&gt;&lt;/a&gt;Transparency and collaboration
&lt;/h2&gt;&lt;p&gt;Among the &lt;a class="link" href="https://dep-team.pages.debian.net/deps/dep18/" target="_blank" rel="noopener"
&gt;DEP-18&lt;/a&gt; recommendations is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The recommended first step in contributing to a package is to use the built-in &amp;ldquo;Fork&amp;rdquo; feature on Salsa. This serves two purposes. Primarily, it allows any contributor to publish their Git branches and submit them as Merge Requests. Additionally, the mere existence of a list of &amp;ldquo;Forks&amp;rdquo; enables contributors to discover each other, and in rare cases when the original package is not accepting improvements, collaboration could arise among the contributors and potentially lead to permanent forks in the general meaning. Forking is a fundamental part of the dynamics in open source that helps drive quality and agreement. The ability to fork ultimately serves as the last line of defense of users&amp;rsquo; rights. Git supports this by making both temporary and permanent forks easy to create and maintain.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Further, it states:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Debian packaging work should be reasonably transparent and public to allow contributors to participate. A maintainer should push their pending changes to Salsa at regular intervals, so that a potential contributor can discover if a particular change has already been made or a bug has been fixed in version control, and thus avoid duplicate work.&lt;/p&gt;
&lt;p&gt;Debian maintainers should make reasonable efforts to publish planned changes as Merge Requests on Salsa and solicit feedback and reviews. While pushing changes directly on the main Git branch is the fastest workflow, second only to uploading all changes directly to Debian repositories, it is not an inclusive way to develop software. Even packages that are maintained by a single maintainer should at least occasionally publish Merge Requests to allow new contributors to step up and participate.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;strong&gt;I think these are key aspects leading to transparency and true open source collaboration.&lt;/strong&gt; Even though this talks about &lt;a class="link" href="https://salsa.debian.org/" target="_blank" rel="noopener"
&gt;Salsa&lt;/a&gt; — which is based on &lt;a class="link" href="https://gitlab.com/" target="_blank" rel="noopener"
&gt;GitLab&lt;/a&gt; — the concepts are universal and will work also on other forges, like &lt;a class="link" href="https://forgejo.org/" target="_blank" rel="noopener"
&gt;Forgejo&lt;/a&gt; or &lt;a class="link" href="https://github.com/" target="_blank" rel="noopener"
&gt;GitHub&lt;/a&gt;. &lt;strong&gt;The point is that sharing work-in-progress on a real-time platform&lt;/strong&gt;, with CI and other supporting features, &lt;strong&gt;empowers and motivates people&lt;/strong&gt; to iterate on code collaboratively. As an example of an anti-pattern, Oracle MySQL publishes the source code for all their releases and is license-compliant, but as they don&amp;rsquo;t publish their Git commits in real-time, it does not feel like a real open source project. Non-Oracle employees are not motivated to participate as second-class developers who are kept in the dark. Debian should embrace git and sharing work in real-time, embodying a true open source spirit.&lt;/p&gt;
&lt;h2 id="recommend-not-force"&gt;&lt;a href="#recommend-not-force" class="header-anchor"&gt;&lt;/a&gt;Recommend, not force
&lt;/h2&gt;&lt;p&gt;Note that the Debian Enhancement Proposals are not binding. Only the Debian Policy and Technical Committee decisions carry that weight. The nature of collaboration is voluntary anyway, so the DEP does not need to force anything on people who don&amp;rsquo;t want to use &lt;a class="link" href="https://salsa.debian.org/" target="_blank" rel="noopener"
&gt;salsa.debian.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The DEP-18 is also not a guide for package maintainers. I have my own views and have written detailed guides in blog articles if you want to read more on, for example, how to do &lt;a class="link" href="https://optimizedbyotto.com/post/how-to-code-review/" &gt;code reviews&lt;/a&gt; efficiently.&lt;/p&gt;
&lt;p&gt;Within DEP-18, there is plenty of room to work in many different ways, and it does not try to force one single workflow. &lt;strong&gt;The goal here is to simply have agreed-upon minimal common denominators among those who are keen to collaborate using salsa.debian.org,&lt;/strong&gt; not to dictate a complete code submission workflow.&lt;/p&gt;
&lt;p&gt;Once we reach this, there will hopefully be less friction in the most basic and recurring collaboration tasks, giving DDs more energy to improve other processes or just invest in having more and newer packages for Debian users to enjoy.&lt;/p&gt;
&lt;h2 id="next-steps"&gt;&lt;a href="#next-steps" class="header-anchor"&gt;&lt;/a&gt;Next steps
&lt;/h2&gt;&lt;p&gt;In addition to lengthy online discussions on mailing lists and DEP reviews, I also &lt;a class="link" href="https://debconf25.debconf.org/talks/135-merge-request-based-collaboration-for-debian-packages/" target="_blank" rel="noopener"
&gt;presented on this topic at DebConf 2025&lt;/a&gt; in Brest, France. Unfortunately the recording is not yet up on &lt;a class="link" href="https://peertube.debian.social/" target="_blank" rel="noopener"
&gt;Peertube&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The feedback has been overwhelmingly positive. However, there are a few loud and very negative voices that cannot be ignored. Maintaining a Linux distribution at the scale and complexity of Debian requires extraordinary talent and dedication, and people doing this kind of work often have strong views, most of the time for good reasons. We do not want to alienate existing key contributors with new processes, so maximum consensus is desirable.&lt;/p&gt;
&lt;p&gt;We also need more data on what the 1000+ current Debian Developers view as a good process to avoid being skewed by a loud minority. &lt;strong&gt;If you are a current or aspiring Debian Developer, &lt;a class="link" href="https://salsa.debian.org/dep-team/deps/-/merge_requests/21" target="_blank" rel="noopener"
&gt;please add a thumbs up&lt;/a&gt; if you think I should continue with this effort (or a thumbs down if not) on the Merge Request that would make DEP-18 have &lt;em&gt;candidate&lt;/em&gt; status.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;There is also technical work to do. Increased Git use will obviously lead to growing adoption of the new &lt;a class="link" href="https://manpages.debian.org/unstable/git-debpush/tag2upload.5.en.html" target="_blank" rel="noopener"
&gt;tag2upload&lt;/a&gt; feature, which will need to get full &lt;code&gt;git-buildpackage&lt;/code&gt; support so it can integrate into &lt;a class="link" href="https://salsa.debian.org/" target="_blank" rel="noopener"
&gt;salsa.debian.org&lt;/a&gt; without &lt;a class="link" href="https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1106071" target="_blank" rel="noopener"
&gt;turning off&lt;/a&gt; Debian packaging security features. The &lt;code&gt;git-buildpackage&lt;/code&gt; tool itself also needs various improvements, such as making contributing to multiple different packages with various levels of diligence in &lt;code&gt;debian/gbp.conf&lt;/code&gt; maintenance less error-prone.&lt;/p&gt;
&lt;p&gt;Eventually, if it starts looking like all Debian packages might get hosted on &lt;a class="link" href="https://salsa.debian.org/" target="_blank" rel="noopener"
&gt;salsa.debian.org&lt;/a&gt;, I would also start building a &lt;em&gt;review.debian.org&lt;/em&gt; website to facilitate code review aspects that are unique to Debian, such as tracking Merge Requests across GitLab projects in ways GitLab can&amp;rsquo;t do, highlighting which submissions need review most urgently, feeding code reviews and approvals into the &lt;a class="link" href="https://contributors.debian.org/" target="_blank" rel="noopener"
&gt;contributors.debian.org&lt;/a&gt; database for better attribution, and so forth.&lt;/p&gt;
&lt;p&gt;Details on this vision will be in a later blog post, so subscribe to updates!&lt;/p&gt;</description>
    </item>
    <item>
      <title>Zero-configuration TLS and password management best practices in MariaDB 11.8</title>
      <link>https://optimizedbyotto.com/post/zero-configuration-tls-mariadb-11.8/</link>
      <pubDate>Sun, 14 Sep 2025 00:00:00 +0000</pubDate>
      <guid>https://optimizedbyotto.com/post/zero-configuration-tls-mariadb-11.8/</guid>
      <description>&lt;img src="https://optimizedbyotto.com/post/zero-configuration-tls-mariadb-11.8/featured-image.jpg" alt="Featured image of post Zero-configuration TLS and password management best practices in MariaDB 11.8" /&gt;&lt;p&gt;Locking down database access is probably the single most important thing for a system administrator or software developer to prevent their application from leaking its data. As MariaDB 11.8 is the first long-term supported version with a few new key security features, let&amp;rsquo;s recap what the most important things are every DBA should know about MariaDB in 2025.&lt;/p&gt;
&lt;p&gt;Back in the old days, MySQL administrators had a habit of running the clumsy &lt;code&gt;mysql-secure-installation&lt;/code&gt; script, but it has long been obsolete. A modern MariaDB database server is already secure by default and locked down out of the box, and no such extra scripts are needed. On the contrary, the database administrator is expected to open up access to MariaDB according to the specific needs of each server. Therefore, it is important that the DBA can &lt;em&gt;understand&lt;/em&gt; and &lt;em&gt;correctly configure&lt;/em&gt; three things:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Separate application-specific users with granular permissions allowing only necessary access and no more.&lt;/li&gt;
&lt;li&gt;Distributing and storing passwords and credentials securely&lt;/li&gt;
&lt;li&gt;Ensuring all remote connections are properly encrypted&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;For holistic security, one should also consider proper auditing, logging, backups, regular security updates and more, but in this post we will focus only on the above aspects related to securing database access.&lt;/p&gt;
&lt;h2 id="how-encrypting-database-connections-with-tls-differs-from-web-server-https"&gt;&lt;a href="#how-encrypting-database-connections-with-tls-differs-from-web-server-https" class="header-anchor"&gt;&lt;/a&gt;How encrypting database connections with TLS differs from web server HTTP(S)
&lt;/h2&gt;&lt;p&gt;Even though MariaDB (and other databases) use the same SSL/TLS protocol for encrypting remote connections as web servers and HTTPS, the way it is implemented is &lt;strong&gt;significantly different&lt;/strong&gt;, and the different security assumptions are important for a database administrator to grasp.&lt;/p&gt;
&lt;p&gt;Firstly, most HTTP requests to a web server are unauthenticated, meaning the web server serves public web pages and does not require users to log in. Traditionally, when a user logs in over a HTTP connection, the username and password were transmitted in plaintext as a HTTP POST request. Modern TLS, which was previously called SSL, does not change how HTTP works but simply encapsulates it. When using HTTPS, a web browser and a web server will start an encrypted TLS connection as the very first thing, and only once established, do they send HTTP requests and responses inside it. There are no passwords or other shared secrets needed to form the TLS connection. Instead, the web server relies on a trusted third party, a Certificate Authority (CA), to vet that the TLS certificate offered by the web server can be trusted by the web browser.&lt;/p&gt;
&lt;p&gt;For a database server like MariaDB, the situation is quite different. All users need to &lt;strong&gt;first authenticate&lt;/strong&gt; and log in to the server before getting being allowed to run any SQL and getting any data out of the server. The database server and client programs have built-in authentication methods, and passwords are not, and have never been, sent in plaintext. Over the years, MySQL and its successor, MariaDB, have had multiple password authentication methods: the original SHA-1-based hashing, later double SHA-1-based &lt;em&gt;mysql_native_password&lt;/em&gt;, followed by &lt;em&gt;sha256_password&lt;/em&gt; and &lt;em&gt;caching_sha256_password&lt;/em&gt; in MySQL and &lt;em&gt;ed25519&lt;/em&gt; in MariaDB. The &lt;a class="link" href="https://mariadb.org/history-of-mysql-mariadb-authentication-protocols/" target="_blank" rel="noopener"
&gt;MariaDB.org blog post by Sergei Golubchik&lt;/a&gt; recaps the history of these well.&lt;/p&gt;
&lt;p&gt;Even though most modern MariaDB installations should be using TLS to encrypt all remote connections in 2025, having the authentication method be as secure as possible still matters, because &lt;strong&gt;authentication is done before the TLS connection is fully established&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;To further harden the authentication against man-in-the-middle attacks, a new password authentication method &lt;a class="link" href="https://mariadb.com/docs/server/reference/plugins/authentication-plugins/authentication-plugin-parsec" target="_blank" rel="noopener"
&gt;PARSEC was introduced in MariaDB 11.8&lt;/a&gt;, which builds upon the previous ed25519 public-key-based verification (similar to how modern SSH does), and also combines key derivation with PBKDF2 with hash functions (SHA512,SHA256) and a high iteration count.&lt;/p&gt;
&lt;p&gt;At first it may seem like a disadvantage to not wrap all connections in a TLS tunnel like HTTPS does, but actually not having the authentication done in a MitM resistant way regardless of the connection encryption status allows a clever extra capability that is now available in MariaDB: as the &lt;strong&gt;database server and client already have a shared secret&lt;/strong&gt; that is being used by the server to authenticate the user, it can also be &lt;strong&gt;used by the client to validate the server&amp;rsquo;s TLS certificate&lt;/strong&gt; and no third parties like CAs or root certificates are needed. MariaDB 11.8 was the first LTS version to ship with this capability for &lt;a class="link" href="https://mariadb.org/mission-impossible-zero-configuration-ssl/" target="_blank" rel="noopener"
&gt;zero-configuration TLS&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Note that the zero-configuration TLS also works on older password authentication methods and does not require users to have PARSEC enabled. As PARSEC is not yet the default authentication method in MariaDB, it is recommended to enable it in installations that use zero-configuration TLS encryption to maximize the security of the TLS certificate validation.&lt;/p&gt;
&lt;h2 id="why-the-root-user-in-mariadb-has-no-password-and-how-it-makes-the-database-more-secure"&gt;&lt;a href="#why-the-root-user-in-mariadb-has-no-password-and-how-it-makes-the-database-more-secure" class="header-anchor"&gt;&lt;/a&gt;Why the &amp;lsquo;root&amp;rsquo; user in MariaDB has no password and how it makes the database more secure
&lt;/h2&gt;&lt;p&gt;Relying on passwords for security is problematic, as there is always a risk that they could leak, and &lt;strong&gt;a malicious user could access the system using the leaked password&lt;/strong&gt;. It is unfortunately far too common for database passwords to be stored in plaintext in configuration files that are accidentally committed into version control and published on GitHub and similar platforms. Every application or administrative password that exists should be tracked to ensure only people who need it know it, and rotated at regular intervals to ensure old employees etc won&amp;rsquo;t be able to use old passwords. This password management is complex and error-prone.&lt;/p&gt;
&lt;p&gt;Replacing passwords with other authentication methods is always advisable when possible. On a database server, whoever installed the database by running e.g. &lt;code&gt;apt install mariadb-server&lt;/code&gt;, and configured it with e.g. &lt;code&gt;nano /etc/mysql/mariadb.cnf&lt;/code&gt;, already has full root access to the operating system, and asking them for a password to access the MariaDB database shell is moot, since they could circumvent any checks by directly accessing the files on the system anyway. Therefore, MariaDB, &lt;a class="link" href="https://mariadb.org/authentication-in-mariadb-10-4/" target="_blank" rel="noopener"
&gt;since version 10.4&lt;/a&gt; stopped requiring the root user to enter a password when connecting locally, and instead checks using socket authentication whether the user is the operating-system root user or equivalent (e.g. running &lt;code&gt;sudo&lt;/code&gt;). This is an elegant way to get rid of a password that was actually unnecessary to begin with. As there is no root password anymore, the &lt;strong&gt;risk of an external user accessing the database as root with a leaked password is fully eliminated&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Note that socket authentication only works for local connections on the same server. If you want to access a MariaDB server remotely as the &lt;code&gt;root&lt;/code&gt; user, you would need to configure a password for it first. This is not generally recommended, as explained in the next section.&lt;/p&gt;
&lt;h2 id="create-separate-database-users-for-normal-use-and-keep-root-for-administrative-use-only"&gt;&lt;a href="#create-separate-database-users-for-normal-use-and-keep-root-for-administrative-use-only" class="header-anchor"&gt;&lt;/a&gt;Create separate database users for normal use and keep &amp;lsquo;root&amp;rsquo; for administrative use only
&lt;/h2&gt;&lt;p&gt;Out of the box a MariaDB installation is already secure by default, and only the local &lt;code&gt;root&lt;/code&gt; user can connect to it. This account is intended for administrative use only, and for regular daily use you should create separate database users with access limited to the databases they need and the permissions required.&lt;/p&gt;
&lt;p&gt;The most typical commands needed to create a new database for an app and a user the app can use to connect to the database would be the following:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;sql&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-0"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-0" style="display:none;"&gt;CREATE DATABASE app_db;
CREATE USER &amp;#39;app_user&amp;#39;@&amp;#39;%&amp;#39; IDENTIFIED BY &amp;#39;your_secure_password&amp;#39;;
GRANT ALL PRIVILEGES ON app_db.* TO &amp;#39;app_user&amp;#39;@&amp;#39;%&amp;#39;;
FLUSH PRIVILEGES;&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;DATABASE&lt;/span&gt; app_db;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;USER&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;app_user&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;@&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;%&amp;#39;&lt;/span&gt; IDENTIFIED &lt;span style="color:#66d9ef"&gt;BY&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;your_secure_password&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;GRANT&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ALL&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;PRIVILEGES&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;ON&lt;/span&gt; app_db.&lt;span style="color:#f92672"&gt;*&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;TO&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;app_user&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;@&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;%&amp;#39;&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;FLUSH &lt;span style="color:#66d9ef"&gt;PRIVILEGES&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Alternatively, if you want to use the parsec authentication method, run this to create the user:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;sql&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-1"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-1" style="display:none;"&gt;CREATE OR REPLACE USER &amp;#39;app_user&amp;#39;@&amp;#39;%&amp;#39;
IDENTIFIED VIA parsec
USING PASSWORD(&amp;#39;your_secure_password&amp;#39;);&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-sql" data-lang="sql"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;CREATE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;OR&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;REPLACE&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;USER&lt;/span&gt; &lt;span style="color:#e6db74"&gt;&amp;#39;app_user&amp;#39;&lt;/span&gt;&lt;span style="color:#f92672"&gt;@&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;%&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; IDENTIFIED VIA parsec
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; &lt;span style="color:#66d9ef"&gt;USING&lt;/span&gt; PASSWORD(&lt;span style="color:#e6db74"&gt;&amp;#39;your_secure_password&amp;#39;&lt;/span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Note that the plugin auth_parsec is not enabled by default. If you see the error message &lt;code&gt;ERROR 1524 (HY000): Plugin 'parsec' is not loaded&lt;/code&gt; fix this by running &lt;code&gt;INSTALL SONAME 'auth_parsec';&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the &lt;code&gt;CREATE USER&lt;/code&gt; statements, the &lt;code&gt;@'%'&lt;/code&gt; means that the user is allowed to connect from any host. This needs to be defined, as MariaDB always checks permissions based on both the username and the remote IP address or hostname of the user, combined with the authentication method. Note that it is possible to have multiple &lt;code&gt;user@remote&lt;/code&gt; combinations, and they can have different authentication methods. A user could, for example, be allowed to log in locally using the socket authentication and over the network using a password.&lt;/p&gt;
&lt;p&gt;If you are running a custom application and you know exactly what permissions are sufficient for the database users, replace the &lt;code&gt;ALL PRIVILEGES&lt;/code&gt; with a subset of &lt;a class="link" href="https://mariadb.com/docs/server/reference/sql-statements/account-management-sql-statements/grant#privilege-levels" target="_blank" rel="noopener"
&gt;privileges listed in the MariaDB documentation&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For new permissions to take effect, restart the database or run &lt;code&gt;FLUSH PRIVILEGES&lt;/code&gt;.&lt;/p&gt;
&lt;h2 id="allow-mariadb-to-accept-remote-connections-and-enforce-tls"&gt;&lt;a href="#allow-mariadb-to-accept-remote-connections-and-enforce-tls" class="header-anchor"&gt;&lt;/a&gt;Allow MariaDB to accept remote connections and enforce TLS
&lt;/h2&gt;&lt;p&gt;Using the above &lt;code&gt;'app_user'@'%'&lt;/code&gt; is not enough on its own to allow remote connections to MariaDB. The MariaDB server also &lt;strong&gt;needs to be configured to listen on a network interface&lt;/strong&gt; to accept remote connections. As MariaDB is secure by default, it only accepts connections from &lt;code&gt;localhost&lt;/code&gt; until the administrator updates its configuration. On a typical Debian/Ubuntu system, the recommended way is to drop a new custom config in e.g. &lt;code&gt;/etc/mysql/mariadb.conf.d/99-server-customizations.cnf&lt;/code&gt;, with the contents:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-2"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-2" style="display:none;"&gt;[mariadbd]
# Listen for connections from anywhere
bind-address = 0.0.0.0
# Only allow TLS encrypted connections
require-secure-transport = on&lt;/code&gt;&lt;pre&gt;&lt;code&gt;[mariadbd]
# Listen for connections from anywhere
bind-address = 0.0.0.0
# Only allow TLS encrypted connections
require-secure-transport = on&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For settings to take effect, restart the server with &lt;code&gt;systemctl restart mariadb&lt;/code&gt;. After this, the server will accept connections on any network interface. If the system is using a firewall, the port 3306 would additionally need to be allow-listed.&lt;/p&gt;
&lt;p&gt;To confirm that the settings took effect, run e.g. &lt;code&gt;mariadb -e &amp;quot;SHOW VARIABLES LIKE 'bind_address';&amp;quot;&lt;/code&gt; , which should now show &lt;code&gt;0.0.0.0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When allowing remote connections, it is important to also always define &lt;code&gt;require-secure-transport = on&lt;/code&gt; to enforce that only TLS-encrypted connections are allowed. If the server is running MariaDB 11.8 and the clients are also MariaDB 11.8 or newer, &lt;strong&gt;no additional configuration is needed&lt;/strong&gt; thanks to MariaDB automatically providing TLS certificates and appropriate certificate validation in recent versions.&lt;/p&gt;
&lt;p&gt;On older long-term-supported versions of the MariaDB server one would have had to manually create the certificates and configure the &lt;code&gt;ssl_key&lt;/code&gt;, &lt;code&gt;ssl_cert&lt;/code&gt; and &lt;code&gt;ssl_ca&lt;/code&gt; values on the server, and distribute the certificate to the clients as well, which was cumbersome, so good it is not required anymore. In MariaDB 11.8 the only additional related config that might still be worth setting is &lt;code&gt;tls_version = TLSv1.3&lt;/code&gt; to ensure only the latest TLS protocol version is used.&lt;/p&gt;
&lt;p&gt;Finally, test connections to ensure they work and to confirm that TLS is used by running e.g.:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-3"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-3" style="display:none;"&gt;mariadb --user=app_user --password=your_secure_password \
--host=192.168.1.66 -e &amp;#39;\s&amp;#39;&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mariadb --user&lt;span style="color:#f92672"&gt;=&lt;/span&gt;app_user --password&lt;span style="color:#f92672"&gt;=&lt;/span&gt;your_secure_password &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; --host&lt;span style="color:#f92672"&gt;=&lt;/span&gt;192.168.1.66 -e &lt;span style="color:#e6db74"&gt;&amp;#39;\s&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The result should show something along:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-4"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-4" style="display:none;"&gt;--------------
mariadb from 11.8.3-MariaDB, client 15.2 for debian-linux-gnu (x86_64)
...
Current user: app_user@192.168.1.66
SSL: Cipher in use is TLS_AES_256_GCM_SHA384, cert is OK
...&lt;/code&gt;&lt;pre&gt;&lt;code&gt;--------------
mariadb from 11.8.3-MariaDB, client 15.2 for debian-linux-gnu (x86_64)
...
Current user: app_user@192.168.1.66
SSL: Cipher in use is TLS_AES_256_GCM_SHA384, cert is OK
...&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If running a Debian/Ubuntu system, see the bundled README with &lt;code&gt;zcat /usr/share/doc/mariadb-server/README.Debian.gz&lt;/code&gt; to read more configuration tips.&lt;/p&gt;
&lt;h2 id="should-tls-encryption-be-used-also-on-internal-networks"&gt;&lt;a href="#should-tls-encryption-be-used-also-on-internal-networks" class="header-anchor"&gt;&lt;/a&gt;Should TLS encryption be used also on internal networks?
&lt;/h2&gt;&lt;p&gt;If a database server and app are running on the same private network, the chances that the connection gets eavesdropped on or man-in-the-middle attacked by a malicious user are low. However, it is not zero, and if it happens, it can be difficult to detect or prove that it didn&amp;rsquo;t happen. The benefit of using end-to-end encryption is that both the database server and the client can validate the certificates and keys used, log it, and later have logs audited to prove that connections were indeed encrypted and show how they were encrypted.&lt;/p&gt;
&lt;p&gt;If all the computers on an internal network already have centralized user account management and centralized log collection that includes all database sessions, reusing existing SSH connections, SOCKS proxies, dedicated HTTPS tunnels, point-to-point VPNs, or similar solutions might also be a practical option. Note that the zero-configuration TLS only works with password validation methods. This means that systems configured to use PAM or Kerberos/GSSAPI can&amp;rsquo;t use it, but again those systems are typically part of a centrally configured network anyway and are likely to have certificate authorities and key distribution or network encryption facilities already set up.&lt;/p&gt;
&lt;p&gt;In a typical software app stack however, the simplest solution is often the best and I recommend DBAs use the end-to-end TLS encryption in MariaDB 11.8 in most cases.&lt;/p&gt;
&lt;p&gt;Hopefully with these tips you can enjoy having your MariaDB deployments both simpler and more secure than before!&lt;/p&gt;</description>
    </item>
    <item>
      <title>Going full-time as an open source developer</title>
      <link>https://optimizedbyotto.com/post/full-time-open-source-developer/</link>
      <pubDate>Wed, 16 Apr 2025 00:00:00 +0000</pubDate>
      <guid>https://optimizedbyotto.com/post/full-time-open-source-developer/</guid>
      <description>&lt;img src="https://optimizedbyotto.com/post/full-time-open-source-developer/featured-image.jpg" alt="Featured image of post Going full-time as an open source developer" /&gt;&lt;p&gt;After careful consideration, I&amp;rsquo;ve decided to embark on a new chapter in my professional journey. I&amp;rsquo;ve left my position at AWS to dedicate &lt;strong&gt;&lt;em&gt;at least&lt;/em&gt; the next six months to developing open source software&lt;/strong&gt; and strengthening digital ecosystems. My focus will be on contributing to Linux distributions (primarily Debian) and other &lt;em&gt;critical infrastructure components&lt;/em&gt; that our modern society depends on, but which may not receive adequate attention or resources.&lt;/p&gt;
&lt;h2 id="the-evolution-of-open-source"&gt;&lt;a href="#the-evolution-of-open-source" class="header-anchor"&gt;&lt;/a&gt;The Evolution of Open Source
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Open source won.&lt;/strong&gt; Over the 25+ years I&amp;rsquo;ve been involved in the open source movement, I&amp;rsquo;ve witnessed its remarkable evolution. Today, Linux powers billions of devices — from tiny embedded systems and Android smartphones to massive cloud datacenters and even space stations. Examine any modern large-scale digital system, and you&amp;rsquo;ll discover it&amp;rsquo;s built upon thousands of open source projects.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;I feel the priority for the open source movement should no longer be increasing adoption, but rather &lt;em&gt;solving how to best maintain&lt;/em&gt; the vast ecosystem of software.&lt;/strong&gt; This requires building &lt;em&gt;robust institutions and processes&lt;/em&gt; to secure proper resourcing and ensure the collaborative development process remains efficient and leads to ever-increasing quality of software.&lt;/p&gt;
&lt;h2 id="what-is-special-about-debian"&gt;&lt;a href="#what-is-special-about-debian" class="header-anchor"&gt;&lt;/a&gt;What is Special About Debian?
&lt;/h2&gt;&lt;p&gt;Debian, established in 1993 by Ian Murdock, stands as one of these institutions that has demonstrated exceptional resilience. There is no single authority, but instead a complex web of various stakeholders, each with their own goals and sources of funding. Every idea needs to be championed at length to a wide audience and implemented through a process of organic evolution.&lt;/p&gt;
&lt;p&gt;Thanks to this approach, Debian has been consistently delivering production-quality, universally useful software for over three decades. Having been a Debian Developer for more than ten years, I&amp;rsquo;m well-positioned to contribute meaningfully to this community.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;If your organization relies on Debian or its derivatives such as Ubuntu, and you&amp;rsquo;re interested in funding cyber infrastructure maintenance by &lt;em&gt;sponsoring Debian work&lt;/em&gt;, please don&amp;rsquo;t hesitate to reach out.&lt;/strong&gt; This could include package maintenance and version currency, improving automated upgrade testing, general quality assurance and supply chain security enhancements.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Best way to reach me is &lt;strong&gt;by e-mail &lt;em&gt;otto at debian.org&lt;/em&gt;&lt;/strong&gt;. You can also &lt;a class="link" href="https://cal.com/ottok" target="_blank" rel="noopener"
&gt;&lt;strong&gt;book a 15-minute chat with me&lt;/strong&gt;&lt;/a&gt; for a quick introduction.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="grow-or-die"&gt;&lt;a href="#grow-or-die" class="header-anchor"&gt;&lt;/a&gt;Grow or Die
&lt;/h2&gt;&lt;p&gt;My four-year tenure as a Software Development Manager at Amazon Web Services was very interesting. I&amp;rsquo;m grateful for my time at AWS and proud of my team&amp;rsquo;s accomplishments, particularly for creating an open source contribution process that got Amazon from zero to the largest external contributor to the MariaDB open source database.&lt;/p&gt;
&lt;p&gt;During this time, I got to experience and witness a plethora of interesting things. I will surely share some of my key learnings in future blog posts. Unfortunately, the rate of progress in this mammoth 1.5 million employee organization was slowing down, and I didn&amp;rsquo;t feel I learned much new in the last few years. This realization, combined with the opportunity cost of not spending enough time on new cutting-edge technology, motivated me to take this leap.&lt;/p&gt;
&lt;p&gt;Being a full-time open source developer may not be financially the most lucrative idea, but I think it is an excellent way to force myself to truly assess what is important on a global scale and what areas I want to contribute to.&lt;/p&gt;
&lt;p&gt;Working fully on open source presents a fascinating duality: you&amp;rsquo;re not bound by any external resource or schedule limitations, and the progress you make is directly proportional to how much energy you decide to invest. Yet, you also depend on collaboration with people you might never meet and who are not financially incentivized to collaborate. This will undoubtedly expose me to all kinds of challenges. But what would be better in fostering holistic personal growth? I know that deep down in my DNA, I am not made to stay cozy or to do easy things. &lt;strong&gt;I need momentum.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;OK, let&amp;rsquo;s get going 🙂&lt;/p&gt;</description>
    </item>
    <item>
      <title>Debian Salsa CI in Google Summer of Code 2025</title>
      <link>https://optimizedbyotto.com/post/debian-salsa-ci-gsoc-2025/</link>
      <pubDate>Tue, 25 Mar 2025 00:00:00 +0000</pubDate>
      <guid>https://optimizedbyotto.com/post/debian-salsa-ci-gsoc-2025/</guid>
      <description>&lt;img src="https://optimizedbyotto.com/post/debian-salsa-ci-gsoc-2025/featured-image.jpg" alt="Featured image of post Debian Salsa CI in Google Summer of Code 2025" /&gt;&lt;p&gt;Are you a student aspiring to participate in the &lt;a class="link" href="https://summerofcode.withgoogle.com/" target="_blank" rel="noopener"
&gt;Google Summer of Code 2025&lt;/a&gt;? Would you like to improve the continuous integration pipeline used at &lt;a class="link" href="https://salsa.debian.org" target="_blank" rel="noopener"
&gt;salsa.debian.org&lt;/a&gt;, the Debian GitLab instance, to help improve the quality of tens of thousands of software packages in Debian?&lt;/p&gt;
&lt;p&gt;This summer 2025, I and Emmanuel Arias will be participating as mentors in the GSoC program. We are available to mentor students who propose and develop improvements to the &lt;a class="link" href="https://salsa.debian.org/salsa-ci-team/pipeline" target="_blank" rel="noopener"
&gt;Salsa CI pipeline&lt;/a&gt;, as we are members of the Debian team that maintains it.&lt;/p&gt;
&lt;p&gt;A post by Santiago Ruano Rincón in the &lt;a class="link" href="https://about.gitlab.com/blog/2023/09/19/debian-customizes-ci-tooling-with-gitlab/" target="_blank" rel="noopener"
&gt;GitLab blog explains what Salsa CI is&lt;/a&gt; and its short history since inception in 2018. At the time of the article in fall 2023 there were 9000+ source packages in Debian using Salsa CI. Now in 2025 there are over &lt;a class="link" href="https://codesearch.debian.net/search?q=salsa&amp;#43;path%3Adebian%2F.*.yml&amp;amp;literal=0" target="_blank" rel="noopener"
&gt;27,000 source packages&lt;/a&gt; in Debian using it, and since summer 2024 some Ubuntu developers have started using it for enhanced quality assurance of packaging changes before uploading new package revisions to Ubuntu. Personally, I have been using Salsa CI since its inception, and contributing as a team member since 2019. See my blog post about &lt;a class="link" href="https://optimizedbyotto.com/post/gitlab-mariadb-debian/" &gt;GitLab CI for MariaDB in Debian&lt;/a&gt; for a description of an advanced and extensive use case.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Helping Salsa CI is a great way to make a global impact&lt;/strong&gt;, as it will help avoid regressions and improve the quality of Debian packages. The benefits reach far beyond just Debian, as it will &lt;a class="link" href="https://en.wikipedia.org/wiki/List_of_Linux_distributions" target="_blank" rel="noopener"
&gt;also help hundreds of Debian derivatives&lt;/a&gt;, such as Ubuntu, Linux Mint, Tails, Purism PureOS, Pop!_OS, Zorin OS, Raspberry Pi OS, a large portion of Docker containers, and even the Windows Subsystem for Linux.&lt;/p&gt;
&lt;h2 id="improving-salsa-ci-more-features-robustness-speed"&gt;&lt;a href="#improving-salsa-ci-more-features-robustness-speed" class="header-anchor"&gt;&lt;/a&gt;Improving Salsa CI: more features, robustness, speed
&lt;/h2&gt;&lt;p&gt;While Salsa CI with contributions from 71 people is already quite mature and capable, there are many ideas floating around about how it could be further extended. For example, &lt;a class="link" href="https://salsa.debian.org/salsa-ci-team/pipeline/-/issues/147" target="_blank" rel="noopener"
&gt;Salsa CI issue #147&lt;/a&gt; describes various static analyzers and linters that may be generally useful. &lt;a class="link" href="https://salsa.debian.org/salsa-ci-team/pipeline/-/issues/411" target="_blank" rel="noopener"
&gt;Issue #411&lt;/a&gt; proposes using &lt;a class="link" href="https://manpages.debian.org/bookworm/faketime/faketime.1.en.html" target="_blank" rel="noopener"
&gt;libfaketime&lt;/a&gt; to run &lt;a class="link" href="https://manpages.debian.org/bookworm/autopkgtest/autopkgtest.1.en.html" target="_blank" rel="noopener"
&gt;autopkgtest&lt;/a&gt; on arbitrary future dates to test for failures caused by date assumptions, such as the &lt;a class="link" href="https://en.wikipedia.org/wiki/Year_2038_problem" target="_blank" rel="noopener"
&gt;Y2038 issue&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There are also ideas about making Salsa CI more robust and code easier to reuse by refactoring some of the yaml scripts into independent scripts in &lt;a class="link" href="https://salsa.debian.org/salsa-ci-team/pipeline/-/issues/230" target="_blank" rel="noopener"
&gt;#230&lt;/a&gt;, which could make it easier to run Salsa CI locally as suggested in &lt;a class="link" href="https://salsa.debian.org/salsa-ci-team/pipeline/-/issues/169" target="_blank" rel="noopener"
&gt;#169&lt;/a&gt;. There are also ideas about improving the Salsa CI&amp;rsquo;s own CI to avoid regressions from pipeline changes in &lt;a class="link" href="https://salsa.debian.org/salsa-ci-team/pipeline/-/issues/318" target="_blank" rel="noopener"
&gt;#318&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The CI system is also better when it&amp;rsquo;s faster, and some speed improvement ideas have been noted in &lt;a class="link" href="https://salsa.debian.org/salsa-ci-team/pipeline/-/issues/412" target="_blank" rel="noopener"
&gt;#412&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Improvements don&amp;rsquo;t have to be limited to changes in the pipeline itself. A useful project would also be to update more Debian packages to use Salsa CI, and ensure they adopt it in an optimal way as noted in &lt;a class="link" href="https://salsa.debian.org/salsa-ci-team/pipeline/-/issues/416" target="_blank" rel="noopener"
&gt;#416&lt;/a&gt;. It would also be nice to have a dashboard with statistics about all public Salsa CI pipeline runs as suggested in &lt;a class="link" href="https://salsa.debian.org/salsa-ci-team/pipeline/-/issues/413" target="_blank" rel="noopener"
&gt;#413&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;These and more ideas can be found in the &lt;a class="link" href="https://salsa.debian.org/salsa-ci-team/pipeline/-/issues/?sort=priority_desc&amp;amp;state=opened&amp;amp;or%5Blabel_name%5D%5B%5D=Accepting%20MRs&amp;amp;or%5Blabel_name%5D%5B%5D=Newcomer&amp;amp;or%5Blabel_name%5D%5B%5D=Nice-To-Have&amp;amp;first_page_size=100" target="_blank" rel="noopener"
&gt;issue list by filtering for tags Newcomer, Nice-To-Have or Accepting MRs&lt;/a&gt;. A Google Summer of Code proposal does not have to be limited to these existing ideas. Participants are also welcome to propose completely novel ideas!&lt;/p&gt;
&lt;h2 id="good-time-to-also-learn-debian-packaging"&gt;&lt;a href="#good-time-to-also-learn-debian-packaging" class="header-anchor"&gt;&lt;/a&gt;Good time to also learn Debian packaging
&lt;/h2&gt;&lt;p&gt;Anyone working with Debian team should also take the opportunity to &lt;a class="link" href="https://optimizedbyotto.com/post/debian-maintainer-habits/" &gt;learn Debian packaging&lt;/a&gt;, and contribute to the packaging or maintenance of 1-2 packages in parallel to improving the Salsa CI. All Salsa CI team members are also Debian Developers who can mentor and sponsor uploads to Debian.&lt;/p&gt;
&lt;p&gt;Maintaining a few packages is a &lt;a class="link" href="https://en.wikipedia.org/wiki/Eating_your_own_dog_food" target="_blank" rel="noopener"
&gt;great way to eat your own cooking and experience Salsa CI from the user perspective&lt;/a&gt;, and likely to make you better at Salsa CI development.&lt;/p&gt;
&lt;h2 id="apply-now"&gt;&lt;a href="#apply-now" class="header-anchor"&gt;&lt;/a&gt;Apply now!
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;The contributor applications opened yesterday on March 24, so to participate act now!&lt;/strong&gt; If you are an eligible student and want to attend, head over to &lt;a class="link" href="https://summerofcode.withgoogle.com/" target="_blank" rel="noopener"
&gt;summerofcode.withgoogle.com&lt;/a&gt; to learn more.&lt;/p&gt;
&lt;p&gt;There are over a thousand participating organizations, with &lt;a class="link" href="https://summerofcode.withgoogle.com/programs/2025/organizations/debian" target="_blank" rel="noopener"
&gt;Debian&lt;/a&gt;, &lt;a class="link" href="https://summerofcode.withgoogle.com/programs/2025/organizations/gitlab" target="_blank" rel="noopener"
&gt;GitLab&lt;/a&gt; and &lt;a class="link" href="https://mariadb.com/kb/en/google-summer-of-code-2025/" target="_blank" rel="noopener"
&gt;MariaDB&lt;/a&gt; being some examples. Within these organizations there may be multiple subteams and projects to choose from. The &lt;a class="link" href="https://wiki.debian.org/SummerOfCode2025/Projects" target="_blank" rel="noopener"
&gt;full list of participating Debian projects&lt;/a&gt; can be found in the Debian wiki.&lt;/p&gt;
&lt;p&gt;If you are interested in &lt;a class="link" href="https://wiki.debian.org/SummerOfCode2025/Projects#SummerOfCode2025.2FApprovedProjects.2FSalsaCI.Salsa_CI_in_Debian" target="_blank" rel="noopener"
&gt;GSoC for Salsa CI&lt;/a&gt; specifically, feel free to&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Reach out to me and Emmanuel by email at otto@ and eamanu@ (debian.org).&lt;/li&gt;
&lt;li&gt;Sign up at salsa.debian.org for an account (note it takes a few days due to manual vetting and approval process)&lt;/li&gt;
&lt;li&gt;Read the project &lt;a class="link" href="https://salsa.debian.org/salsa-ci-team/pipeline/-/blob/master/README.md" target="_blank" rel="noopener"
&gt;README&lt;/a&gt;, &lt;a class="link" href="https://salsa.debian.org/salsa-ci-team/pipeline/-/blob/master/STRUCTURE.md" target="_blank" rel="noopener"
&gt;STRUCTURE&lt;/a&gt; and &lt;a class="link" href="https://salsa.debian.org/salsa-ci-team/pipeline/-/blob/master/CONTRIBUTING.md" target="_blank" rel="noopener"
&gt;CONTRIBUTING&lt;/a&gt; to get a developer&amp;rsquo;s overview&lt;/li&gt;
&lt;li&gt;Participate in issue discussions at &lt;a class="link" href="https://salsa.debian.org/salsa-ci-team/pipeline/-/issues/" target="_blank" rel="noopener"
&gt;https://salsa.debian.org/salsa-ci-team/pipeline/-/issues/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Note that you don&amp;rsquo;t have to wait for GSoC to officially start to contribute. In fact, it may be useful to start immediately by submitting a Merge Request to do some small contribution, just to learn the process and to get more familiar with how everything works, and the team maintaining Salsa CI. Looking forward to seeing new contributors!&lt;/p&gt;
&lt;blockquote&gt;
&lt;h2 id="update-may-8th-2025"&gt;&lt;a href="#update-may-8th-2025" class="header-anchor"&gt;&lt;/a&gt;Update May 8th, 2025
&lt;/h2&gt;&lt;p&gt;The approved Google Summer of Code 2025 students have now been announced, and I am thrilled that &lt;a class="link" href="https://summerofcode.withgoogle.com/programs/2025/organizations/debian" target="_blank" rel="noopener"
&gt;9 students got approved for Debian&lt;/a&gt;. I will be mentoring two students, &lt;a class="link" href="https://summerofcode.withgoogle.com/programs/2025/projects/mmwLagR0" target="_blank" rel="noopener"
&gt;Aquila&lt;/a&gt; and &lt;a class="link" href="https://summerofcode.withgoogle.com/programs/2025/projects/YTXVewUk" target="_blank" rel="noopener"
&gt;Aayush&lt;/a&gt;. You can follow their progress on the &lt;a class="link" href="https://salsa.debian.org/salsa-ci-team/pipeline" target="_blank" rel="noopener"
&gt;Salsa CI Team GitLab page&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;</description>
    </item>
    <item>
      <title>10 habits to help becoming a Debian maintainer</title>
      <link>https://optimizedbyotto.com/post/debian-maintainer-habits/</link>
      <pubDate>Sun, 26 Jan 2025 00:00:00 +0000</pubDate>
      <guid>https://optimizedbyotto.com/post/debian-maintainer-habits/</guid>
      <description>&lt;img src="https://optimizedbyotto.com/post/debian-maintainer-habits/featured-image.jpg" alt="Featured image of post 10 habits to help becoming a Debian maintainer" /&gt;&lt;p&gt;Becoming a &lt;a class="link" href="https://www.debian.org/devel/join/index.en.html#joining" target="_blank" rel="noopener"
&gt;Debian maintainer&lt;/a&gt; is a journey that combines technical expertise, community collaboration, and continuous learning. In this post, I&amp;rsquo;ll share 10 key habits that will both help you navigate the complexities of Debian packaging without getting lost and enable you to contribute more effectively to one of the world&amp;rsquo;s largest open source projects.&lt;/p&gt;
&lt;h2 id="1-read-and-re-read-the-debian-policy-the-developers-reference-and-the-git-buildpackage-manual"&gt;&lt;a href="#1-read-and-re-read-the-debian-policy-the-developers-reference-and-the-git-buildpackage-manual" class="header-anchor"&gt;&lt;/a&gt;1. Read and re-read the Debian Policy, the Developer&amp;rsquo;s Reference and the git-buildpackage manual
&lt;/h2&gt;&lt;p&gt;Anyone learning Debian packaging and aspiring to become a Debian maintainer is likely to wade through a lot of documentation, only to realize that much of it is outdated or sometimes outright incorrect.&lt;/p&gt;
&lt;p&gt;Therefore, it is important to learn right from the start which sources are the most reliable and truly worth reading and re-reading. I recommend these documents, in order of importance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://www.debian.org/doc/debian-policy/" target="_blank" rel="noopener"
&gt;The Debian Policy Manual&lt;/a&gt;: Describes the structure of the operating system, the package archive, and requirements for packages to be included in the Debian archive.&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.debian.org/doc/manuals/developers-reference/developers-reference.en.html" target="_blank" rel="noopener"
&gt;The Developer&amp;rsquo;s Reference&lt;/a&gt;: A collection of best practices and process descriptions Debian packagers are expected to follow while interacting with one another.&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://manpages.debian.org/unstable/git-buildpackage/index.html" target="_blank" rel="noopener"
&gt;The git-buildpackage man pages&lt;/a&gt;: While the Policy focuses on the end result and is intentionally void of practical instructions on creating or maintaining Debian packages, the Developer&amp;rsquo;s Reference goes into greater detail. However, it too lacks step-by-step instructions. For the exact commands, consult the man pages of git-buildpackage and its subcommands (e.g., &lt;a class="link" href="https://manpages.debian.org/unstable/git-buildpackage/gbp-clone.1.en.html" target="_blank" rel="noopener"
&gt;&lt;code&gt;gbp clone&lt;/code&gt;&lt;/a&gt;, &lt;a class="link" href="https://manpages.debian.org/unstable/git-buildpackage/gbp-import-orig.1.en.html" target="_blank" rel="noopener"
&gt;&lt;code&gt;gbp import-orig&lt;/code&gt;&lt;/a&gt;, &lt;a class="link" href="https://manpages.debian.org/unstable/git-buildpackage/gbp-pq.1.en.html" target="_blank" rel="noopener"
&gt;&lt;code&gt;gbp pq&lt;/code&gt;&lt;/a&gt;, &lt;a class="link" href="https://manpages.debian.org/unstable/git-buildpackage/gbp-dch.1.en.html" target="_blank" rel="noopener"
&gt;&lt;code&gt;gbp dch&lt;/code&gt;&lt;/a&gt;, &lt;code&gt;gbp push&lt;/code&gt;). See also my post on &lt;a class="link" href="https://optimizedbyotto.com/post/debian-source-package-git/" &gt;Debian source package Git branch and tags&lt;/a&gt; for easy to understand diagrams.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="2-make-reading-man-pages-a-habit"&gt;&lt;a href="#2-make-reading-man-pages-a-habit" class="header-anchor"&gt;&lt;/a&gt;2. Make reading man pages a habit
&lt;/h2&gt;&lt;p&gt;In addition to the above, try to make a habit of &lt;strong&gt;checking out the man page of every new tool&lt;/strong&gt; you use to ensure you are using it as intended.&lt;/p&gt;
&lt;p&gt;The best place to read accurate and up-to-date documentation is &lt;a class="link" href="http://manpages.debian.org" target="_blank" rel="noopener"
&gt;manpages.debian.org&lt;/a&gt;. The manual pages are maintained alongside the tools by their developers, ensuring greater accuracy than any third-party documentation.&lt;/p&gt;
&lt;p&gt;If you are using a tool in the way the tool author documented, you can be confident you are doing the right thing, even if it wasn&amp;rsquo;t explicitly mentioned in some third-party guide about Debian packaging best practices.&lt;/p&gt;
&lt;h2 id="3-read-and-write-emails"&gt;&lt;a href="#3-read-and-write-emails" class="header-anchor"&gt;&lt;/a&gt;3. Read and write emails
&lt;/h2&gt;&lt;p&gt;While members of the Debian community have many channels of communication, the &lt;a class="link" href="https://lists.debian.org/completeindex.html" target="_blank" rel="noopener"
&gt;mailing lists&lt;/a&gt; are by far the most prominent. Asking questions on the appropriate list is a good way to get current advice from other people doing Debian packaging. Staying subscribed to lists of interest is also a good way to read about new developments as they happen.&lt;/p&gt;
&lt;p&gt;Note that every post is public and archived permanently, so the discussions on &lt;strong&gt;the mailing lists also form a body of documentation&lt;/strong&gt; that can later be searched and referred to.&lt;/p&gt;
&lt;p&gt;Regularly writing short and well-structured emails on the mailing lists is &lt;a class="link" href="https://optimizedbyotto.com/post/efficient-communication-software-engineering-org/" &gt;great practice for improving technical communication skills&lt;/a&gt; — a useful ability in general. For Debian specifically, being active on mailing lists helps build a reputation that can later attract collaborators and supporters for more complex initiatives.&lt;/p&gt;
&lt;h2 id="4-create-and-use-an-openpgp-key"&gt;&lt;a href="#4-create-and-use-an-openpgp-key" class="header-anchor"&gt;&lt;/a&gt;4. Create and use an OpenPGP key
&lt;/h2&gt;&lt;p&gt;Related to reputation and identity, OpenPGP keys play a central role in the Debian community. OpenPGP is used to various degrees to sign Git commits and tags, sign and encrypt email, and — most importantly — to sign Debian packages so their origin can be verified.&lt;/p&gt;
&lt;p&gt;The process of becoming a Debian Maintainer and eventually a Debian Developer culminates in getting your OpenPGP key included in the Debian keyring, which is used to control who can upload packages into the Debian archive.&lt;/p&gt;
&lt;p&gt;The earlier you create a key and start using it to gain reputation for that specific key that is used to sign your work, the better. Note that due to a recent &lt;a class="link" href="https://lwn.net/Articles/953797/" target="_blank" rel="noopener"
&gt;schism&lt;/a&gt; in the OpenPGP standards working group, it is safest to create an OpenPGP key using GnuPG version 2.2.x (not 2.4.x), or using &lt;a class="link" href="https://sequoia-pgp.org/" target="_blank" rel="noopener"
&gt;Sequoia-PGP&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="5-integrate-salsa-ci-in-all-work"&gt;&lt;a href="#5-integrate-salsa-ci-in-all-work" class="header-anchor"&gt;&lt;/a&gt;5. Integrate Salsa CI in all work
&lt;/h2&gt;&lt;p&gt;One reason Debian remains popular, even 30 years after its inception, is due to its culture of maintaining high standards. For a newcomer, learning all the quality assurance tools such as Lintian, Piuparts, Adequate, various build variations, and reproducible builds may be overwhelming. However, these tasks are easier to manage thanks to Salsa CI, the continuous integration pipeline in Debian that runs tests on every commit at &lt;a class="link" href="https://salsa.debian.org/" target="_blank" rel="noopener"
&gt;salsa.debian.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The earlier you &lt;a class="link" href="https://salsa.debian.org/salsa-ci-team/pipeline" target="_blank" rel="noopener"
&gt;activate Salsa CI&lt;/a&gt; in the package repository you are working on, the faster you will achieve high quality in your package with fewer missteps. You can also further &lt;a class="link" href="https://optimizedbyotto.com/post/gitlab-mariadb-debian/" &gt;customize a package-specific &lt;code&gt;salsa-ci.yml&lt;/code&gt;&lt;/a&gt; to have more testing coverage.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://optimizedbyotto.com/post/gitlab-mariadb-debian/mariadb-salsa-ci-example.png"
loading="lazy"
alt="Example Salsa CI pipeline with customizations"
&gt;
&lt;/p&gt;
&lt;h2 id="6-fork-on-salsa-and-use-draft-merge-requests-to-solicit-feedback"&gt;&lt;a href="#6-fork-on-salsa-and-use-draft-merge-requests-to-solicit-feedback" class="header-anchor"&gt;&lt;/a&gt;6. Fork on Salsa and use draft Merge Requests to solicit feedback
&lt;/h2&gt;&lt;p&gt;All modern Debian packages are hosted on &lt;a class="link" href="https://salsa.debian.org/" target="_blank" rel="noopener"
&gt;salsa.debian.org&lt;/a&gt;. If you want to make a change to any package, it is easy to fork, make an initial attempt at the change, and publish it as a &lt;strong&gt;draft Merge Request&lt;/strong&gt; (MR) on Salsa to solicit feedback.&lt;/p&gt;
&lt;p&gt;People might have surprising reasons to object to the change you propose, or they might need time to get used to the idea before agreeing to it. Also, some people might object to a vague idea out of suspicion but agree once they see the exact implementation. There may also be a surprising number of people supporting your idea, and if there is an MR, they have a place to show their support.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Don&amp;rsquo;t expect every Merge Request to be accepted.&lt;/strong&gt; However, proposing an idea as running code in an MR is far more effective than raising the idea on a mailing list or in a bug report. Get into the habit of publishing plenty of merge requests to solicit feedback and drive discussions toward consensus.&lt;/p&gt;
&lt;h2 id="7-use-git-rebase-frequently"&gt;&lt;a href="#7-use-git-rebase-frequently" class="header-anchor"&gt;&lt;/a&gt;7. Use git rebase frequently
&lt;/h2&gt;&lt;p&gt;Linear Git history is much easier to read. The ease of reading &lt;code&gt;git log&lt;/code&gt; and &lt;code&gt;git blame&lt;/code&gt; output is vital in Debian, where packages often have updates from multiple people spanning many years — even decades. Debian packagers likely spend more time than the average software developer reading Git history.&lt;/p&gt;
&lt;p&gt;Make sure you master &lt;a class="link" href="https://optimizedbyotto.com/post/advanced-git-commands/" &gt;Git commands&lt;/a&gt; such as &lt;code&gt;gitk --all&lt;/code&gt;, &lt;code&gt;git citool --amend&lt;/code&gt;, &lt;code&gt;git commit -a --fixup &amp;lt;commit id&amp;gt;&lt;/code&gt;, &lt;code&gt;git rebase -i --autosquash &amp;lt;target branch&amp;gt;&lt;/code&gt;, &lt;code&gt;git cherry-pick &amp;lt;commit id 1&amp;gt; &amp;lt;id 2&amp;gt; &amp;lt;id 3&amp;gt;&lt;/code&gt;, and &lt;code&gt;git pull --rebase&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If rebasing is not done on your initiative, rest assured others will ask you to do it. Thus, if the commands above are familiar, rebasing will be quick and easy for you.&lt;/p&gt;
&lt;h2 id="8-reviews-give-some-get-some"&gt;&lt;a href="#8-reviews-give-some-get-some" class="header-anchor"&gt;&lt;/a&gt;8. Reviews: give some, get some
&lt;/h2&gt;&lt;p&gt;In open source, the larger a project becomes, the more it attracts contributions, and the bottleneck for its growth isn&amp;rsquo;t how much code developers can create but how much code submissions can be properly reviewed.&lt;/p&gt;
&lt;p&gt;At the time of writing, the &lt;a class="link" href="https://salsa.debian.org/groups/debian/-/merge_requests" target="_blank" rel="noopener"
&gt;main Salsa group &amp;ldquo;Debian&amp;rdquo; has over 800 open merge requests&lt;/a&gt; pending reviews and approvals. Feel free to read and comment on any merge request you find. &lt;a class="link" href="https://optimizedbyotto.com/post/how-to-code-review/" &gt;You don&amp;rsquo;t have to be a subject matter expert&lt;/a&gt; to provide valuable feedback. Even if you don&amp;rsquo;t have specific feedback, your comment as another human acknowledging that you read the MR and found no issues is viewed positively by the author. Besides, if you spend enough time reviewing MRs in a specific domain, you will eventually become an expert in it. &lt;strong&gt;Code reviews are not just about providing feedback to the submitter; they are also great learning opportunities for the reviewer.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;As a rule of thumb, you should review at least twice as many merge requests as you submit yourself.&lt;/p&gt;
&lt;h2 id="9-improve-debian-by-improving-upstream"&gt;&lt;a href="#9-improve-debian-by-improving-upstream" class="header-anchor"&gt;&lt;/a&gt;9. Improve Debian by improving upstream
&lt;/h2&gt;&lt;p&gt;It is common that while packaging software for Debian, bugs are uncovered and patched in Debian. &lt;strong&gt;Do not forget to submit the fixes upstream&lt;/strong&gt;, and add a &lt;code&gt;Forwarded&lt;/code&gt; field to the file in &lt;code&gt;debian/patches&lt;/code&gt;! As the person building and packaging something in Debian, you automatically become an authority on that software, and the upstream is likely glad to receive your improvements.&lt;/p&gt;
&lt;p&gt;While submitting patches upstream is a bit of work initially, getting improvements merged upstream eventually saves time for everyone and makes packaging in Debian easier, as there will be fewer patches to maintain with each new upstream release.&lt;/p&gt;
&lt;h2 id="10-dont-hold-any-habits-too-firmly"&gt;&lt;a href="#10-dont-hold-any-habits-too-firmly" class="header-anchor"&gt;&lt;/a&gt;10. Don&amp;rsquo;t hold any habits too firmly
&lt;/h2&gt;&lt;p&gt;Last but not least: Once people learn a specific way of working, they tend to stick to it for decades. Learning how to create and maintain Debian packages requires significant effort, and people tend to stop learning once they feel they&amp;rsquo;ve reached a sufficient level. &lt;strong&gt;This tendency to get stuck in a &amp;ldquo;local optimum&amp;rdquo; is understandable and natural, but try to resist it.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It is likely that better techniques will evolve over time, so stay humble and re-evaluate your beliefs and practices every few years.&lt;/p&gt;
&lt;p&gt;Mastering these habits takes time, but each small step brings you closer to making a meaningful impact on Debian. By staying curious, collaborative, and adaptable, you can ensure your contributions stand the test of time — just like Debian itself. Good luck on your journey toward becoming a Debian Maintainer!&lt;/p&gt;</description>
    </item>
    <item>
      <title>Advanced Git commands every senior software developer needs to know</title>
      <link>https://optimizedbyotto.com/post/advanced-git-commands/</link>
      <pubDate>Thu, 29 Feb 2024 00:00:00 +0000</pubDate>
      <guid>https://optimizedbyotto.com/post/advanced-git-commands/</guid>
      <description>&lt;img src="https://optimizedbyotto.com/post/advanced-git-commands/featured-image.jpg" alt="Featured image of post Advanced Git commands every senior software developer needs to know" /&gt;&lt;p&gt;&lt;a class="link" href="https://git-scm.com/" target="_blank" rel="noopener"
&gt;Git&lt;/a&gt; is by far the most popular software version control system today, and every software developer surely knows the basics of how to &lt;a class="link" href="https://optimizedbyotto.com/post/good-git-commit/" &gt;make a Git commit&lt;/a&gt;. Given the popularity, it is surprising how many people don&amp;rsquo;t actually know the advanced commands. Mastering them might help you unlock a new level of productivity. Let&amp;rsquo;s dive in!&lt;/p&gt;
&lt;h2 id="avoid-excess-downloads-with-selective-and-shallow-git-clone"&gt;&lt;a href="#avoid-excess-downloads-with-selective-and-shallow-git-clone" class="header-anchor"&gt;&lt;/a&gt;Avoid excess downloads with selective and shallow Git clone
&lt;/h2&gt;&lt;p&gt;When working with large Git repositories, it is not always desirable to clone the full repository as it would take too long to download. Instead you can execute the clone for example like this:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-0"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-0" style="display:none;"&gt;git clone --branch 11.5 --shallow-since=3m https://github.com/MariaDB/server.git mariadb-server&lt;/code&gt;&lt;pre&gt;&lt;code&gt;git clone --branch 11.5 --shallow-since=3m https://github.com/MariaDB/server.git mariadb-server&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will make a clone that &lt;strong&gt;only tracks branch &lt;em&gt;11.5&lt;/em&gt; and no other branches&lt;/strong&gt;. Additionally, this uses the shallow clone feature to &lt;strong&gt;fetch commit history only for the past 3 months&lt;/strong&gt; instead of the entire history (which in this example would otherwise be 20+ years). You could also specify &lt;code&gt;3w&lt;/code&gt; or &lt;code&gt;1y&lt;/code&gt; to fetch three weeks or one year. After the initial clone, you can use &lt;code&gt;git remote set-branches --add origin 10.11&lt;/code&gt; to start tracking an additional branch, which will be downloaded on &lt;code&gt;git fetch&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you already have a git repository, and all you want to do is &lt;strong&gt;fetch one single branch from a remote repository one-off&lt;/strong&gt;, without adding it as a new remote, you can run:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-1"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-1" style="display:none;"&gt;$ git fetch https://github.com/robinnewhouse/mariadb-server.git ninja-build-cracklib
From https://github.com/robinnewhouse/mariadb-server
* branch ninja-build-cracklib -&amp;gt; FETCH_HEAD
$ git merge FETCH_HEAD
Updating 112eb14f..c649d78a
Fast-forward
plugin/cracklib_password_check/CMakeLists.txt | 3 &amp;#43;&amp;#43;-
1 file changed, 2 insertions(&amp;#43;), 1 deletion(-)
$ git show
commit c649d78a8163413598b83f5717d3ef3ad9938960 (HEAD -&amp;gt; 11.5)
Author: Robin&lt;/code&gt;&lt;pre&gt;&lt;code&gt;$ git fetch https://github.com/robinnewhouse/mariadb-server.git ninja-build-cracklib
From https://github.com/robinnewhouse/mariadb-server
* branch ninja-build-cracklib -&amp;gt; FETCH_HEAD
$ git merge FETCH_HEAD
Updating 112eb14f..c649d78a
Fast-forward
plugin/cracklib_password_check/CMakeLists.txt | 3 &amp;#43;&amp;#43;-
1 file changed, 2 insertions(&amp;#43;), 1 deletion(-)
$ git show
commit c649d78a8163413598b83f5717d3ef3ad9938960 (HEAD -&amp;gt; 11.5)
Author: Robin&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This is a very fast and small download, which will not persist as a remote. It creates a temporary Git reference called &lt;code&gt;FETCH_HEAD&lt;/code&gt;, which you can then use to inspect the branch history by running &lt;code&gt;git show FETCH_HEAD&lt;/code&gt;, or you can merge it, cherry-pick, or perform other operations.&lt;/p&gt;
&lt;p&gt;If you want to download the bare minimum, you can even operate on individual commits as raw patch files. A typical example would be to &lt;strong&gt;download a GitHub Pull Request as a patch file and apply it locally&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-2"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-2" style="display:none;"&gt;$ curl -LO https://patch-diff.githubusercontent.com/raw/MariaDB/server/pull/3026.patch
$ git am 3026.patch
Applying: Fix ninja build for cracklib_password_check
$ git show
commit a9c44bc204735574f2724020842373b53864e131 (HEAD -&amp;gt; 11.5)
Author: Robin&lt;/code&gt;&lt;pre&gt;&lt;code&gt;$ curl -LO https://patch-diff.githubusercontent.com/raw/MariaDB/server/pull/3026.patch
$ git am 3026.patch
Applying: Fix ninja build for cracklib_password_check
$ git show
commit a9c44bc204735574f2724020842373b53864e131 (HEAD -&amp;gt; 11.5)
Author: Robin&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The same works for GitLab Merge Requests as well – just add &lt;code&gt;.patch&lt;/code&gt; at the end of the MR url. This will apply both the code change inside the patch, as well as honor the author field, and use the patch description as the commit subject line and message body. However, when running &lt;code&gt;git am&lt;/code&gt;, the committer name, email, and date will be that of the user applying the patch, and thus the SHA-sum of the commit ID will not be identical.&lt;/p&gt;
&lt;p&gt;The latest Git has a new experimental command &lt;a class="link" href="https://git-scm.com/docs/git-sparse-checkout" target="_blank" rel="noopener"
&gt;sparse-checkout&lt;/a&gt; that allows one to checkout only a subset of files, but I won&amp;rsquo;t recommend it as this post is purely about best practices and tips I myself find frequently useful to know.&lt;/p&gt;
&lt;h2 id="inspecting-git-history-and-comparing-revisions"&gt;&lt;a href="#inspecting-git-history-and-comparing-revisions" class="header-anchor"&gt;&lt;/a&gt;Inspecting Git history and comparing revisions
&lt;/h2&gt;&lt;p&gt;The best command to view the history of a single file is:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-3"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-3" style="display:none;"&gt;git log --oneline --follow path/to/filename.ext&lt;/code&gt;&lt;pre&gt;&lt;code&gt;git log --oneline --follow path/to/filename.ext&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The extra &lt;code&gt;--follow&lt;/code&gt; makes Git traverse the history longer to find if the same contents existed previously with a different file name, thus &lt;strong&gt;showing file contents across file renames&lt;/strong&gt;. Using &lt;code&gt;--oneline&lt;/code&gt; provides a nice short list of just the Git subject lines. To view the full Git commit messages as well as the actual changes, use this:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-4"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-4" style="display:none;"&gt;git log --patch --follow path/to/filename.ext&lt;/code&gt;&lt;pre&gt;&lt;code&gt;git log --patch --follow path/to/filename.ext&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If there is a specific change you are looking for, search it with &lt;code&gt;git log --patch -S &amp;lt;keyword&amp;gt;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To view the project history in general, having this alias is handy:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-5"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-5" style="display:none;"&gt;alias g-log=&amp;#34;git log --graph --format=&amp;#39;format:%C(yellow)%h%C(reset) %s %C(magenta)%cr%C(reset)%C(auto)%d%C(reset)&amp;#39;&amp;#34;&lt;/code&gt;&lt;pre&gt;&lt;code&gt;alias g-log=&amp;#34;git log --graph --format=&amp;#39;format:%C(yellow)%h%C(reset) %s %C(magenta)%cr%C(reset)%C(auto)%d%C(reset)&amp;#39;&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src="https://optimizedbyotto.com/post/advanced-git-commands/git-log-branches.png"
width="1253"
height="769"
srcset="https://optimizedbyotto.com/post/advanced-git-commands/git-log-branches_hu12940301691173766031.png 480w, https://optimizedbyotto.com/post/advanced-git-commands/git-log-branches_hu16415094831403011112.png 1024w, https://optimizedbyotto.com/post/advanced-git-commands/git-log-branches.png 1253w"
loading="lazy"
alt="Custom git log format with all branches"
class="gallery-image"
data-flex-grow="162"
data-flex-basis="391px"
&gt;
&lt;/p&gt;
&lt;p&gt;The output shows all references, multiple branches in parallel and it is nicely colorized. If the project has a lot of messy merges, sticking to one branch may be more readable:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-6"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-6" style="display:none;"&gt;git log --oneline --no-merges --first-parent&lt;/code&gt;&lt;pre&gt;&lt;code&gt;git log --oneline --no-merges --first-parent&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src="https://optimizedbyotto.com/post/advanced-git-commands/git-log-parent-branch-only.png"
width="1252"
height="774"
srcset="https://optimizedbyotto.com/post/advanced-git-commands/git-log-parent-branch-only_hu15579114208679559908.png 480w, https://optimizedbyotto.com/post/advanced-git-commands/git-log-parent-branch-only_hu13676921408714466298.png 1024w, https://optimizedbyotto.com/post/advanced-git-commands/git-log-parent-branch-only.png 1252w"
loading="lazy"
alt="Custom git log format with parent branches only"
class="gallery-image"
data-flex-grow="161"
data-flex-basis="388px"
&gt;
&lt;/p&gt;
&lt;p&gt;However, an even better option is to use &lt;code&gt;gitk --all &amp;amp;&lt;/code&gt;. This standard Git graphical user interface allows you to browse the history, search for changes with a specific string, jump to a specific commit to quickly inspect it and what preceded it, open a graphical Git blame in a new window, etc. The &lt;code&gt;--all&lt;/code&gt; instructs &lt;code&gt;gitk&lt;/code&gt; to show all branches and references, and the ampersand backgrounds the process so that your command-line prompt is freed to run other commands. If your workflow is based on working over SSH on a remote server, simply connect with &lt;code&gt;ssh -X remote.server.example&lt;/code&gt; to have X11 forwarding enabled (only works on Linux). Then on the SSH command-line just run &lt;code&gt;gitk --all &amp;amp;&lt;/code&gt; and a window should pop up.&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-7"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-7" style="display:none;"&gt;laptop$ ssh -X remote-server.example.com
server$ echo $DISPLAY
:0 (X11 forwarding is enabled and xauth running)
server$ cd path/to/git/repo
server$ gitk --all &amp;amp;&lt;/code&gt;&lt;pre&gt;&lt;code&gt;laptop$ ssh -X remote-server.example.com
server$ echo $DISPLAY
:0 (X11 forwarding is enabled and xauth running)
server$ cd path/to/git/repo
server$ gitk --all &amp;amp;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A typical need is also to compare the files and changes across multiple commits or branches using Git diff. The nicer graphical option to it is to run &lt;code&gt;git difftool --dir-diff branch1..branch2&lt;/code&gt; which will open the diff program of your choice. Personally I have opted to always use &lt;a class="link" href="https://meldmerge.org/" target="_blank" rel="noopener"
&gt;Meld&lt;/a&gt; with &lt;code&gt;git config diff.tool meld&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://optimizedbyotto.com/post/advanced-git-commands/git-difftool-meld.png"
width="1254"
height="778"
srcset="https://optimizedbyotto.com/post/advanced-git-commands/git-difftool-meld_hu11108748408415570093.png 480w, https://optimizedbyotto.com/post/advanced-git-commands/git-difftool-meld_hu6908882807784497843.png 1024w, https://optimizedbyotto.com/post/advanced-git-commands/git-difftool-meld.png 1254w"
loading="lazy"
alt="Demo of git difftool with Meld"
class="gallery-image"
data-flex-grow="161"
data-flex-basis="386px"
&gt;
&lt;/p&gt;
&lt;h2 id="committing-rebasing-cherry-picking-and-merging"&gt;&lt;a href="#committing-rebasing-cherry-picking-and-merging" class="header-anchor"&gt;&lt;/a&gt;Committing, rebasing, cherry-picking and merging
&lt;/h2&gt;&lt;p&gt;When making a Git commit, doing it graphically with &lt;code&gt;git citool&lt;/code&gt; helps to clearly see what changes have been made, and to select the files and even the exact lines to be committed with the click of a mouse. The tool also offers built-in spell-checking, and the text box is sized just right to visually enforce keeping line lengths within limits. Since development involves committing and amending commits all the time, I recommend having these aliases:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-8"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-8" style="display:none;"&gt;alias g-commit=&amp;#39;git citool &amp;amp;&amp;#39;
alias g-amend=&amp;#39;git citool --amend &amp;amp;&amp;#39;&lt;/code&gt;&lt;pre&gt;&lt;code&gt;alias g-commit=&amp;#39;git citool &amp;amp;&amp;#39;
alias g-amend=&amp;#39;git citool --amend &amp;amp;&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Personally, I practically never commit by simply running &lt;code&gt;git commit&lt;/code&gt;. If I commit from the command line at all, it is usually due to the need to do something special, such as change the author with:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-9"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-9" style="display:none;"&gt;git commit --amend --no-edit --author &amp;#34;Otto Kekäläinen &amp;lt;otto@debian.org&amp;gt;&amp;#34;&lt;/code&gt;&lt;pre&gt;&lt;code&gt;git commit --amend --no-edit --author &amp;#34;Otto Kekäläinen &amp;lt;otto@debian.org&amp;gt;&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Another case where a command-line commit fits my workflow well is during final testing before a code submission when I find a flaw on the branch I am working on. In these cases, I fix the code, and quickly issue:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-10"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-10" style="display:none;"&gt;git commit -a --fixup a1b2c3
git rebase -i --autosquash main&lt;/code&gt;&lt;pre&gt;&lt;code&gt;git commit -a --fixup a1b2c3
git rebase -i --autosquash main&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will commit the change, mark it as a fix for commit &lt;code&gt;a1b2c3&lt;/code&gt;, and then open the interactive rebase view &lt;strong&gt;with the fixup commit automatically placed at the right location&lt;/strong&gt;, resulting in a quick turnaround to make the branch flawless and ready for submission.&lt;/p&gt;
&lt;p&gt;Occasionally a Git commit needs to be applied to multiple branches. For example, after making a bugfix with the id &lt;code&gt;a1b2c3&lt;/code&gt; on the main branch, you might want to backport it to release branches 11.4 and 11.3 with:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-11"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-11" style="display:none;"&gt;git cherry-pick -x a1b2c3&lt;/code&gt;&lt;pre&gt;&lt;code&gt;git cherry-pick -x a1b2c3&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The extra -x will make Git amend the commit message with a reference to the commit id it originated from. In this case, it would state: &lt;code&gt;(cherry picked from commit a1b2c3)&lt;/code&gt;. This helps people reading the commit messages later to track down when and where the commit was first made.&lt;/p&gt;
&lt;p&gt;When doing merges, the most effective way to handle conflicts is by &lt;strong&gt;using Meld to graphically compare and resolve merges&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-12"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-12" style="display:none;"&gt;$ git merge branch2
Auto-merging VERSION
CONFLICT (content): Merge conflict in SOMEFILE
Automatic merge failed; fix conflicts and then commit the result.
$ git mergetool
Merging:
SOMEFILE
Normal merge conflict for &amp;#39;SOMEFILE&amp;#39;:
{local}: modified file
{remote}: modified file
$ git commit -a
[branch1 e4952e06] Merge branch &amp;#39;branch2&amp;#39; into branch1&lt;/code&gt;&lt;pre&gt;&lt;code&gt;$ git merge branch2
Auto-merging VERSION
CONFLICT (content): Merge conflict in SOMEFILE
Automatic merge failed; fix conflicts and then commit the result.
$ git mergetool
Merging:
SOMEFILE
Normal merge conflict for &amp;#39;SOMEFILE&amp;#39;:
{local}: modified file
{remote}: modified file
$ git commit -a
[branch1 e4952e06] Merge branch &amp;#39;branch2&amp;#39; into branch1&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src="https://optimizedbyotto.com/post/advanced-git-commands/git-mergetool-with-meld-demo.gif"
width="1246"
height="765"
loading="lazy"
alt="Demo of git mergetool with Meld"
class="gallery-image"
data-flex-grow="162"
data-flex-basis="390px"
&gt;
&lt;/p&gt;
&lt;p&gt;One more thing to remember is that if a merge or rebase fails, remember to run &lt;code&gt;git merge --abort&lt;/code&gt; or &lt;code&gt;git rebase --abort&lt;/code&gt; to stop it and get back to the normal state. Another typical need is to discard all temporary changes and get back to a clean state ready to do new commits. For that I recommend this alias:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-13"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-13" style="display:none;"&gt;alias g-clean=&amp;#39;git clean -fdx &amp;amp;&amp;amp; git reset --hard &amp;amp;&amp;amp; git submodule foreach --recursive git clean -fdx &amp;amp;&amp;amp; git submodule foreach --recursive git reset --hard&amp;#39;&lt;/code&gt;&lt;pre&gt;&lt;code&gt;alias g-clean=&amp;#39;git clean -fdx &amp;amp;&amp;amp; git reset --hard &amp;amp;&amp;amp; git submodule foreach --recursive git clean -fdx &amp;amp;&amp;amp; git submodule foreach --recursive git reset --hard&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will reset all modified files to their pristine state from the last commit, as well as delete all files that are not in version control but may be present in the project directory.&lt;/p&gt;
&lt;h2 id="managing-multiple-remotes-and-branches"&gt;&lt;a href="#managing-multiple-remotes-and-branches" class="header-anchor"&gt;&lt;/a&gt;Managing multiple remotes and branches
&lt;/h2&gt;&lt;p&gt;The most important tip for working with Git repositories is to remember at the start of every coding session to always run &lt;code&gt;git remote update&lt;/code&gt;. This will fetch all remotes and make sure you have all the latest Git commits made since the last time you worked with the repository.&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-14"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-14" style="display:none;"&gt;$ git remote update
Fetching origin
Fetching upstream
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 2), reused 3 (delta 2), pack-reused 0
Unpacking objects: 100% (3/3), 445 bytes | 55.00 KiB/s, done.
From https://github.com/eradman/entr
e2a6ab7..6fa963e master -&amp;gt; upstream/master&lt;/code&gt;&lt;pre&gt;&lt;code&gt;$ git remote update
Fetching origin
Fetching upstream
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 2), reused 3 (delta 2), pack-reused 0
Unpacking objects: 100% (3/3), 445 bytes | 55.00 KiB/s, done.
From https://github.com/eradman/entr
e2a6ab7..6fa963e master -&amp;gt; upstream/master&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the example above, you can see that there isn&amp;rsquo;t just the &lt;code&gt;origin&lt;/code&gt;, but also a second remote called &lt;code&gt;upstream&lt;/code&gt;. Most people use Git in a centralized model, meaning that there is one central main repository on e.g. GitHub or GitLab, and each developer in the project &lt;code&gt;pushes&lt;/code&gt; and &lt;code&gt;pulls&lt;/code&gt; that central repository. However, Git was designed from the start to be a distributed system that can sync with multiple remotes. To understand how to control this one needs to learn the concept of tracking branches and learn the options of the &lt;code&gt;git remote&lt;/code&gt; command.&lt;/p&gt;
&lt;p&gt;Consider this example that has two remotes, &lt;em&gt;origin&lt;/em&gt; and &lt;em&gt;upstream&lt;/em&gt;, and the &lt;em&gt;origin&lt;/em&gt; remote has 3 push urls:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-15"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-15" style="display:none;"&gt;$ git remote -v
origin git@salsa.debian.org:debian/entr.git (fetch)
origin git@salsa.debian.org:debian/entr.git (push)
origin git@gitlab.com:ottok/entr.git (push)
origin git@github.com:ottok/entr.git (push)
upstream https://github.com/eradman/entr (fetch)
upstream https://github.com/eradman/entr (push)
$ cat .git/config
[remote &amp;#34;origin&amp;#34;]
url = git@salsa.debian.org:debian/entr.git
fetch = &amp;#43;refs/heads/*:refs/remotes/origin/*
pushurl = git@salsa.debian.org:debian/entr.git
pushurl = git@gitlab.com:ottok/entr.git
pushurl = git@github.com:ottok/entr.git
[remote &amp;#34;upstream&amp;#34;]
url = https://github.com/eradman/entr
fetch = &amp;#43;refs/heads/*:refs/remotes/upstream/*
[branch &amp;#34;debian/latest&amp;#34;]
remote = origin
merge = refs/heads/debian/latest
[branch &amp;#34;master&amp;#34;]
remote = upstream
merge = refs/heads/master&lt;/code&gt;&lt;pre&gt;&lt;code&gt;$ git remote -v
origin git@salsa.debian.org:debian/entr.git (fetch)
origin git@salsa.debian.org:debian/entr.git (push)
origin git@gitlab.com:ottok/entr.git (push)
origin git@github.com:ottok/entr.git (push)
upstream https://github.com/eradman/entr (fetch)
upstream https://github.com/eradman/entr (push)
$ cat .git/config
[remote &amp;#34;origin&amp;#34;]
url = git@salsa.debian.org:debian/entr.git
fetch = &amp;#43;refs/heads/*:refs/remotes/origin/*
pushurl = git@salsa.debian.org:debian/entr.git
pushurl = git@gitlab.com:ottok/entr.git
pushurl = git@github.com:ottok/entr.git
[remote &amp;#34;upstream&amp;#34;]
url = https://github.com/eradman/entr
fetch = &amp;#43;refs/heads/*:refs/remotes/upstream/*
[branch &amp;#34;debian/latest&amp;#34;]
remote = origin
merge = refs/heads/debian/latest
[branch &amp;#34;master&amp;#34;]
remote = upstream
merge = refs/heads/master&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In this repository, the branch &lt;code&gt;master&lt;/code&gt; is configured to track the remote &lt;code&gt;upstream&lt;/code&gt;. Thus, if I am in the branch &lt;code&gt;master&lt;/code&gt; and run &lt;code&gt;git pull&lt;/code&gt; it will fetch &lt;code&gt;master&lt;/code&gt; from the upstream repository. I can then checkout the &lt;code&gt;debian/latest&lt;/code&gt; branch, merge on &lt;code&gt;upstream&lt;/code&gt; and do other changes. Eventually, when I am done and issue &lt;code&gt;git push&lt;/code&gt;, the changes on branch &lt;code&gt;debian/latest&lt;/code&gt; will go to remote &lt;code&gt;origin&lt;/code&gt; automatically. The &lt;code&gt;origin&lt;/code&gt; has 3 &lt;code&gt;pushurls&lt;/code&gt;, which means that the updated debian/latest will end up on both the Debian server as well as GitHub and GitLab.&lt;/p&gt;
&lt;p&gt;The commands to set this up were:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-16"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-16" style="display:none;"&gt;git clone git@salsa.debian.org:debian/entr.git
cd entr
git remote set-url --add --push origin git@salsa.debian.org:otto/entr.git
git remote set-url --add --push origin git@gitlab.com:ottok/entr.git
git remote set-url --add --push origin git@github.com:ottok/entr.git
git remote add upstream https://github.com/eradman/entr&lt;/code&gt;&lt;pre&gt;&lt;code&gt;git clone git@salsa.debian.org:debian/entr.git
cd entr
git remote set-url --add --push origin git@salsa.debian.org:otto/entr.git
git remote set-url --add --push origin git@gitlab.com:ottok/entr.git
git remote set-url --add --push origin git@github.com:ottok/entr.git
git remote add upstream https://github.com/eradman/entr&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="keeping-repositories-nice-and-tidy"&gt;&lt;a href="#keeping-repositories-nice-and-tidy" class="header-anchor"&gt;&lt;/a&gt;Keeping repositories nice and tidy
&lt;/h2&gt;&lt;p&gt;As most developers use feature and bug branches to make changes and submit them for review, a lot of old and unnecessary branches will start to pollute the Git history over time. Therefore it is good to check from time to time what branches have been merged with &lt;code&gt;git branch --merged&lt;/code&gt; and delete them.&lt;/p&gt;
&lt;p&gt;If a branch is deleted remotely as a result of somebody else doing cleanup, you can make Git automatically delete those branches for you locally as well with &lt;code&gt;git config --local fetch.prune true&lt;/code&gt;. You can run this one-off as well with &lt;code&gt;git fetch --prune --verbose --dry-run&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When working with multiple remotes, it might at times be hard to reason what will happen on a Git pull or Git push command. To see what tags and branches are updated and how without actually updating them run:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-17"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-17" style="display:none;"&gt;git fetch --verbose --dry-run
git push --verbose --dry-run
git push --tags --verbose --dry-run&lt;/code&gt;&lt;pre&gt;&lt;code&gt;git fetch --verbose --dry-run
git push --verbose --dry-run
git push --tags --verbose --dry-run&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Using the &lt;code&gt;--dry-run&lt;/code&gt; option is particularly important when running &lt;code&gt;push&lt;/code&gt; or &lt;code&gt;pull&lt;/code&gt; with &lt;code&gt;--prune&lt;/code&gt; or &lt;code&gt;--prune-tags&lt;/code&gt; to see which branches or tags would be deleted locally or on the remote.&lt;/p&gt;
&lt;p&gt;Another maintenance task to occasionally spend time on is to run this command to make Git delete all unreachable objects and to pack the ones that should be kept forever:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-18"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-18" style="display:none;"&gt;git prune --verbose --progress; git repack -ad; git gc --aggressive; git prune-packed&lt;/code&gt;&lt;pre&gt;&lt;code&gt;git prune --verbose --progress; git repack -ad; git gc --aggressive; git prune-packed&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To do this for every Git repository on your computer, you can run:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-19"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-19" style="display:none;"&gt;find ~ -name .git -type d | while read D
do
echo &amp;#34;===&amp;gt; $D: &amp;#34;
(cd &amp;#34;$D&amp;#34;; git prune --verbose --progress; nice -n 15 git repack -ad; nice -n 15 git gc --aggressive; git prune-packed)
done&lt;/code&gt;&lt;pre&gt;&lt;code&gt;find ~ -name .git -type d | while read D
do
echo &amp;#34;===&amp;gt; $D: &amp;#34;
(cd &amp;#34;$D&amp;#34;; git prune --verbose --progress; nice -n 15 git repack -ad; nice -n 15 git gc --aggressive; git prune-packed)
done&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="better-git-experience-with-liquip-prompt-and-fzf"&gt;&lt;a href="#better-git-experience-with-liquip-prompt-and-fzf" class="header-anchor"&gt;&lt;/a&gt;Better Git experience with Liquip Prompt and fzf
&lt;/h2&gt;&lt;p&gt;It is not practical to constantly run &lt;code&gt;git status&lt;/code&gt; (or &lt;code&gt;git status --ignored&lt;/code&gt;) or to press &lt;code&gt;F5&lt;/code&gt; in a &lt;code&gt;gitk&lt;/code&gt; window to be aware of the Git repository status. A much handier solution is to have the Git status integrated in the command-line prompt. My favorite is &lt;a class="link" href="https://linuxnatives.net/2020/liquid-prompt" target="_blank" rel="noopener"
&gt;Liquid Prompt&lt;/a&gt;, which shows the branch name, and displays green if everything is committed and clean, red if there are uncommitted changes, and yellow if changes are not pushed.&lt;/p&gt;
&lt;p&gt;Another additional tool I recommend is the &lt;a class="link" href="https://linuxnatives.net/2021/save-time-command-line-fuzzy-finder" target="_blank" rel="noopener"
&gt;Fuzzy Finder fzf&lt;/a&gt;. It has many uses in the command-line environment, and for Git this alias is handy for changing branches:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-20"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-20" style="display:none;"&gt;alias g-checkout=&amp;#34;git checkout &amp;#34;$(git branch --sort=-committerdate --no-merged | fzf)&amp;#34;&amp;#34;&lt;/code&gt;&lt;pre&gt;&lt;code&gt;alias g-checkout=&amp;#34;git checkout &amp;#34;$(git branch --sort=-committerdate --no-merged | fzf)&amp;#34;&amp;#34;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This will list all local branches with the recent ones topmost, and present the list in an interactive form using fzf so you can select the branch either using arrow keys, or typing a part of the branch name.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://optimizedbyotto.com/post/advanced-git-commands/liquid-prompt-fzf-git-demo.gif"
width="1246"
height="765"
loading="lazy"
alt="Demo of Liquid Prompt and git branch selection with Fuzzy Finder (fzf)"
class="gallery-image"
data-flex-grow="162"
data-flex-basis="390px"
&gt;
&lt;/p&gt;
&lt;h2 id="bash-aliases"&gt;&lt;a href="#bash-aliases" class="header-anchor"&gt;&lt;/a&gt;Bash aliases
&lt;/h2&gt;&lt;p&gt;While Git has its own alias system, I prefer to have everything in plain &lt;a class="link" href="https://en.wikipedia.org/wiki/Bash_%28Unix_shell%29" target="_blank" rel="noopener"
&gt;Bash aliases&lt;/a&gt; defined in my &lt;code&gt;.bashrc&lt;/code&gt;. Many of these are explained in this post, but there are a couple extra as well. I leave it up to the reader to study the &lt;a class="link" href="https://manpages.debian.org/unstable/git-man/git-push.1.en.html" target="_blank" rel="noopener"
&gt;Git man page&lt;/a&gt; to learn for example what &lt;code&gt;git push --force-with-lease&lt;/code&gt; does.&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-21"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-21" style="display:none;"&gt;alias g-log=&amp;#34;git log --graph --format=&amp;#39;format:%C(yellow)%h%C(reset) %s %C(magenta)%cr%C(reset)%C(auto)%d%C(reset)&amp;#39;&amp;#34;
alias g-history=&amp;#39;gitk --all &amp;amp;&amp;#39;
alias g-checkout=&amp;#39;git checkout $(git branch --sort=-committerdate --no-merged | fzf)&amp;#39;
alias g-commit=&amp;#39;git citool &amp;amp;&amp;#39;
alias g-amend=&amp;#39;git citool --amend &amp;amp;&amp;#39;
alias g-fixup=&amp;#39;git commit -a --fixup&amp;#39;
alias g-rebase=&amp;#39;git rebase --interactive --autosquash&amp;#39;
alias g-pull=&amp;#39;git pull --verbose --rebase&amp;#39;
alias g-pushf=&amp;#39;git push --verbose --force-with-lease&amp;#39;
alias g-status=&amp;#39;git status --ignored&amp;#39;
alias g-clean=&amp;#39;git clean -fdx &amp;amp;&amp;amp; git reset --hard &amp;amp;&amp;amp; git submodule foreach --recursive git clean -fdx &amp;amp;&amp;amp; git submodule foreach --recursive git reset --hard&amp;#39;&lt;/code&gt;&lt;pre&gt;&lt;code&gt;alias g-log=&amp;#34;git log --graph --format=&amp;#39;format:%C(yellow)%h%C(reset) %s %C(magenta)%cr%C(reset)%C(auto)%d%C(reset)&amp;#39;&amp;#34;
alias g-history=&amp;#39;gitk --all &amp;amp;&amp;#39;
alias g-checkout=&amp;#39;git checkout $(git branch --sort=-committerdate --no-merged | fzf)&amp;#39;
alias g-commit=&amp;#39;git citool &amp;amp;&amp;#39;
alias g-amend=&amp;#39;git citool --amend &amp;amp;&amp;#39;
alias g-fixup=&amp;#39;git commit -a --fixup&amp;#39;
alias g-rebase=&amp;#39;git rebase --interactive --autosquash&amp;#39;
alias g-pull=&amp;#39;git pull --verbose --rebase&amp;#39;
alias g-pushf=&amp;#39;git push --verbose --force-with-lease&amp;#39;
alias g-status=&amp;#39;git status --ignored&amp;#39;
alias g-clean=&amp;#39;git clean -fdx &amp;amp;&amp;amp; git reset --hard &amp;amp;&amp;amp; git submodule foreach --recursive git clean -fdx &amp;amp;&amp;amp; git submodule foreach --recursive git reset --hard&amp;#39;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="keep-on-learning"&gt;&lt;a href="#keep-on-learning" class="header-anchor"&gt;&lt;/a&gt;Keep on learning
&lt;/h2&gt;&lt;p&gt;As a programmer, it is not enough to know programming languages and how to write code well. You also need to understand the software lifecycle and change management. Understanding Git deeply helps you better prepare for situations where potentially hundreds of people collaborate on the same code base for years and years.&lt;/p&gt;
&lt;p&gt;To learn more about Git concepts, I recommend reading the entire &lt;a class="link" href="https://git-scm.com/book/en/v2" target="_blank" rel="noopener"
&gt;Pro Git book&lt;/a&gt;. The original version is over a decade old, but the online version keeps getting regular updates by people contributing to it in the open source spirit. As an example, I &lt;a class="link" href="https://github.com/progit/progit2/pull/1850" target="_blank" rel="noopener"
&gt;wrote&lt;/a&gt; a new section last year about &lt;a class="link" href="https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work#_everyone_must_sign" target="_blank" rel="noopener"
&gt;automatically signing Git commits&lt;/a&gt;. Skimming through the &lt;a class="link" href="https://git-scm.com/docs" target="_blank" rel="noopener"
&gt;Git reference documentation&lt;/a&gt; (online version of &lt;a class="link" href="https://en.wikipedia.org/wiki/Man_page" target="_blank" rel="noopener"
&gt;man pages&lt;/a&gt;) is also a great way to become aware of what capabilities Git offers.&lt;/p&gt;
&lt;p&gt;What is your favorite command-line Git trick or favorite tool? Comment below.&lt;/p&gt;</description>
    </item>
    <item>
      <title>How to make a good git commit</title>
      <link>https://optimizedbyotto.com/post/good-git-commit/</link>
      <pubDate>Sun, 26 Mar 2023 00:00:00 +0000</pubDate>
      <guid>https://optimizedbyotto.com/post/good-git-commit/</guid>
      <description>&lt;img src="https://optimizedbyotto.com/post/good-git-commit/git-citool-example.png" alt="Featured image of post How to make a good git commit" /&gt;&lt;p&gt;As a software developer, your core skill is how to improve an existing code base to make the software better iteratively, &lt;strong&gt;patch by patch&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;To be a good software developer you need to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;understand the concept of a code patch,&lt;/li&gt;
&lt;li&gt;know how to do code improvements in well sized and properly documented patches, and&lt;/li&gt;
&lt;li&gt;skillfully use &lt;a class="link" href="https://git-scm.com/" target="_blank" rel="noopener"
&gt;git version control software&lt;/a&gt; to manage patches.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="what-is-a-patch"&gt;&lt;a href="#what-is-a-patch" class="header-anchor"&gt;&lt;/a&gt;What is a patch?
&lt;/h2&gt;&lt;p&gt;A &lt;strong&gt;patch defines the changes&lt;/strong&gt; to be made to the code base. It is basically a list of code lines to be added, removed or modified in a code base. Each patch always also has an &lt;strong&gt;author&lt;/strong&gt;, a &lt;strong&gt;timestamp&lt;/strong&gt; when it was written, a &lt;strong&gt;title&lt;/strong&gt; that describes it and a longer text body that &lt;strong&gt;explains why&lt;/strong&gt; this particular patch is good and applying it on the code base is beneficial.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;patch&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-0"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-0" style="display:none;"&gt;Author: Otto Kekäläinen
Date: June 22nd, 2022 08:08:08
Make output friendlier for users
Add line break so text is readable and add a 2 second delay between
messages so it does not scroll too fast.
--- a/demo.c
&amp;#43;&amp;#43;&amp;#43; b/demo.c
@@ -8,7 &amp;#43;8,8 @@ int main()
{
for(;;)
{
- printf(&amp;#34;Hello world!&amp;#34;);
&amp;#43; printf(&amp;#34;Hello world!\n&amp;#34;);
&amp;#43; sleep(2);
}
return 0;
}&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-patch" data-lang="patch"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Author: Otto Kekäläinen
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Date: June 22nd, 2022 08:08:08
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Make output friendlier for users
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;Add line break so text is readable and add a 2 second delay between
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;messages so it does not scroll too fast.
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;--- a/demo.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;+++ b/demo.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;@@ -8,7 +8,8 @@ int main()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; for(;;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;- printf(&amp;#34;Hello world!&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;+ printf(&amp;#34;Hello world!\n&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;+ sleep(2);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; return 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="how-to-make-a-patch"&gt;&lt;a href="#how-to-make-a-patch" class="header-anchor"&gt;&lt;/a&gt;How to make a patch
&lt;/h2&gt;&lt;p&gt;You can make a patch by simply copying a file, changing something in it, and then comparing the copy to the original file using the &lt;a class="link" href="https://manpages.debian.org/unstable/diffutils/diff.1.en.html" target="_blank" rel="noopener"
&gt;command diff&lt;/a&gt; and saving the output.&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-1"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-1" style="display:none;"&gt;$ cp demo.c demo.c.orig
$ nano demo.c
$ diff -u demo.c.orig demo.c &amp;gt; demo.patch
$ cat demo.patch&lt;/code&gt;&lt;pre&gt;&lt;code&gt;$ cp demo.c demo.c.orig
$ nano demo.c
$ diff -u demo.c.orig demo.c &amp;gt; demo.patch
$ cat demo.patch&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;patch&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-2"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-2" style="display:none;"&gt;--- demo.c.orig
&amp;#43;&amp;#43;&amp;#43; demo.c
@@ -8,7 &amp;#43;8,8 @@ int main()
{
for(;;)
{
- printf(&amp;#34;Hello world!&amp;#34;);
&amp;#43; printf(&amp;#34;Hello world!\n&amp;#34;);
&amp;#43; sleep(2);
}
return 0;
}&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-patch" data-lang="patch"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;--- demo.c.orig
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;+++ demo.c
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&lt;/span&gt;&lt;span style="color:#75715e"&gt;@@ -8,7 +8,8 @@ int main()
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;&lt;/span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; for(;;)
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; {
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;- printf(&amp;#34;Hello world!&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;&lt;/span&gt;&lt;span style="color:#a6e22e"&gt;+ printf(&amp;#34;Hello world!\n&amp;#34;);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;+ sleep(2);
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#a6e22e"&gt;&lt;/span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; return 0;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; }
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The patch can be sent by email or uploaded somewhere. After that, anybody can download the patch, read it, and apply it to their copy of the code base using the &lt;a class="link" href="https://manpages.debian.org/unstable/patch/patch.1.en.html" target="_blank" rel="noopener"
&gt;command patch&lt;/a&gt;.&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-3"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-3" style="display:none;"&gt;$ grep Hello demo.c
printf(&amp;#34;Hello world!&amp;#34;);
$ curl -O https://…/demo.patch
$ patch -p0 &amp;lt; demo.patch
patching file demo.c
$ grep Hello demo.c
printf(&amp;#34;Hello world!\n&amp;#34;);&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ grep Hello demo.c
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Hello world!&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ curl -O https://…/demo.patch
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ patch -p0 &amp;lt; demo.patch
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;patching file demo.c
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ grep Hello demo.c
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; printf&lt;span style="color:#f92672"&gt;(&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#34;Hello world!\n&amp;#34;&lt;/span&gt;&lt;span style="color:#f92672"&gt;)&lt;/span&gt;;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;As this is not very fast nor convenient, software developers like to use git, a version control software that automates all of this. In git, we tend to talk about git &lt;strong&gt;commits&lt;/strong&gt;, which basically just means a &lt;strong&gt;patch that has been applied on a code base&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="examples-of-good-git-commit-messages"&gt;&lt;a href="#examples-of-good-git-commit-messages" class="header-anchor"&gt;&lt;/a&gt;Examples of good git commit messages
&lt;/h2&gt;&lt;p&gt;A good git commit message typically has these characteristics (adapted from the &lt;a class="link" href="https://git-scm.com/book/en/v2/Distributed-Git-Contributing-to-a-Project#_commit_guidelines" target="_blank" rel="noopener"
&gt;Git Pro book&lt;/a&gt;):&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-4"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-4" style="display:none;"&gt;Capitalized, short summary of what the change is
More detailed explanatory text that focuses on the &amp;#39;why&amp;#39; to motivate
the change. Use present tense and imperative format (write &amp;#34;Fix bug&amp;#34;,
not &amp;#34;Fixed bug&amp;#34;). Wrap it to about 72 characters or so. The blank line
separating the summary from the body is critical.
Further paragraphs come after blank lines.
- Bullet points are okay, too
- Typically a hyphen or asterisk is used for the bullet, followed by a
single space, with blank lines in between, but conventions vary here
- Use a hanging indent&lt;/code&gt;&lt;pre&gt;&lt;code&gt;Capitalized, short summary of what the change is
More detailed explanatory text that focuses on the &amp;#39;why&amp;#39; to motivate
the change. Use present tense and imperative format (write &amp;#34;Fix bug&amp;#34;,
not &amp;#34;Fixed bug&amp;#34;). Wrap it to about 72 characters or so. The blank line
separating the summary from the body is critical.
Further paragraphs come after blank lines.
- Bullet points are okay, too
- Typically a hyphen or asterisk is used for the bullet, followed by a
single space, with blank lines in between, but conventions vary here
- Use a hanging indent&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Here are a couple of real-world examples in pure text form:&lt;/p&gt;
&lt;p&gt;From &lt;a class="link" href="https://github.com/MariaDB/server/commit/ff1d8fa7b0fe473a6bacd23ac553e711b3a11032" target="_blank" rel="noopener"
&gt;MariaDB@ff1d8fa7&lt;/a&gt;:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-5"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-5" style="display:none;"&gt;Deb: Clean away Buster to Bookworm upgrade tests in Salsa-CI
Upgrades from Debian 10 &amp;#34;Buster&amp;#34; directly to Debian 12 &amp;#34;Bookworm&amp;#34;,
skipping Debian 11 &amp;#34;Bullseye&amp;#34;, fail with apt erroring on:
libcrypt.so.1: cannot open shared object file
This is an intentional OpenSSL transition as described in
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=993755&lt;/code&gt;&lt;pre&gt;&lt;code&gt;Deb: Clean away Buster to Bookworm upgrade tests in Salsa-CI
Upgrades from Debian 10 &amp;#34;Buster&amp;#34; directly to Debian 12 &amp;#34;Bookworm&amp;#34;,
skipping Debian 11 &amp;#34;Bullseye&amp;#34;, fail with apt erroring on:
libcrypt.so.1: cannot open shared object file
This is an intentional OpenSSL transition as described in
https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=993755&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;From &lt;a class="link" href="https://github.com/MariaDB/server/commit/2c5294142382469a9ad48c44979b7fcb7b146417" target="_blank" rel="noopener"
&gt;MariaDB@2c529441&lt;/a&gt;:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-6"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-6" style="display:none;"&gt;Deb: Run wrap-and-sort -av
Sort and organize the Debian packaging files.
Also revert 4d03269 that was done in vain.&lt;/code&gt;&lt;pre&gt;&lt;code&gt;Deb: Run wrap-and-sort -av
Sort and organize the Debian packaging files.
Also revert 4d03269 that was done in vain.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="five-requirements-for-a-good-git-commit"&gt;&lt;a href="#five-requirements-for-a-good-git-commit" class="header-anchor"&gt;&lt;/a&gt;Five requirements for a good git commit
&lt;/h2&gt;&lt;p&gt;In order of importance:&lt;/p&gt;
&lt;h3 id="1-commits-should-be-atomic"&gt;&lt;a href="#1-commits-should-be-atomic" class="header-anchor"&gt;&lt;/a&gt;1. Commits should be &lt;em&gt;atomic&lt;/em&gt;
&lt;/h3&gt;&lt;p&gt;The first and most important thing about &lt;strong&gt;a good patch or a commit&lt;/strong&gt; is that it &lt;strong&gt;should be a &lt;a class="link" href="https://git-scm.com/docs/gitworkflows#_separate_changes" target="_blank" rel="noopener"
&gt;self-standing change&lt;/a&gt;&lt;/strong&gt;. If a commit fixes a bug, it should not at the same time add a new feature or fix some other completely unrelated bug, otherwise it is not &lt;em&gt;atomic&lt;/em&gt;. If you add a new feature, the same commit should ideally also add automatic tests for the feature to ensure it won&amp;rsquo;t regress, and the same commit should update the documentation to mention the feature, as it is all related and should either go or not go into the code base along with the feature itself.&lt;/p&gt;
&lt;p&gt;If your changes are not properly scoped and self-standing, you might end up in a situation later on where somebody decides to revert or reject the commit that introduced a new feature, but miss removing the tests or documentation about it, which would not have happened if they were added in separate commits.&lt;/p&gt;
&lt;p&gt;There is no clear rule on what is the optimal scope for a commit; it is something you will learn by experience. Sometimes it makes sense to have several separate changes in one single commit simply because of each one of them being so small. In other cases, one single logical change might span multiple commits, because it was perhaps clearer to move or rename files in one commit and then update their commits in another. This is something you will just have to learn over time as you become a more experienced software developer.&lt;/p&gt;
&lt;h3 id="2-the-title-should-be-descriptive-yet-terse-and-not-too-long"&gt;&lt;a href="#2-the-title-should-be-descriptive-yet-terse-and-not-too-long" class="header-anchor"&gt;&lt;/a&gt;2. The title should be descriptive, yet terse and not too long
&lt;/h3&gt;&lt;p&gt;A title starts with a capital letter and has no trailing dot. Just like the subject line in an email. The title should make sense when read in a list of commits. If the title is too long, it will be cut off. A limit of 72 characters is safe to all typical places where people will be reading it, such as in a terminal window or when browsing GitHub or GitLab, but striving for under 50 characters is even better.&lt;/p&gt;
&lt;h3 id="3-the-commit-message-should-explain-why-it-was-made"&gt;&lt;a href="#3-the-commit-message-should-explain-why-it-was-made" class="header-anchor"&gt;&lt;/a&gt;3. The commit message should explain &lt;em&gt;why&lt;/em&gt; it was made
&lt;/h3&gt;&lt;p&gt;The text should be verbose enough for anybody reviewing the commit to understand &lt;strong&gt;why&lt;/strong&gt; it was made, and to be convinced that the change is good. Every commit must have a text body, even if it is very short. This forces the author to spend a few seconds thinking about the change before committing.&lt;/p&gt;
&lt;p&gt;Note that the commit message is about the change itself, so it should answer the question ‘why&amp;rsquo;. If you want to explain how a certain line of code works, simply use an inline comment next to the code itself. That way, the &lt;em&gt;documentation is in the correct context&lt;/em&gt;. &lt;strong&gt;The git commit description should have just a tiny bit of ‘what&amp;rsquo; and ‘how&amp;rsquo;, and mostly focus on the ‘why&amp;rsquo;.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The commit body should be wrapped at about 72 characters. Proper use of empty lines and lists that are indented with a dash or star makes the body more readable.&lt;/p&gt;
&lt;p&gt;Remember to use imperative format. Don&amp;rsquo;t write &lt;em&gt;Fixed bug&lt;/em&gt; or &lt;em&gt;Added feature&lt;/em&gt;. Instead write &lt;em&gt;Fix bug&lt;/em&gt; or &lt;em&gt;Add feature&lt;/em&gt;. The patch hasn&amp;rsquo;t added or fixed anything at the time you wrote it. Think about it like an order you give to the code base to start following. Also, try to keep your text in the current tense and passive format. Don&amp;rsquo;t write &lt;em&gt;This commit makes X&lt;/em&gt; but simply &lt;em&gt;Make X&lt;/em&gt;. Don&amp;rsquo;t write &lt;em&gt;I changed Y&lt;/em&gt; but just simply &lt;em&gt;Change Y&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id="4-use-references-when-available"&gt;&lt;a href="#4-use-references-when-available" class="header-anchor"&gt;&lt;/a&gt;4. Use references when available
&lt;/h3&gt;&lt;p&gt;If your code change is related to a previous commit, mention the commit ID. In most software commits, IDs will automatically become links. If the code change is related to something that was discussed or tracked elsewhere, please include the bug tracker ID or a URL to the discussion. However, the reference alone does not remove the need to write a git commit message. You cannot expect that somebody reading your commit has time or even access to open and read all references - use them only as pointers for more information.&lt;/p&gt;
&lt;p&gt;Viewing one of the earlier git commit message examples in &lt;a class="link" href="https://git-scm.com/docs/gitk" target="_blank" rel="noopener"
&gt;gitk&lt;/a&gt;, &lt;a class="link" href="https://gitlab.com/ottok/mariadb/-/commit/2c5294142382469a9ad48c44979b7fcb7b146417" target="_blank" rel="noopener"
&gt;GitLab&lt;/a&gt; and &lt;a class="link" href="https://github.com/MariaDB/server/commit/ff1d8fa7b0fe473a6bacd23ac553e711b3a11032" target="_blank" rel="noopener"
&gt;GitHub&lt;/a&gt; illustrates how a git commit automatically becomes a link:&lt;/p&gt;
&lt;p&gt;&lt;img src="https://optimizedbyotto.com/post/good-git-commit/good-git-commit-gitk-gitlab-github.png"
width="1440"
height="424"
srcset="https://optimizedbyotto.com/post/good-git-commit/good-git-commit-gitk-gitlab-github_hu15316212958483157633.png 480w, https://optimizedbyotto.com/post/good-git-commit/good-git-commit-gitk-gitlab-github_hu17365610380609069757.png 1024w, https://optimizedbyotto.com/post/good-git-commit/good-git-commit-gitk-gitlab-github.png 1440w"
loading="lazy"
alt="Same commit in gitk, GitLab and GitHub"
class="gallery-image"
data-flex-grow="339"
data-flex-basis="815px"
&gt;
&lt;/p&gt;
&lt;h3 id="5-maintain-correct-authorship-and-copyright-credits"&gt;&lt;a href="#5-maintain-correct-authorship-and-copyright-credits" class="header-anchor"&gt;&lt;/a&gt;5. Maintain correct authorship and copyright credits
&lt;/h3&gt;&lt;p&gt;The author name and timestamp are automatic if you configure your git correctly, so this should be a non-issue. If you neglect to configure git with your real name and email, you will be muddling the waters for anybody who later wants to verify something about authorship. In the worst case scenario, all your commits might be purged from the git repository due to unclear copyright.&lt;/p&gt;
&lt;p&gt;Also keep in mind that if you commit code on behalf of somebody else, you must tell git that the author for a particular commit was somebody else and you only committed it. Read up on &lt;a class="link" href="https://git-scm.com/docs/git-commit#Documentation/git-commit.txt---authorltauthorgt" target="_blank" rel="noopener"
&gt;git commit &amp;ndash;author&lt;/a&gt; for details.&lt;/p&gt;
&lt;h2 id="the-right-tools-make-git-commits-easy"&gt;&lt;a href="#the-right-tools-make-git-commits-easy" class="header-anchor"&gt;&lt;/a&gt;The right tools make git commits easy
&lt;/h2&gt;&lt;p&gt;Using a good tool to craft your git commits goes a long way in making the commit flawless.&lt;/p&gt;
&lt;p&gt;My personal choice is &lt;a class="link" href="https://github.com/prati0100/git-gui/" target="_blank" rel="noopener"
&gt;git-citool&lt;/a&gt;, which is distributed together with git itself, so anybody can use it on any operating system. It does not use the native graphics of each operating system, but a cross-platform graphics library, which may look a bit ugly. It is, however, very easy and convenient to use, so I love it.&lt;/p&gt;
&lt;p&gt;To make a new commit, simply run &lt;code&gt;git citool&lt;/code&gt;. It starts off empty and then you can select which files you want to stage, and write the git commit message in this box, and press commit. Super easy, and it is very clear what changes you are committing.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://optimizedbyotto.com/post/good-git-commit/git-citool-example.png"
width="1317"
height="617"
srcset="https://optimizedbyotto.com/post/good-git-commit/git-citool-example_hu15856864830268359891.png 480w, https://optimizedbyotto.com/post/good-git-commit/git-citool-example_hu18299217684725536277.png 1024w, https://optimizedbyotto.com/post/good-git-commit/git-citool-example.png 1317w"
loading="lazy"
alt="git citool example"
class="gallery-image"
data-flex-grow="213"
data-flex-basis="512px"
&gt;
&lt;/p&gt;
&lt;h2 id="dont-settle-for-bad-commits---amend-them"&gt;&lt;a href="#dont-settle-for-bad-commits---amend-them" class="header-anchor"&gt;&lt;/a&gt;Don&amp;rsquo;t settle for bad commits - amend them
&lt;/h2&gt;&lt;p&gt;If you are not happy with your commit and want to edit it, or to use git terminology you want to &amp;ldquo;amend&amp;rdquo;, this is possible only for the topmost git commit that does not have any child commits yet. Run &lt;code&gt;git-citool --amend&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here you can see a git commit that is really bad, so it really needs to be fixed. However, with git-citool it is easy and fast.&lt;/p&gt;
&lt;h2 id="wip-commits-how-to-avoid-postponing-writing-the-perfect-git-commit-message"&gt;&lt;a href="#wip-commits-how-to-avoid-postponing-writing-the-perfect-git-commit-message" class="header-anchor"&gt;&lt;/a&gt;WIP commits: how to avoid postponing writing the perfect git commit message
&lt;/h2&gt;&lt;p&gt;Remember that you don&amp;rsquo;t have to make a perfect git commit right off the bat. Do it only once you know what you actually want to write in it. While still working on the code and saving intermediate versions of it, I recommend using WIP commits where the title is simply &lt;em&gt;WIP&lt;/em&gt;, or if you already have some commit text draft, prefix the title with &lt;em&gt;WIP:&lt;/em&gt;.&lt;/p&gt;
&lt;h3 id="use-git-rebase--i-frequently"&gt;&lt;a href="#use-git-rebase--i-frequently" class="header-anchor"&gt;&lt;/a&gt;Use &lt;code&gt;git rebase -i&lt;/code&gt; frequently
&lt;/h3&gt;&lt;p&gt;When you are done with WIP commits, you can run &lt;a class="link" href="https://git-scm.com/docs/git-rebase" target="_blank" rel="noopener"
&gt;git rebase -i&lt;/a&gt; to squash them together and write the final git commit message.&lt;/p&gt;
&lt;p&gt;For a visual explanation see the presentation &lt;a class="link" href="https://www.youtube.com/watch?v=1NoNTqank_U&amp;amp;t=76s" target="_blank" rel="noopener"
&gt;A Branch in Time (a story about revision histories)&lt;/a&gt; by Tekin Süleyman on how to use interactive rebase in git and why rebasing and amending commits will end up making the code quality better in the long run.&lt;/p&gt;
&lt;div class="video-wrapper"&gt;
&lt;iframe loading="lazy"
src="https://www.youtube.com/embed/1NoNTqank_U?start=76"
allowfullscreen
title="YouTube Video"
&gt;
&lt;/iframe&gt;
&lt;/div&gt;
&lt;h2 id="a-polished-git-commit-is-always-worth-the-effort"&gt;&lt;a href="#a-polished-git-commit-is-always-worth-the-effort" class="header-anchor"&gt;&lt;/a&gt;A polished git commit is always worth the effort
&lt;/h2&gt;&lt;p&gt;Someone who is lazy might say that while they agree with the principles, they don&amp;rsquo;t have time to follow them. To that I respond that &lt;strong&gt;doing things correctly from the onset actually saves time down the road&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;If your git commits are good, the job of the reviewer will be much easier.&lt;/strong&gt; They won&amp;rsquo;t waste time on just trying to understand your change, but they will get it directly and will be able to focus their energy on actually reviewing and spotting flaws in your code. If you avoid shipping a bug, you save a lot of work not having to debug, write a fix and ship a new release.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A great git commit is also useful even if it later turns out the commit had a bug&lt;/strong&gt;, because whoever fixes that bug will have a much easier time reading in the commit what the change was supposed to do, and understanding where it fell short, and then making the same change in the correct way. This leads to bugs being fixed much more quickly and with less effort - and most often the person doing the fix is a future you who no longer remembers what the present you was thinking while making that commit, with the future you just having to stare at the commit until it makes sense.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;You don&amp;rsquo;t have to rewrite anything when it comes time to submit the commit for review&lt;/strong&gt;. Every single code review system I have ever used will automatically use the commit title and message as the review title and message if the review is a single commit review.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id="now-go-and-build-great-software--patch-by-patch"&gt;&lt;a href="#now-go-and-build-great-software--patch-by-patch" class="header-anchor"&gt;&lt;/a&gt;Now go and build great software – patch by patch!
&lt;/h2&gt;&lt;p&gt;Now you know how to make a good git commit message. If you are proud of your work and like doing things well, you will follow these guidelines. To further learn how to polish your git commit messages, see also the post on &lt;a class="link" href="https://optimizedbyotto.com/post/git-commit-message-examples/" &gt;git commit messages by example&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The Linux kernel developer&amp;rsquo;s guide has also an excellent description of &lt;a class="link" href="https://docs.kernel.org/process/submitting-patches.html#separate-your-changes" target="_blank" rel="noopener"
&gt;how to separate changes into self-standing logical changes&lt;/a&gt;, and &lt;a class="link" href="https://docs.kernel.org/process/submitting-patches.html#describe-your-changes" target="_blank" rel="noopener"
&gt;how to describe the changes&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Quick builds and rebuilds of MariaDB using Docker</title>
      <link>https://optimizedbyotto.com/post/quick-builds-and-rebuilds-of-mariadb-with-docker/</link>
      <pubDate>Sun, 12 Mar 2023 00:00:00 +0000</pubDate>
      <guid>https://optimizedbyotto.com/post/quick-builds-and-rebuilds-of-mariadb-with-docker/</guid>
      <description>&lt;img src="https://optimizedbyotto.com/post/quick-builds-and-rebuilds-of-mariadb-with-docker/mariadb-server-atom-autosave-entr-demo.gif" alt="Featured image of post Quick builds and rebuilds of MariaDB using Docker" /&gt;&lt;p&gt;The MariaDB server has over 2 million lines of code. Downloading, compiling (and re-compiling), and running the test suite can potentially consume a lot of time away from actually making the code changes and being productive. Knowing a few simple shortcuts can help avoid wasting time.&lt;/p&gt;
&lt;p&gt;While the official build instructions on &lt;a class="link" href="https://mariadb.org/get-involved/getting-started-for-developers/get-code-build-test/" target="_blank" rel="noopener"
&gt;mariadb.org&lt;/a&gt; and &lt;a class="link" href="https://mariadb.com/kb/en/generic-build-instructions/" target="_blank" rel="noopener"
&gt;mariadb.com/kb&lt;/a&gt; are useful to read, there are ways to make the build (and rebuild) significantly faster and more efficient.&lt;/p&gt;
&lt;blockquote&gt;
&lt;h2 id="tldr-for-debianubuntu-users"&gt;&lt;a href="#tldr-for-debianubuntu-users" class="header-anchor"&gt;&lt;/a&gt;TL;DR for Debian/Ubuntu users
&lt;/h2&gt;&lt;p&gt;Get the latest MariaDB 11.0 source code, install build dependencies, configure, build and run test suite to validate binaries work:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-0"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-0" style="display:none;"&gt;mkdir quick-rebuilds
cd quick-rebuilds
git clone --branch 11.0 --shallow-since=3m \
--recurse-submodules --shallow-submodules \
https://github.com/MariaDB/server.git mariadb-server
mkdir -p ccache build data
docker run --interactive --tty --rm -v ${PWD}:/quick-rebuilds \
-w /quick-rebuilds debian:sid bash
echo &amp;#39;deb-src http://deb.debian.org/debian sid main&amp;#39; \
&amp;gt; /etc/apt/sources.list.d/deb-src-sid.list
apt update
apt install -y --no-install-recommends \
devscripts equivs ccache eatmydata ninja-build clang entr moreutils
mk-build-deps -r -i mariadb-server/debian/control \
-t &amp;#39;apt-get -y -o Debug::pkgProblemResolver=yes --no-install-recommends&amp;#39;
export CCACHE_DIR=$PWD/ccache
export CXX=${CXX:-clang&amp;#43;&amp;#43;}
export CC=${CC:-clang}
export CXX_FOR_BUILD=${CXX_FOR_BUILD:-clang&amp;#43;&amp;#43;}
export CC_FOR_BUILD=${CC_FOR_BUILD:-clang}
export CFLAGS=&amp;#39;-Wno-unused-command-line-argument&amp;#39;
export CXXFLAGS=&amp;#39;-Wno-unused-command-line-argument&amp;#39;
cmake -S mariadb-server/ -B build/ -G Ninja --fresh \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DPLUGIN_COLUMNSTORE=NO -DPLUGIN_ROCKSDB=NO -DPLUGIN_S3=NO \
-DPLUGIN_MROONGA=NO -DPLUGIN_CONNECT=NO -DPLUGIN_TOKUDB=NO \
-DPLUGIN_PERFSCHEMA=NO -DWITH_WSREP=OFF
eatmydata cmake --build build/
./build/mysql-test/mysql-test-run.pl --force --parallel=auto&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir quick-rebuilds
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd quick-rebuilds
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;git clone --branch 11.0 --shallow-since&lt;span style="color:#f92672"&gt;=&lt;/span&gt;3m &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; --recurse-submodules --shallow-submodules &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; https://github.com/MariaDB/server.git mariadb-server
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir -p ccache build data
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker run --interactive --tty --rm -v &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;PWD&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;:/quick-rebuilds &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; -w /quick-rebuilds debian:sid bash
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#39;deb-src http://deb.debian.org/debian sid main&amp;#39;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; &amp;gt; /etc/apt/sources.list.d/deb-src-sid.list
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;apt install -y --no-install-recommends &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; devscripts equivs ccache eatmydata ninja-build clang entr moreutils
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mk-build-deps -r -i mariadb-server/debian/control &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; -t &lt;span style="color:#e6db74"&gt;&amp;#39;apt-get -y -o Debug::pkgProblemResolver=yes --no-install-recommends&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export CCACHE_DIR&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$PWD/ccache
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export CXX&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;CXX&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;clang++&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export CC&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;CC&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;clang&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export CXX_FOR_BUILD&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;CXX_FOR_BUILD&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;clang++&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export CC_FOR_BUILD&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;CC_FOR_BUILD&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;clang&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export CFLAGS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;-Wno-unused-command-line-argument&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export CXXFLAGS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;-Wno-unused-command-line-argument&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cmake -S mariadb-server/ -B build/ -G Ninja --fresh &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; -DCMAKE_CXX_COMPILER_LAUNCHER&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ccache -DCMAKE_C_COMPILER_LAUNCHER&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ccache &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; -DPLUGIN_COLUMNSTORE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;NO -DPLUGIN_ROCKSDB&lt;span style="color:#f92672"&gt;=&lt;/span&gt;NO -DPLUGIN_S3&lt;span style="color:#f92672"&gt;=&lt;/span&gt;NO &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; -DPLUGIN_MROONGA&lt;span style="color:#f92672"&gt;=&lt;/span&gt;NO -DPLUGIN_CONNECT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;NO -DPLUGIN_TOKUDB&lt;span style="color:#f92672"&gt;=&lt;/span&gt;NO &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; -DPLUGIN_PERFSCHEMA&lt;span style="color:#f92672"&gt;=&lt;/span&gt;NO -DWITH_WSREP&lt;span style="color:#f92672"&gt;=&lt;/span&gt;OFF
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;eatmydata cmake --build build/
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./build/mysql-test/mysql-test-run.pl --force --parallel&lt;span style="color:#f92672"&gt;=&lt;/span&gt;auto&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To rebuild after code change simply run:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-1"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-1" style="display:none;"&gt;eatmydata cmake --build build/&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;eatmydata cmake --build build/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;For full details, read the whole article.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="stay-organized-keep-directories-clean"&gt;&lt;a href="#stay-organized-keep-directories-clean" class="header-anchor"&gt;&lt;/a&gt;Stay organized, keep directories clean
&lt;/h2&gt;&lt;p&gt;The first step is to create the working directory and some directories inside it to:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-2"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-2" style="display:none;"&gt;mkdir quick-rebuilds
cd quick-rebuilds
mkdir -p ccache build data&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir quick-rebuilds
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cd quick-rebuilds
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mkdir -p ccache build data&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The directory &lt;code&gt;ccache&lt;/code&gt; will be used by the tool with the same name to store build cache permanently. Build artifacts will be output in the directory &lt;code&gt;build&lt;/code&gt; to avoid polluting the source code directory so that Git in the source tree will not accidentally commit any machine-generated files. The &lt;code&gt;data&lt;/code&gt; directory is useful for temporary test installs.&lt;/p&gt;
&lt;p&gt;The next step is to get the source code into this working directory.&lt;/p&gt;
&lt;h2 id="dont-download-the-whole-project--use-shallow-git-clone"&gt;&lt;a href="#dont-download-the-whole-project--use-shallow-git-clone" class="header-anchor"&gt;&lt;/a&gt;Don&amp;rsquo;t download the whole project – use shallow Git clone
&lt;/h2&gt;&lt;p&gt;The oldest Git commit in the project is from &lt;a class="link" href="https://github.com/MariaDB/server/commit/7eec25e393727b16bb916b50d82b0aa3084e065c" target="_blank" rel="noopener"
&gt;July, 2000&lt;/a&gt;. Since then, MariaDB has had nearly 200 000 commits. To build the latest version and perhaps submit a Pull Request to commit your improvement to the project, you don&amp;rsquo;t necessarily need to have all those 200 000 commits available in your Git clone. You can use &lt;a class="link" href="https://git-scm.com/docs/shallow" target="_blank" rel="noopener"
&gt;shallow Git clone&lt;/a&gt; to, for example, fetch only the history of the past 3 months:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-3"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-3" style="display:none;"&gt;$ git clone --branch 11.0 --shallow-since=3m \
--recurse-submodules --shallow-submodules \
https://github.com/MariaDB/server.git mariadb-server
Cloning into &amp;#39;mariadb-server&amp;#39;...
remote: Enumerating objects: 41075, done.
remote: Counting objects: 100% (41075/41075), done.
remote: Compressing objects: 100% (29333/29333), done.
remote: Total 41075 (delta 19706), reused 20092 (delta 10708), pack-reused 0
Receiving objects: 100% (41075/41075), 75.85 MiB | 8.48 MiB/s, done.
Resolving deltas: 100% (19706/19706), done.
Checking out files: 100% (24070/24070), done.
Submodule &amp;#39;extra/wolfssl/wolfssl&amp;#39; (https://github.com/wolfSSL/wolfssl.git) registered for path &amp;#39;extra/wolfssl/wolfssl&amp;#39;
Submodule &amp;#39;libmariadb&amp;#39; (https://github.com/MariaDB/mariadb-connector-c.git) registered for path &amp;#39;libmariadb&amp;#39;
Submodule &amp;#39;storage/columnstore/columnstore&amp;#39; (https://github.com/mariadb-corporation/mariadb-columnstore-engine.git) registered for path &amp;#39;storage/columnstore/columnstore&amp;#39;
Submodule &amp;#39;storage/maria/libmarias3&amp;#39; (https://github.com/mariadb-corporation/libmarias3.git) registered for path &amp;#39;storage/maria/libmarias3&amp;#39;
Submodule &amp;#39;storage/rocksdb/rocksdb&amp;#39; (https://github.com/facebook/rocksdb.git) registered for path &amp;#39;storage/rocksdb/rocksdb&amp;#39;
Submodule &amp;#39;wsrep-lib&amp;#39; (https://github.com/codership/wsrep-lib.git) registered for path &amp;#39;wsrep-lib&amp;#39;
Cloning into &amp;#39;/srv/sources/mariadb/quick-rebuilds/mariadb-server/extra/wolfssl/wolfssl&amp;#39;...
remote: Enumerating objects: 2851, done.
remote: Counting objects: 100% (2851/2851), done.
remote: Compressing objects: 100% (2124/2124), done.
remote: Total 2851 (delta 800), reused 1576 (delta 589), pack-reused 0
Receiving objects: 100% (2851/2851), 20.91 MiB | 10.43 MiB/s, done.
Resolving deltas: 100% (800/800), done.
...
Unpacking objects: 100% (3/3), done.
From https://github.com/codership/wsrep-API
* branch 694d6ca47f5eec7873be99b7d6babccf633d1231 -&amp;gt; FETCH_HEAD
Submodule path &amp;#39;wsrep-lib/wsrep-API/v26&amp;#39;: checked out &amp;#39;694d6ca47f5eec7873be99b7d6babccf633d1231&amp;#39;
$ git -C mariadb-server/ show --oneline --summary
f2dc4d4c (HEAD -&amp;gt; 11.0, origin/HEAD, origin/11.0) MDEV-30673 InnoDB recovery hangs when buf_LRU_get_free_block
$ git -C mariadb-server submodule
4fbd4fd36a21efd9d1a7e17aba390e91c78693b1 extra/wolfssl/wolfssl (4fbd4fd)
12bd1d5511fc2ff766ff6256c71b79a95739533f libmariadb (12bd1d5)
8b032853b7a200d9af4d468ac58bb9f4b6ac7040 storage/columnstore/columnstore (8b03285)
3846890513df0653b8919bc45a7600f9b55cab31 storage/maria/libmarias3 (3846890)
bba5e7bc21093d7cfa765e1280a7c4fdcd284288 storage/rocksdb/rocksdb (bba5e7b)
275a0af8c5b92f0ee33cfe9e23f3db5f59b56e9d wsrep-lib (275a0af)
$ du -shc mariadb-server/.git/modules/{storage/*,extra/wolfssl,libmariadb,wsrep-lib} \
mariadb-server/.git mariadb-server/
30M mariadb-server/.git/modules/storage/columnstore
1M mariadb-server/.git/modules/storage/maria
20M mariadb-server/.git/modules/storage/rocksdb
40M mariadb-server/.git/modules/extra/wolfssl
2M mariadb-server/.git/modules/libmariadb
1M mariadb-server/.git/modules/wsrep-lib
80M mariadb-server/.git
548M mariadb-server/
=720M total&lt;/code&gt;&lt;pre&gt;&lt;code&gt;$ git clone --branch 11.0 --shallow-since=3m \
--recurse-submodules --shallow-submodules \
https://github.com/MariaDB/server.git mariadb-server
Cloning into &amp;#39;mariadb-server&amp;#39;...
remote: Enumerating objects: 41075, done.
remote: Counting objects: 100% (41075/41075), done.
remote: Compressing objects: 100% (29333/29333), done.
remote: Total 41075 (delta 19706), reused 20092 (delta 10708), pack-reused 0
Receiving objects: 100% (41075/41075), 75.85 MiB | 8.48 MiB/s, done.
Resolving deltas: 100% (19706/19706), done.
Checking out files: 100% (24070/24070), done.
Submodule &amp;#39;extra/wolfssl/wolfssl&amp;#39; (https://github.com/wolfSSL/wolfssl.git) registered for path &amp;#39;extra/wolfssl/wolfssl&amp;#39;
Submodule &amp;#39;libmariadb&amp;#39; (https://github.com/MariaDB/mariadb-connector-c.git) registered for path &amp;#39;libmariadb&amp;#39;
Submodule &amp;#39;storage/columnstore/columnstore&amp;#39; (https://github.com/mariadb-corporation/mariadb-columnstore-engine.git) registered for path &amp;#39;storage/columnstore/columnstore&amp;#39;
Submodule &amp;#39;storage/maria/libmarias3&amp;#39; (https://github.com/mariadb-corporation/libmarias3.git) registered for path &amp;#39;storage/maria/libmarias3&amp;#39;
Submodule &amp;#39;storage/rocksdb/rocksdb&amp;#39; (https://github.com/facebook/rocksdb.git) registered for path &amp;#39;storage/rocksdb/rocksdb&amp;#39;
Submodule &amp;#39;wsrep-lib&amp;#39; (https://github.com/codership/wsrep-lib.git) registered for path &amp;#39;wsrep-lib&amp;#39;
Cloning into &amp;#39;/srv/sources/mariadb/quick-rebuilds/mariadb-server/extra/wolfssl/wolfssl&amp;#39;...
remote: Enumerating objects: 2851, done.
remote: Counting objects: 100% (2851/2851), done.
remote: Compressing objects: 100% (2124/2124), done.
remote: Total 2851 (delta 800), reused 1576 (delta 589), pack-reused 0
Receiving objects: 100% (2851/2851), 20.91 MiB | 10.43 MiB/s, done.
Resolving deltas: 100% (800/800), done.
...
Unpacking objects: 100% (3/3), done.
From https://github.com/codership/wsrep-API
* branch 694d6ca47f5eec7873be99b7d6babccf633d1231 -&amp;gt; FETCH_HEAD
Submodule path &amp;#39;wsrep-lib/wsrep-API/v26&amp;#39;: checked out &amp;#39;694d6ca47f5eec7873be99b7d6babccf633d1231&amp;#39;
$ git -C mariadb-server/ show --oneline --summary
f2dc4d4c (HEAD -&amp;gt; 11.0, origin/HEAD, origin/11.0) MDEV-30673 InnoDB recovery hangs when buf_LRU_get_free_block
$ git -C mariadb-server submodule
4fbd4fd36a21efd9d1a7e17aba390e91c78693b1 extra/wolfssl/wolfssl (4fbd4fd)
12bd1d5511fc2ff766ff6256c71b79a95739533f libmariadb (12bd1d5)
8b032853b7a200d9af4d468ac58bb9f4b6ac7040 storage/columnstore/columnstore (8b03285)
3846890513df0653b8919bc45a7600f9b55cab31 storage/maria/libmarias3 (3846890)
bba5e7bc21093d7cfa765e1280a7c4fdcd284288 storage/rocksdb/rocksdb (bba5e7b)
275a0af8c5b92f0ee33cfe9e23f3db5f59b56e9d wsrep-lib (275a0af)
$ du -shc mariadb-server/.git/modules/{storage/*,extra/wolfssl,libmariadb,wsrep-lib} \
mariadb-server/.git mariadb-server/
30M mariadb-server/.git/modules/storage/columnstore
1M mariadb-server/.git/modules/storage/maria
20M mariadb-server/.git/modules/storage/rocksdb
40M mariadb-server/.git/modules/extra/wolfssl
2M mariadb-server/.git/modules/libmariadb
1M mariadb-server/.git/modules/wsrep-lib
80M mariadb-server/.git
548M mariadb-server/
=720M total&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;With a 3-month history, the main Git data for MariaDB is about 50 MB, and the submodules as shallow clones add 30 MB more. If not using shallow cloning, the whole MariaDB repository and submodules would amount to over 1 GB of data, so using shallow clones cuts the amount of data to be downloaded by over 80%.&lt;/p&gt;
&lt;p&gt;The checked out data is almost 550 MB, but that is unpacked from the Git data, so actual network transfer was at max 80 MB of Git data.&lt;/p&gt;
&lt;h2 id="build-inside-a-throwaway-container"&gt;&lt;a href="#build-inside-a-throwaway-container" class="header-anchor"&gt;&lt;/a&gt;Build inside a throwaway container
&lt;/h2&gt;&lt;p&gt;In addition to the source code, one also needs a long list of build dependencies installed. Instead of polluting your laptop/workstation with tens of new libraries, install all the dependencies inside a container that has a working directory mounted inside it. This way your system will stay clean, but files written in the working directory will be accessible both inside and outside the container and persist after the container is gone.&lt;/p&gt;
&lt;p&gt;Next, start the container:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-4"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-4" style="display:none;"&gt;docker run --interactive --tty --rm \
-v ${PWD}:/quick-rebuilds -w /quick-rebuilds debian:sid bash&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker run --interactive --tty --rm &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; -v &lt;span style="color:#e6db74"&gt;${&lt;/span&gt;PWD&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;:/quick-rebuilds -w /quick-rebuilds debian:sid bash&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This example uses &lt;a class="link" href="https://en.wikipedia.org/wiki/Docker_%28software%29" target="_blank" rel="noopener"
&gt;Docker&lt;/a&gt;, but the principle is the same with &lt;a class="link" href="https://en.wikipedia.org/wiki/OS-level_virtualization#Implementations" target="_blank" rel="noopener"
&gt;any Linux container&lt;/a&gt; tool, such as Podman.&lt;/p&gt;
&lt;p&gt;Inside the Debian container, use apt to automatically install all dependencies (about 160 MB download, over 660 MB when unpacked to disk) as defined in MariaDB sources file &lt;code&gt;debian/control&lt;/code&gt;:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-5"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-5" style="display:none;"&gt;echo &amp;#39;deb-src http://deb.debian.org/debian sid main&amp;#39; \
&amp;gt; /etc/apt/sources.list.d/deb-src-sid.list
apt update
apt install -y --no-install-recommends \
devscripts equivs ccache eatmydata ninja-build clang entr moreutils
mk-build-deps -r -i mariadb-server/debian/control \
-t &amp;#39;apt-get -y -o Debug::pkgProblemResolver=yes --no-install-recommends&amp;#39;&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;echo &lt;span style="color:#e6db74"&gt;&amp;#39;deb-src http://deb.debian.org/debian sid main&amp;#39;&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; &amp;gt; /etc/apt/sources.list.d/deb-src-sid.list
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;apt install -y --no-install-recommends &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; devscripts equivs ccache eatmydata ninja-build clang entr moreutils
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mk-build-deps -r -i mariadb-server/debian/control &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; -t &lt;span style="color:#e6db74"&gt;&amp;#39;apt-get -y -o Debug::pkgProblemResolver=yes --no-install-recommends&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The single biggest boost to the (re-)compilation speed is gained with &lt;a class="link" href="https://ccache.dev/" target="_blank" rel="noopener"
&gt;Ccache&lt;/a&gt;:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-6"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-6" style="display:none;"&gt;export CCACHE_DIR=$PWD/ccache
ccache --show-stats --verbose&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export CCACHE_DIR&lt;span style="color:#f92672"&gt;=&lt;/span&gt;$PWD/ccache
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;ccache --show-stats --verbose&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;We also want to prime the environment to use &lt;a class="link" href="https://clang.llvm.org/" target="_blank" rel="noopener"
&gt;Clang&lt;/a&gt;:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-7"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-7" style="display:none;"&gt;export CXX=${CXX:-clang&amp;#43;&amp;#43;}
export CC=${CC:-clang}
export CXX_FOR_BUILD=${CXX_FOR_BUILD:-clang&amp;#43;&amp;#43;}
export CC_FOR_BUILD=${CC_FOR_BUILD:-clang}
export CFLAGS=&amp;#39;-Wno-unused-command-line-argument&amp;#39;
export CXXFLAGS=&amp;#39;-Wno-unused-command-line-argument&amp;#39;&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export CXX&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;CXX&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;clang++&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export CC&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;CC&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;clang&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export CXX_FOR_BUILD&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;CXX_FOR_BUILD&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;clang++&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export CC_FOR_BUILD&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;${&lt;/span&gt;CC_FOR_BUILD&lt;span style="color:#66d9ef"&gt;:-&lt;/span&gt;clang&lt;span style="color:#e6db74"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export CFLAGS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;-Wno-unused-command-line-argument&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export CXXFLAGS&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#e6db74"&gt;&amp;#39;-Wno-unused-command-line-argument&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The first step in actual compilation is to run &lt;a class="link" href="https://manpages.debian.org/unstable/cmake/cmake.1.en.html" target="_blank" rel="noopener"
&gt;CMake&lt;/a&gt;, instructing it to look at the source in directory &lt;code&gt;mariadb-server/&lt;/code&gt;, output build artifacts in directory &lt;code&gt;build/&lt;/code&gt; and use &lt;a class="link" href="https://ninja-build.org/" target="_blank" rel="noopener"
&gt;Ninja&lt;/a&gt; as the build system. This line also always forces a fresh configuration, discarding any previous CMakeCache.txt files, to use ccache instead of calling gcc/c++ directly, and also skip a bunch of rarely used large plugins to save a lot of compilation time.&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-8"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-8" style="display:none;"&gt;cmake -S mariadb-server/ -B build/ -G Ninja --fresh \
-DCMAKE_CXX_COMPILER_LAUNCHER=ccache -DCMAKE_C_COMPILER_LAUNCHER=ccache \
-DPLUGIN_COLUMNSTORE=NO -DPLUGIN_ROCKSDB=NO -DPLUGIN_S3=NO \
-DPLUGIN_MROONGA=NO -DPLUGIN_CONNECT=NO -DPLUGIN_TOKUDB=NO \
-DPLUGIN_PERFSCHEMA=NO -DWITH_WSREP=OFF&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cmake -S mariadb-server/ -B build/ -G Ninja --fresh &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; -DCMAKE_CXX_COMPILER_LAUNCHER&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ccache -DCMAKE_C_COMPILER_LAUNCHER&lt;span style="color:#f92672"&gt;=&lt;/span&gt;ccache &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; -DPLUGIN_COLUMNSTORE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;NO -DPLUGIN_ROCKSDB&lt;span style="color:#f92672"&gt;=&lt;/span&gt;NO -DPLUGIN_S3&lt;span style="color:#f92672"&gt;=&lt;/span&gt;NO &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; -DPLUGIN_MROONGA&lt;span style="color:#f92672"&gt;=&lt;/span&gt;NO -DPLUGIN_CONNECT&lt;span style="color:#f92672"&gt;=&lt;/span&gt;NO -DPLUGIN_TOKUDB&lt;span style="color:#f92672"&gt;=&lt;/span&gt;NO &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; -DPLUGIN_PERFSCHEMA&lt;span style="color:#f92672"&gt;=&lt;/span&gt;NO -DWITH_WSREP&lt;span style="color:#f92672"&gt;=&lt;/span&gt;OFF&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;If you are interested in knowing all possible build flags available, simply query them from CMake with:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-9"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-9" style="display:none;"&gt;cmake build/ -LH&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cmake build/ -LH&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Note that after the configure stage has run, there are no traditional Makefiles in &amp;lsquo;build/&amp;rsquo;, only a &lt;code&gt;ninja.build&lt;/code&gt; since we are using Ninja. Thus, running &lt;code&gt;make build&lt;/code&gt; will build. With Ninja it will be &lt;code&gt;ninja -C build&lt;/code&gt;. However, we don&amp;rsquo;t need to call Ninja directly either but just let CMake orchestrate everything with:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-10"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-10" style="display:none;"&gt;$ eatmydata cmake --build build/
[173/1462] Building C object plugin/auth_ed25519/CMakeFiles/ref10.dir/ref10/ge_add.c.o&lt;/code&gt;&lt;pre&gt;&lt;code&gt;$ eatmydata cmake --build build/
[173/1462] Building C object plugin/auth_ed25519/CMakeFiles/ref10.dir/ref10/ge_add.c.o&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In interactive mode, Ninja will have just one line of output at the time showing progress. The numbers inside the brackets show how many files have been compiled of the total number of files to compile, and the filename after it shows which file is currently being compiled. Ninja runs by default on all available CPU cores, so there is no need to define parallelism manually. If Ninja encounters warnings or errors, it will spit them out but continue to show the one-liner status at the bottom of the terminal. To abort Ninja, feel free to press &lt;code&gt;Ctrl+C&lt;/code&gt; at any time.&lt;/p&gt;
&lt;p&gt;Re-starting the compilation will continue where it left off – Ninja is very smart and fast in figuring out what files need to compiled.&lt;/p&gt;
&lt;h2 id="running-the-mariadb-test-suite-mtr"&gt;&lt;a href="#running-the-mariadb-test-suite-mtr" class="header-anchor"&gt;&lt;/a&gt;Running the MariaDB test suite (MTR)
&lt;/h2&gt;&lt;p&gt;While the MariaDB server does have a small amount of &lt;a class="link" href="https://cmake.org/cmake/help/book/mastering-cmake/chapter/Testing%20With%20CMake%20and%20CTest.html#testing-using-ctest" target="_blank" rel="noopener"
&gt;CTest unit tests&lt;/a&gt;, the main test system is the &lt;a class="link" href="https://mariadb.com/kb/en/mysql-test-runpl-options/" target="_blank" rel="noopener"
&gt;mariadb-test-run script&lt;/a&gt; (inherited from mysql-test-run). Each test file (suffix &lt;code&gt;.test&lt;/code&gt;) consists mainly of SQL code which is executed by &lt;code&gt;mariadb-test-run&lt;/code&gt; (MTR) and output compared to the corresponding file with the expected output in text format (suffix &lt;code&gt;.result&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;To start the MTR with CMake run:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-11"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-11" style="display:none;"&gt;cmake --build build/ -t test-force&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;cmake --build build/ -t test-force&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Alternatively, one can simply invoke the script directly after the binaries have been compiled:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-12"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-12" style="display:none;"&gt;./build/mysql-test/mysql-test-run.pl --force&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./build/mysql-test/mysql-test-run.pl --force&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This offers more flexibility, as you can easily add parameters such as &lt;code&gt;--parallel=auto&lt;/code&gt; (as the default is to run just one test worker on one CPU) or limit the scope to just one suite or just one individual test:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-13"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-13" style="display:none;"&gt;./build/mysql-test/mysql-test-run.pl --force --parallel=auto --skip-rpl --suite=main&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;./build/mysql-test/mysql-test-run.pl --force --parallel&lt;span style="color:#f92672"&gt;=&lt;/span&gt;auto --skip-rpl --suite&lt;span style="color:#f92672"&gt;=&lt;/span&gt;main&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Note that all commands in this example run as root, as it is necessary to start the whole container with a root user inside it to have permissions to apt install build dependencies. However, the mariadb-test-run is actually not designed to be run as root and will end up skipping some tests when run as root. Also, when run like this, a lot of the debugging information isn&amp;rsquo;t fully shown. To make most out of the mysql-test-run/mariadb-test-run script, read more in the post &lt;a class="link" href="https://optimizedbyotto.com/post/grokking-mariadb-test-run-mtr" &gt;Grokking the MariaDB test runner (MTR)&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="more-build-targets"&gt;&lt;a href="#more-build-targets" class="header-anchor"&gt;&lt;/a&gt;More build targets
&lt;/h2&gt;&lt;p&gt;As concluded above, the target &lt;code&gt;test-force&lt;/code&gt; was for MTR, and the plainly named target &lt;code&gt;test&lt;/code&gt; is for CUnit tests. The equivalent direct Ninja command for running target &lt;code&gt;test&lt;/code&gt; would be &lt;code&gt;ninja -C build/ test&lt;/code&gt;. To list all targets, run &lt;code&gt;cmake --build build/ --target help&lt;/code&gt; or &lt;code&gt;ninja -C build/ -t targets all&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;MariaDB 11.0 has currently over 1300 targets. There does not seem to be a very consistent pattern in how build targets are named or how they are intended to be used. One way to find CMake targets that might be more important than others is to simply grep them from the main level CMake configuration file:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-14"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-14" style="display:none;"&gt;$ grep ADD_CUSTOM_TARGET mariadb-server/CMakeLists.txt
ADD_CUSTOM_TARGET(import_executables
ADD_CUSTOM_TARGET(INFO_SRC ALL
ADD_CUSTOM_TARGET(INFO_BIN ALL
ADD_CUSTOM_TARGET(minbuild)
ADD_CUSTOM_TARGET(smoketest&lt;/code&gt;&lt;pre&gt;&lt;code&gt;$ grep ADD_CUSTOM_TARGET mariadb-server/CMakeLists.txt
ADD_CUSTOM_TARGET(import_executables
ADD_CUSTOM_TARGET(INFO_SRC ALL
ADD_CUSTOM_TARGET(INFO_BIN ALL
ADD_CUSTOM_TARGET(minbuild)
ADD_CUSTOM_TARGET(smoketest&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;One of the standard targets is &lt;code&gt;install&lt;/code&gt;, which can be run &lt;code&gt;ninja -C build install&lt;/code&gt; or CMake:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-15"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-15" style="display:none;"&gt;$ cmake --install build/
-- Install configuration: &amp;#34;RelWithDebInfo&amp;#34;
-- Up-to-date: /usr/local/mysql/./README.md
-- Up-to-date: /usr/local/mysql/./CREDITS
-- Up-to-date: /usr/local/mysql/./COPYING
-- Up-to-date: /usr/local/mysql/./THIRDPARTY
-- Up-to-date: /usr/local/mysql/./INSTALL-BINARY
-- Up-to-date: /usr/local/mysql/lib/plugin/dialog.so
-- Up-to-date: /usr/local/mysql/lib/plugin/client_ed25519.so
-- Up-to-date: /usr/local/mysql/lib/plugin/caching_sha2_password.so
-- Up-to-date: /usr/local/mysql/lib/plugin/sha256_password.so
...
-- Installing: /usr/local/mysql/support-files/systemd/mysql.service
-- Installing: /usr/local/mysql/support-files/systemd/mysqld.service
-- Installing: /usr/local/mysql/support-files/systemd/mariadb@.service
-- Installing: /usr/local/mysql/support-files/systemd/mariadb@.socket
-- Installing: /usr/local/mysql/support-files/systemd/mariadb-extra@.socket
-- Up-to-date: /usr/local/mysql/support-files/systemd/mysql.service
-- Up-to-date: /usr/local/mysql/support-files/systemd/mysqld.service&lt;/code&gt;&lt;pre&gt;&lt;code&gt;$ cmake --install build/
-- Install configuration: &amp;#34;RelWithDebInfo&amp;#34;
-- Up-to-date: /usr/local/mysql/./README.md
-- Up-to-date: /usr/local/mysql/./CREDITS
-- Up-to-date: /usr/local/mysql/./COPYING
-- Up-to-date: /usr/local/mysql/./THIRDPARTY
-- Up-to-date: /usr/local/mysql/./INSTALL-BINARY
-- Up-to-date: /usr/local/mysql/lib/plugin/dialog.so
-- Up-to-date: /usr/local/mysql/lib/plugin/client_ed25519.so
-- Up-to-date: /usr/local/mysql/lib/plugin/caching_sha2_password.so
-- Up-to-date: /usr/local/mysql/lib/plugin/sha256_password.so
...
-- Installing: /usr/local/mysql/support-files/systemd/mysql.service
-- Installing: /usr/local/mysql/support-files/systemd/mysqld.service
-- Installing: /usr/local/mysql/support-files/systemd/mariadb@.service
-- Installing: /usr/local/mysql/support-files/systemd/mariadb@.socket
-- Installing: /usr/local/mysql/support-files/systemd/mariadb-extra@.socket
-- Up-to-date: /usr/local/mysql/support-files/systemd/mysql.service
-- Up-to-date: /usr/local/mysql/support-files/systemd/mysqld.service&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To better understand the full capabilities of the build tools, it is recommended to skim through the &lt;a class="link" href="https://manpages.debian.org/unstable/cmake/cmake.1.en.html" target="_blank" rel="noopener"
&gt;cmake man page&lt;/a&gt; and the &lt;a class="link" href="https://manpages.debian.org/unstable/ninja-build/ninja.1.en.html" target="_blank" rel="noopener"
&gt;ninja man page&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="run-the-build-binaries-directly"&gt;&lt;a href="#run-the-build-binaries-directly" class="header-anchor"&gt;&lt;/a&gt;Run the build binaries directly
&lt;/h2&gt;&lt;p&gt;Instead of wasting time on running the &lt;code&gt;install&lt;/code&gt; target, one can simply invoke the build binaries directly:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-16"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-16" style="display:none;"&gt;$ ./build/client/mariadb --version
./build/client/mariadb from 11.0.1-MariaDB, client 15.2 for Linux (x86_64) using EditLine wrapper
$ ./build/sql/mariadbd --version
./build/sql/mariadbd Ver 11.0.1-MariaDB for Linux on x86_64 (Source distribution)&lt;/code&gt;&lt;pre&gt;&lt;code&gt;$ ./build/client/mariadb --version
./build/client/mariadb from 11.0.1-MariaDB, client 15.2 for Linux (x86_64) using EditLine wrapper
$ ./build/sql/mariadbd --version
./build/sql/mariadbd Ver 11.0.1-MariaDB for Linux on x86_64 (Source distribution)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To actually run the server, it needs a data directory and a user, which can be created with:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-17"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-17" style="display:none;"&gt;$ ./build/scripts/mariadb-install-db --srcdir=mariadb-server
$ adduser --disabled-password mariadb
$ chown -R mariadb:mariadb ./data
$ ./build/sql/mariadbd --datadir=./data --user=mariadb &amp;amp;
[Note] Starting MariaDB 11.0.1-MariaDB source revision as process 5428
[Note] InnoDB: Compressed tables use zlib 1.2.13
[Note] InnoDB: Using transactional memory
[Note] InnoDB: Number of transaction pools: 1
[Note] InnoDB: Using crc32 &amp;#43; pclmulqdq instructions
[Warning] mariadbd: io_uring_queue_init() failed with errno 0
[Warning] InnoDB: liburing disabled: falling back to innodb_use_native_aio=OFF
[Note] InnoDB: Initializing buffer pool, total size = 128.000MiB, chunk size = 2.000MiB
[Note] InnoDB: Completed initialization of buffer pool
[Note] InnoDB: File system buffers for log disabled (block size=512 bytes)
[Note] InnoDB: Opened 3 undo tablespaces
[Note] InnoDB: 128 rollback segments in 3 undo tablespaces are active.
[Note] InnoDB: Setting file &amp;#39;./ibtmp1&amp;#39; size to 12.000MiB. Physically writing the file full; Please wait ...
[Note] InnoDB: File &amp;#39;./ibtmp1&amp;#39; size is now 12.000MiB.
[Note] InnoDB: log sequence number 47391; transaction id 14
[Note] InnoDB: Loading buffer pool(s) from /quick-rebuilds/data/ib_buffer_pool
[Note] InnoDB: Buffer pool(s) load completed at 230220 20:28:45
[Note] Plugin &amp;#39;FEEDBACK&amp;#39; is disabled.
[Note] Server socket created on IP: &amp;#39;0.0.0.0&amp;#39;.
[Note] Server socket created on IP: &amp;#39;::&amp;#39;.
[Note] ./build/sql/mariadbd: ready for connections.
Version: &amp;#39;11.0.1-MariaDB&amp;#39; socket: &amp;#39;/tmp/mysql.sock&amp;#39; port: 3306 Source distribution&lt;/code&gt;&lt;pre&gt;&lt;code&gt;$ ./build/scripts/mariadb-install-db --srcdir=mariadb-server
$ adduser --disabled-password mariadb
$ chown -R mariadb:mariadb ./data
$ ./build/sql/mariadbd --datadir=./data --user=mariadb &amp;amp;
[Note] Starting MariaDB 11.0.1-MariaDB source revision as process 5428
[Note] InnoDB: Compressed tables use zlib 1.2.13
[Note] InnoDB: Using transactional memory
[Note] InnoDB: Number of transaction pools: 1
[Note] InnoDB: Using crc32 &amp;#43; pclmulqdq instructions
[Warning] mariadbd: io_uring_queue_init() failed with errno 0
[Warning] InnoDB: liburing disabled: falling back to innodb_use_native_aio=OFF
[Note] InnoDB: Initializing buffer pool, total size = 128.000MiB, chunk size = 2.000MiB
[Note] InnoDB: Completed initialization of buffer pool
[Note] InnoDB: File system buffers for log disabled (block size=512 bytes)
[Note] InnoDB: Opened 3 undo tablespaces
[Note] InnoDB: 128 rollback segments in 3 undo tablespaces are active.
[Note] InnoDB: Setting file &amp;#39;./ibtmp1&amp;#39; size to 12.000MiB. Physically writing the file full; Please wait ...
[Note] InnoDB: File &amp;#39;./ibtmp1&amp;#39; size is now 12.000MiB.
[Note] InnoDB: log sequence number 47391; transaction id 14
[Note] InnoDB: Loading buffer pool(s) from /quick-rebuilds/data/ib_buffer_pool
[Note] InnoDB: Buffer pool(s) load completed at 230220 20:28:45
[Note] Plugin &amp;#39;FEEDBACK&amp;#39; is disabled.
[Note] Server socket created on IP: &amp;#39;0.0.0.0&amp;#39;.
[Note] Server socket created on IP: &amp;#39;::&amp;#39;.
[Note] ./build/sql/mariadbd: ready for connections.
Version: &amp;#39;11.0.1-MariaDB&amp;#39; socket: &amp;#39;/tmp/mysql.sock&amp;#39; port: 3306 Source distribution&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;It is necessary to define the custom data directory path and custom user, otherwise mariadbd will fail to start:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-18"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-18" style="display:none;"&gt;[Warning] Can&amp;#39;t create test file /usr/local/mysql/data/03727bdc8fe2.lower-test
./build/sql/mariadbd: Can&amp;#39;t change dir to &amp;#39;/usr/local/mysql/data/&amp;#39; (Errcode: 2 &amp;#34;No such file or directory&amp;#34;)
[ERROR] Aborting
./build/sql/mariadbd: Please consult the Knowledge Base to find out how to run mysqld as root!
[ERROR] Aborting&lt;/code&gt;&lt;pre&gt;&lt;code&gt;[Warning] Can&amp;#39;t create test file /usr/local/mysql/data/03727bdc8fe2.lower-test
./build/sql/mariadbd: Can&amp;#39;t change dir to &amp;#39;/usr/local/mysql/data/&amp;#39; (Errcode: 2 &amp;#34;No such file or directory&amp;#34;)
[ERROR] Aborting
./build/sql/mariadbd: Please consult the Knowledge Base to find out how to run mysqld as root!
[ERROR] Aborting&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To gracefully stop the server, send it the &lt;a class="link" href="https://optimizedbyotto.com/post/stop-senseless-killing/" &gt;SIGTERM signal&lt;/a&gt;:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-19"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-19" style="display:none;"&gt;$ pkill -ef mariadbd
[Note] ./build/sql/mariadbd (initiated by: unknown): Normal shutdown
[Note] InnoDB: FTS optimize thread exiting.
[Note] InnoDB: Starting shutdown...
[Note] InnoDB: Dumping buffer pool(s) to /quick-rebuilds/data/ib_buffer_pool
[Note] InnoDB: Buffer pool(s) dump completed at 230220 20:29:05
[Note] InnoDB: Removed temporary tablespace data file: &amp;#34;./ibtmp1&amp;#34;
[Note] InnoDB: Shutdown completed; log sequence number 47391; transaction id 15
[Note] ./build/sql/mariadbd: Shutdown complete
mariadbd killed (pid 5428)&lt;/code&gt;&lt;pre&gt;&lt;code&gt;$ pkill -ef mariadbd
[Note] ./build/sql/mariadbd (initiated by: unknown): Normal shutdown
[Note] InnoDB: FTS optimize thread exiting.
[Note] InnoDB: Starting shutdown...
[Note] InnoDB: Dumping buffer pool(s) to /quick-rebuilds/data/ib_buffer_pool
[Note] InnoDB: Buffer pool(s) dump completed at 230220 20:29:05
[Note] InnoDB: Removed temporary tablespace data file: &amp;#34;./ibtmp1&amp;#34;
[Note] InnoDB: Shutdown completed; log sequence number 47391; transaction id 15
[Note] ./build/sql/mariadbd: Shutdown complete
mariadbd killed (pid 5428)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="quick-rebuilds"&gt;&lt;a href="#quick-rebuilds" class="header-anchor"&gt;&lt;/a&gt;Quick rebuilds
&lt;/h2&gt;&lt;p&gt;With this setup, you can invoke &lt;code&gt;eatmydata cmake --build build/&lt;/code&gt; to have the source code re-compiled as quickly as possible.&lt;/p&gt;
&lt;p&gt;The &amp;lsquo;screenshot&amp;rsquo; below showcases how Ninja/CMake will only rebuild the file with changes and its dependencies. In the case of a simple MariaDB client version string change, only 5 files needed to be re-built, and it &lt;strong&gt;took less than a second&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-20"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-20" style="display:none;"&gt;$ sed &amp;#39;s/*VER= &amp;#34;15.1&amp;#34;/*VER= &amp;#34;15.2&amp;#34;/&amp;#39; -i mariadb-server/client/mysql.cc
$ time eatmydata cmake --build build/
[5/5] Linking CXX executable client/mariadb
real 0m0.992s
user 0m0.374s
sys 0m0.353s&lt;/code&gt;&lt;pre&gt;&lt;code&gt;$ sed &amp;#39;s/*VER= &amp;#34;15.1&amp;#34;/*VER= &amp;#34;15.2&amp;#34;/&amp;#39; -i mariadb-server/client/mysql.cc
$ time eatmydata cmake --build build/
[5/5] Linking CXX executable client/mariadb
real 0m0.992s
user 0m0.374s
sys 0m0.353s&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;A similar version string change in the server leads to having to rebuild over a thousand files:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-21"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-21" style="display:none;"&gt;$ sed &amp;#39;s/MYSQL_VERSION_PATCH=1/MYSQL_VERSION_PATCH=2/&amp;#39; -i mariadb-server/VERSION
$ time eatmydata cmake --build build/
[0/1] Re-running CMake...
-- Running cmake version 3.25.1
-- MariaDB 11.0.2
-- Packaging as: mariadb-11.0.2-Linux-x86_64
-- Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE)
== Configuring MariaDB Connector/C
-- SYSTEM_LIBS: dl;m;dl;m;/usr/lib/x86_64-linux-gnu/libssl.so;/usr/lib/x86_64-linux-gnu/libcrypto.so;/usr/lib/x86_64-linux-gnu/libz.so
-- Configuring OQGraph
-- Configuring done
-- Generating done
-- Build files have been written to: /quick-rebuilds/build
[377/1257] Generating user.t
troff: fatal error: can&amp;#39;t find macro file m
[378/1257] Generating user.ps
troff: fatal error: can&amp;#39;t find macro file m
[433/1257] Building CXX object storage/archive/CMakeFiles/archive.dir/ha_archive.cc.o
In file included from /quick-rebuilds/mariadb-server/storage/archive/ha_archive.cc:29:
/quick-rebuilds/mariadb-server/storage/archive/ha_archive.h:91:15: warning: &amp;#39;index_type&amp;#39; overrides a member function but is not marked &amp;#39;override&amp;#39; [-Winconsistent-missing-override]
const char *index_type(uint inx) { return &amp;#34;NONE&amp;#34;; }
^
/quick-rebuilds/mariadb-server/sql/handler.h:3915:23: note: overridden virtual function is here
virtual const char *index_type(uint key_number) { DBUG_ASSERT(0); return &amp;#34;&amp;#34;;}
^
[...]
In file included from /quick-rebuilds/mariadb-server/storage/archive/ha_archive.cc:29:
/quick-rebuilds/mariadb-server/storage/archive/ha_archive.h:163:7: warning: &amp;#39;external_lock&amp;#39; overrides a member function but is not marked &amp;#39;override&amp;#39; [-Winconsistent-missing-override]
int external_lock(THD *thd, int lock_type);
^
/quick-rebuilds/mariadb-server/sql/handler.h:5153:15: note: overridden virtual function is here
virtual int external_lock(THD *thd __attribute__((unused)),
^
36 warnings generated.
[1257/1257] Linking CXX executable extra/mariabackup/mariadb-backup
real 2m7.786s
user 12m56.232s
sys 1m57.842s&lt;/code&gt;&lt;pre&gt;&lt;code&gt;$ sed &amp;#39;s/MYSQL_VERSION_PATCH=1/MYSQL_VERSION_PATCH=2/&amp;#39; -i mariadb-server/VERSION
$ time eatmydata cmake --build build/
[0/1] Re-running CMake...
-- Running cmake version 3.25.1
-- MariaDB 11.0.2
-- Packaging as: mariadb-11.0.2-Linux-x86_64
-- Could NOT find PkgConfig (missing: PKG_CONFIG_EXECUTABLE)
== Configuring MariaDB Connector/C
-- SYSTEM_LIBS: dl;m;dl;m;/usr/lib/x86_64-linux-gnu/libssl.so;/usr/lib/x86_64-linux-gnu/libcrypto.so;/usr/lib/x86_64-linux-gnu/libz.so
-- Configuring OQGraph
-- Configuring done
-- Generating done
-- Build files have been written to: /quick-rebuilds/build
[377/1257] Generating user.t
troff: fatal error: can&amp;#39;t find macro file m
[378/1257] Generating user.ps
troff: fatal error: can&amp;#39;t find macro file m
[433/1257] Building CXX object storage/archive/CMakeFiles/archive.dir/ha_archive.cc.o
In file included from /quick-rebuilds/mariadb-server/storage/archive/ha_archive.cc:29:
/quick-rebuilds/mariadb-server/storage/archive/ha_archive.h:91:15: warning: &amp;#39;index_type&amp;#39; overrides a member function but is not marked &amp;#39;override&amp;#39; [-Winconsistent-missing-override]
const char *index_type(uint inx) { return &amp;#34;NONE&amp;#34;; }
^
/quick-rebuilds/mariadb-server/sql/handler.h:3915:23: note: overridden virtual function is here
virtual const char *index_type(uint key_number) { DBUG_ASSERT(0); return &amp;#34;&amp;#34;;}
^
[...]
In file included from /quick-rebuilds/mariadb-server/storage/archive/ha_archive.cc:29:
/quick-rebuilds/mariadb-server/storage/archive/ha_archive.h:163:7: warning: &amp;#39;external_lock&amp;#39; overrides a member function but is not marked &amp;#39;override&amp;#39; [-Winconsistent-missing-override]
int external_lock(THD *thd, int lock_type);
^
/quick-rebuilds/mariadb-server/sql/handler.h:5153:15: note: overridden virtual function is here
virtual int external_lock(THD *thd __attribute__((unused)),
^
36 warnings generated.
[1257/1257] Linking CXX executable extra/mariabackup/mariadb-backup
real 2m7.786s
user 12m56.232s
sys 1m57.842s&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The above example also shows how Ninja spits out warnings.&lt;/p&gt;
&lt;p&gt;Despite the majority of the project files being re-built, it still &lt;strong&gt;took only two minutes&lt;/strong&gt;, mainly thanks to ccache having a high hit-rate.&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-22"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-22" style="display:none;"&gt;$ ccache --show-stats
Cacheable calls: 3235 / 3235 (100.0%)
Hits: 1932 / 3235 (59.72%)
Direct: 49 / 1932 ( 2.54%)
Preprocessed: 1883 / 1932 (97.46%)
Misses: 1303 / 3235 (40.28%)
Local storage:
Cache size (GB): 0.11 / 5.00 ( 2.18%)&lt;/code&gt;&lt;pre&gt;&lt;code&gt;$ ccache --show-stats
Cacheable calls: 3235 / 3235 (100.0%)
Hits: 1932 / 3235 (59.72%)
Direct: 49 / 1932 ( 2.54%)
Preprocessed: 1883 / 1932 (97.46%)
Misses: 1303 / 3235 (40.28%)
Local storage:
Cache size (GB): 0.11 / 5.00 ( 2.18%)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Without ccache, the build time in the same scenario is 6–8 minutes. There are some extra flags in ccache (such as &lt;a class="link" href="https://ccache.dev/manual/4.7.4.html#_configuration_options" target="_blank" rel="noopener"
&gt;CCACHE_SLOPPINESS&lt;/a&gt;) which can be used to further tune the ccache speed, but when I did some experimenting, I didn&amp;rsquo;t discover any that made a visible impact.&lt;/p&gt;
&lt;p&gt;Without &lt;a class="link" href="https://manpages.debian.org/unstable/eatmydata/eatmydata.1.en.html" target="_blank" rel="noopener"
&gt;eatmydata&lt;/a&gt;, the build takes 10-20 seconds longer, as the system calls to disk will wait for &lt;a class="link" href="https://manpages.debian.org/unstable/manpages-dev/fsync.2.en.html" target="_blank" rel="noopener"
&gt;fsync&lt;/a&gt; and the like to complete, but which we are fine skipping since we don&amp;rsquo;t care about data durability and crash recovery as this is a throwaway environment anyway. Using regular &lt;a class="link" href="https://gcc.gnu.org/" target="_blank" rel="noopener"
&gt;GNU GCC&lt;/a&gt; instead of Clang adds another 20–40 seconds to the rebuild time.&lt;/p&gt;
&lt;p&gt;The current two minutes for the build time on my laptop with 8-core Intel i7-8650U CPU @ 1.90GHz is not exactly instant, but it is fast enough that I can sit and wait it out without feeling the need to context switch and loose my focus.&lt;/p&gt;
&lt;h2 id="automatic-rebuild"&gt;&lt;a href="#automatic-rebuild" class="header-anchor"&gt;&lt;/a&gt;Automatic rebuild
&lt;/h2&gt;&lt;p&gt;As showcased in the post &lt;a class="link" href="https://optimizedbyotto.com/post/develop-code-10x-faster/" &gt;How to code 10x faster than an average programmer&lt;/a&gt;, as a high-performing software developer, you don&amp;rsquo;t want to waste time on manually running a lot of commands to build and test your code, but instead you want to have a setup where you write code in your editor and have the code automatically re-compile and run when the source code file is saved.&lt;/p&gt;
&lt;p&gt;For MariaDB, the automatic rebuild part can easily be achieved with:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-23"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-23" style="display:none;"&gt;find mariadb-server/* | entr eatmydata cmake --build build/&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;find mariadb-server/* | entr eatmydata cmake --build build/&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To automatically rebuild and also run a binary (in this case the &lt;em&gt;mariadb&lt;/em&gt; client), define multiple commands in quotes to the &lt;code&gt;-s&lt;/code&gt; parameter:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-24"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-24" style="display:none;"&gt;find mariadb-server/* | \
entr -s &amp;#39;eatmydata cmake --build build/; ./build/client/mariadb --version&amp;#39;&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;find mariadb-server/* | &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; entr -s &lt;span style="color:#e6db74"&gt;&amp;#39;eatmydata cmake --build build/; ./build/client/mariadb --version&amp;#39;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src="https://optimizedbyotto.com/post/quick-builds-and-rebuilds-of-mariadb-with-docker/mariadb-atom-autosave-entr-demo.gif"
width="1200"
height="611"
loading="lazy"
alt="MariaDB client automatic compilation and re-run"
class="gallery-image"
data-flex-grow="196"
data-flex-basis="471px"
&gt;
&lt;/p&gt;
&lt;p&gt;When running the server use the &lt;code&gt;-r&lt;/code&gt; parameter to have Entr automatically restart it:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-25"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-25" style="display:none;"&gt;find mariadb-server/* | \
entr -r ./build/sql/mariadbd --datadir=./data --user=mariadb&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;find mariadb-server/* | &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; entr -r ./build/sql/mariadbd --datadir&lt;span style="color:#f92672"&gt;=&lt;/span&gt;./data --user&lt;span style="color:#f92672"&gt;=&lt;/span&gt;mariadb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src="https://optimizedbyotto.com/post/quick-builds-and-rebuilds-of-mariadb-with-docker/mariadb-server-atom-autosave-entr-demo.gif"
width="1200"
height="611"
loading="lazy"
alt="MariaDB server automatic compilation and restart"
class="gallery-image"
data-flex-grow="196"
data-flex-basis="471px"
&gt;
&lt;/p&gt;
&lt;p&gt;If the you are developing an MTR test by editing *.test files, there is no need to recompile anything, and you can simply have Entr re-run the test every time a file is changed:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-26"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-26" style="display:none;"&gt;find mariadb-server/* | entr -r ./build/mysql-test/mysql-test-run.pl main.connect&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;find mariadb-server/* | entr -r ./build/mysql-test/mysql-test-run.pl main.connect&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;&lt;img src="https://optimizedbyotto.com/post/quick-builds-and-rebuilds-of-mariadb-with-docker/mariadb-mtr-atom-autosave-entr-demo.gif"
width="1200"
height="611"
loading="lazy"
alt="MariaDB test run automatic restart"
class="gallery-image"
data-flex-grow="196"
data-flex-basis="471px"
&gt;
&lt;/p&gt;
&lt;h2 id="conclusion"&gt;&lt;a href="#conclusion" class="header-anchor"&gt;&lt;/a&gt;Conclusion
&lt;/h2&gt;&lt;p&gt;The examples above are specific to MariaDB and illustrate in detail how to be efficient and avoid wasting &lt;a class="link" href="https://xkcd.com/303/" target="_blank" rel="noopener"
&gt;time compiling&lt;/a&gt;, but the principles of utilizing ccache/clang/ninja apply to any software project in C/C++, and entr comes in handy in a myriad of situations.&lt;/p&gt;
&lt;p&gt;Hopefully this inspires you to raise the bar on what to expect of speed and efficiency in the future!&lt;/p&gt;</description>
    </item>
    <item>
      <title>Grokking the MariaDB test runner (MTR)</title>
      <link>https://optimizedbyotto.com/post/grokking-mariadb-test-run-mtr/</link>
      <pubDate>Sun, 19 Feb 2023 00:00:00 +0000</pubDate>
      <guid>https://optimizedbyotto.com/post/grokking-mariadb-test-run-mtr/</guid>
      <description>&lt;img src="https://optimizedbyotto.com/post/grokking-mariadb-test-run-mtr/featured-image.jpg" alt="Featured image of post Grokking the MariaDB test runner (MTR)" /&gt;&lt;p&gt;The main test system in the MariaDB open source database project is the &lt;a class="link" href="https://mariadb.com/kb/en/mysql-test-runpl-options/" target="_blank" rel="noopener"
&gt;mariadb-test-run script&lt;/a&gt; (inherited from &lt;a class="link" href="https://dev.mysql.com/doc/dev/mysql-server/latest/PAGE_MYSQL_TEST_RUN_PL.html" target="_blank" rel="noopener"
&gt;mysql-test-run&lt;/a&gt;). It is easy to run and does not require you to compile any source code.&lt;/p&gt;
&lt;p&gt;While writing MTR tests is relevant only for MariaDB developers, knowing how to run MTR is useful for any database administrator running MariaDB, as it is a &lt;strong&gt;quick way to validate that MariaDB can run correctly on your hardware and operating system version&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;h2 id="tldr-for-debianubuntu-users"&gt;&lt;a href="#tldr-for-debianubuntu-users" class="header-anchor"&gt;&lt;/a&gt;TL;DR for Debian/Ubuntu users
&lt;/h2&gt;&lt;p&gt;Run the full 6000+ test suite as current user in temporary directory with
multiple workers in parallel and with detailed logging on failures, typically
taking over 30 minutes on modern laptop:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-0"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-0" style="display:none;"&gt;apt install -y mariadb-test mariadb-backup mariadb-plugin-* patch gdb
cd /usr/share/mysql/mysql-test
export MTR_PRINT_CORE=detailed
./mtr --force --parallel=auto --vardir=$(mktemp -d) \
--skip-test-list=unstable-tests.amd64 --big-test&lt;/code&gt;&lt;pre&gt;&lt;code&gt;apt install -y mariadb-test mariadb-backup mariadb-plugin-* patch gdb
cd /usr/share/mysql/mysql-test
export MTR_PRINT_CORE=detailed
./mtr --force --parallel=auto --vardir=$(mktemp -d) \
--skip-test-list=unstable-tests.amd64 --big-test&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For full details, read the whole article.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id="install-mariadb-test-package-in-debianubuntu"&gt;&lt;a href="#install-mariadb-test-package-in-debianubuntu" class="header-anchor"&gt;&lt;/a&gt;Install &amp;lsquo;mariadb-test&amp;rsquo; package in Debian/Ubuntu
&lt;/h2&gt;&lt;p&gt;To avoid polluting your actual system with new packages, it is convenient to run MTR in a throwaway container. Start one with some RAM-memory-backed disk allocated with &lt;code&gt;--shm-size=1G&lt;/code&gt; so running MTR with &lt;code&gt;--mem&lt;/code&gt; later on is possible:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-1"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-1" style="display:none;"&gt;docker run --interactive --tty --rm --shm-size=1G debian:sid bash&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;docker run --interactive --tty --rm --shm-size&lt;span style="color:#f92672"&gt;=&lt;/span&gt;1G debian:sid bash&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;This example uses &lt;a class="link" href="https://en.wikipedia.org/wiki/Docker_%28software%29" target="_blank" rel="noopener"
&gt;Docker&lt;/a&gt;, but the principle is the same with &lt;a class="link" href="https://en.wikipedia.org/wiki/OS-level_virtualization#Implementations" target="_blank" rel="noopener"
&gt;any Linux container&lt;/a&gt; tool, such as Podman.&lt;/p&gt;
&lt;p&gt;Next, install the MariaDB test suite package. This will also pull in the MariaDB server and all the necessary dependencies. Additionally, also install &lt;a class="link" href="https://en.wikipedia.org/wiki/GNU_Debugger" target="_blank" rel="noopener"
&gt;the GNU Debugger (gdb)&lt;/a&gt; for automatic stack traces and &lt;a class="link" href="https://manpages.debian.org/unstable/patch/patch.1.en.html" target="_blank" rel="noopener"
&gt;patch&lt;/a&gt;.&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-2"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-2" style="display:none;"&gt;apt update
apt install -y mariadb-test mariadb-backup mariadb-plugin-* patch gdb&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;apt update
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;apt install -y mariadb-test mariadb-backup mariadb-plugin-* patch gdb&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The mariadb-test-run is not intended to be run as root and will skip some tests if run as root. Therefore, create a new user inside the container and grant it permissions to the test directory:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-3"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-3" style="display:none;"&gt;adduser --disabled-password mariadb-test-runner
chown -R mariadb-test-runner /usr/share/mysql/mysql-test&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;adduser --disabled-password mariadb-test-runner
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;chown -R mariadb-test-runner /usr/share/mysql/mysql-test&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;At minimum, the test runner user needs to be able to write to the path &lt;code&gt;/usr/share/mysql/mysql-test/var&lt;/code&gt; (unless some other path is defined with &lt;code&gt;--vardir&lt;/code&gt; and &lt;code&gt;--tmpdir&lt;/code&gt;), but some tests also run &lt;code&gt;patch&lt;/code&gt; to modify the test files on-the-fly, so just grant permissions to the whole test directory. As this is a throwaway container anyway, there is no need to be prudent with the permissions.&lt;/p&gt;
&lt;p&gt;Next, switch to the test user and test directory and start the run with default settings:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-4"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-4" style="display:none;"&gt;$ su - mariadb-test-runner
$ cd /usr/share/mysql/mysql-test
$ ./mariadb-test-run
Logging: ./mariadb-test-run
VS config:
vardir: /usr/share/mysql/mysql-test/var
Creating var directory &amp;#39;/usr/share/mysql/mysql-test/var&amp;#39;...
Checking supported features...
MariaDB Version 10.11.2-MariaDB-1
- SSL connections supported
- binaries built with wsrep patch
Using suites: main-,archive-,atomic-,binlog-,binlog_encryption-,client-,csv-,compat/oracle-,compat/mssql-,compat/maxdb-,encryption-,federated-,funcs_1-,funcs_2-,gcol-,handler-,heap-,innodb-,innodb_fts-,innodb_gis-,innodb_i_s-,innodb_zip-,json-,maria-,mariabackup-,multi_source-,optimizer_unfixed_bugs-,parts-,perfschema-,plugins-,roles-,rpl-,stress-,sys_vars-,sql_sequence-,unit-,vcol-,versioning-,period-,sysschema-,disks,func_test,metadata_lock_info,query_response_time,sequence,sql_discovery,type_inet,type_uuid,user_variables
Collecting tests...
...
main.subselect_innodb &amp;#39;innodb&amp;#39; w4 [ pass ] 3359
main.subselect_sj2 &amp;#39;innodb&amp;#39; w1 [ pass ] 2737
main.subselect_sj2_jcl6 &amp;#39;innodb&amp;#39; w3 [ pass ] 2933
main.parser_bug21114_innodb &amp;#39;innodb&amp;#39; w8 [ pass ] 15364
innodb_gis.rtree_search &amp;#39;innodb&amp;#39; w5 [ pass ] 52379
--------------------------------------------------------------------------
The servers were restarted 1736 times
Spent 8527.863 of 1659 seconds executing testcases
Completed: All 5131 tests were successful.
995 tests were skipped, 280 by the test itself.&lt;/code&gt;&lt;pre&gt;&lt;code&gt;$ su - mariadb-test-runner
$ cd /usr/share/mysql/mysql-test
$ ./mariadb-test-run
Logging: ./mariadb-test-run
VS config:
vardir: /usr/share/mysql/mysql-test/var
Creating var directory &amp;#39;/usr/share/mysql/mysql-test/var&amp;#39;...
Checking supported features...
MariaDB Version 10.11.2-MariaDB-1
- SSL connections supported
- binaries built with wsrep patch
Using suites: main-,archive-,atomic-,binlog-,binlog_encryption-,client-,csv-,compat/oracle-,compat/mssql-,compat/maxdb-,encryption-,federated-,funcs_1-,funcs_2-,gcol-,handler-,heap-,innodb-,innodb_fts-,innodb_gis-,innodb_i_s-,innodb_zip-,json-,maria-,mariabackup-,multi_source-,optimizer_unfixed_bugs-,parts-,perfschema-,plugins-,roles-,rpl-,stress-,sys_vars-,sql_sequence-,unit-,vcol-,versioning-,period-,sysschema-,disks,func_test,metadata_lock_info,query_response_time,sequence,sql_discovery,type_inet,type_uuid,user_variables
Collecting tests...
...
main.subselect_innodb &amp;#39;innodb&amp;#39; w4 [ pass ] 3359
main.subselect_sj2 &amp;#39;innodb&amp;#39; w1 [ pass ] 2737
main.subselect_sj2_jcl6 &amp;#39;innodb&amp;#39; w3 [ pass ] 2933
main.parser_bug21114_innodb &amp;#39;innodb&amp;#39; w8 [ pass ] 15364
innodb_gis.rtree_search &amp;#39;innodb&amp;#39; w5 [ pass ] 52379
--------------------------------------------------------------------------
The servers were restarted 1736 times
Spent 8527.863 of 1659 seconds executing testcases
Completed: All 5131 tests were successful.
995 tests were skipped, 280 by the test itself.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="defining-what-tests-to-run"&gt;&lt;a href="#defining-what-tests-to-run" class="header-anchor"&gt;&lt;/a&gt;Defining what tests to run
&lt;/h2&gt;&lt;p&gt;If no test suite is selected, MTR will run about 6000 tests, which on my laptop takes about 30 minutes. If MTR is started with the additional &lt;code&gt;--big-test&lt;/code&gt; parameter, it will run additional tests that are resource intensive and consume, for example, a lot of RAM memory and take a long time to run, totalling a test run that has 6100 tests and takes 43 minutes to complete (on my laptop). To &lt;em&gt;only&lt;/em&gt; run big tests, use &lt;code&gt;--big --big&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If there is a need to limit the scope, such as in build systems that want to validate that the built binary works without running all tests, typically &lt;code&gt;--suite=main --skip-rpl&lt;/code&gt; is used. This results in about 1000 tests being run, which on my laptop takes about 3½ minutes.&lt;/p&gt;
&lt;p&gt;Even when running without any limitations on what tests are run, many tests have code that makes them opt out automatically based on some condition being missing, and on my laptop about 1000 tests end up being skipped. Some examples:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-5"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-5" style="display:none;"&gt;main.connect2 [ skipped ] Requires debug build
main.mysql_client_test_comp [ skipped ] No IPv6
main.connect-abstract [ skipped ] Need Linux
main.grant_cache_ps_prot [ skipped ] Need ps-protocol
main.fix_priv_tables [ skipped ] Test need MYSQL_FIX_PRIVILEGE_TABLES
main.no-threads [ skipped ] Test requires: &amp;#39;one_thread_per_connection&amp;#39;
main.udf_skip_grants [ skipped ] Need udf example
main.lowercase_mixed_tmpdir_innodb [ skipped ] Test requires: &amp;#39;lowercase2&amp;#39;
main.innodb_load_xa [ skipped ] Need InnoDB plugin
mariabackup.alter_copy_excluded [ skipped ] No mariabackup
binlog.binlog_expire_warnings [ skipped ] Test needs --big-test
encryption.innodb-spatial-index [ skipped ] requires patch executable
plugins.pam_cleartext [ skipped ] Not run as user owning auth_pam_tool_dir
rpl.rpl_gtid_mdev4474 &amp;#39;innodb,row&amp;#39; [ skipped ] Neither MIXED nor STATEMENT binlog format&lt;/code&gt;&lt;pre&gt;&lt;code&gt;main.connect2 [ skipped ] Requires debug build
main.mysql_client_test_comp [ skipped ] No IPv6
main.connect-abstract [ skipped ] Need Linux
main.grant_cache_ps_prot [ skipped ] Need ps-protocol
main.fix_priv_tables [ skipped ] Test need MYSQL_FIX_PRIVILEGE_TABLES
main.no-threads [ skipped ] Test requires: &amp;#39;one_thread_per_connection&amp;#39;
main.udf_skip_grants [ skipped ] Need udf example
main.lowercase_mixed_tmpdir_innodb [ skipped ] Test requires: &amp;#39;lowercase2&amp;#39;
main.innodb_load_xa [ skipped ] Need InnoDB plugin
mariabackup.alter_copy_excluded [ skipped ] No mariabackup
binlog.binlog_expire_warnings [ skipped ] Test needs --big-test
encryption.innodb-spatial-index [ skipped ] requires patch executable
plugins.pam_cleartext [ skipped ] Not run as user owning auth_pam_tool_dir
rpl.rpl_gtid_mdev4474 &amp;#39;innodb,row&amp;#39; [ skipped ] Neither MIXED nor STATEMENT binlog format&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you are interested in one particular test, just give it as the last argument:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-6"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-6" style="display:none;"&gt;$ ./mariadb-test-run main.connect
Logging: ./mariadb-test-run main.connect
Creating var directory &amp;#39;/usr/share/mysql/mysql-test/var&amp;#39;...
Checking supported features...
MariaDB Version 10.11.2-MariaDB-1
- SSL connections supported
- binaries built with wsrep patch
Collecting tests...
Installing system database...
==============================================================================
TEST RESULT TIME (ms) or COMMENT
--------------------------------------------------------------------------
main.connect [ pass ] 14206
--------------------------------------------------------------------------
The servers were restarted 0 times
Spent 14.206 of 20 seconds executing testcases
Completed: All 1 tests were successful.&lt;/code&gt;&lt;pre&gt;&lt;code&gt;$ ./mariadb-test-run main.connect
Logging: ./mariadb-test-run main.connect
Creating var directory &amp;#39;/usr/share/mysql/mysql-test/var&amp;#39;...
Checking supported features...
MariaDB Version 10.11.2-MariaDB-1
- SSL connections supported
- binaries built with wsrep patch
Collecting tests...
Installing system database...
==============================================================================
TEST RESULT TIME (ms) or COMMENT
--------------------------------------------------------------------------
main.connect [ pass ] 14206
--------------------------------------------------------------------------
The servers were restarted 0 times
Spent 14.206 of 20 seconds executing testcases
Completed: All 1 tests were successful.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2 id="optimize-the-mtr-run-for-speed"&gt;&lt;a href="#optimize-the-mtr-run-for-speed" class="header-anchor"&gt;&lt;/a&gt;Optimize the MTR run for speed
&lt;/h2&gt;&lt;p&gt;There are three parameters that can greatly improve how quickly MTR runs. The primary one is &lt;code&gt;--parallel=auto&lt;/code&gt;, which will run MTR in parallel with as many workers as there are CPUs (by default MTR runs with just one worker). On my laptop, going from one MTR worker to 8 in parallel reduced the total run time for the &lt;em&gt;main&lt;/em&gt; suite from 17 to about 3 minutes.&lt;/p&gt;
&lt;p&gt;Another parameter is &lt;code&gt;--fast&lt;/code&gt;, which will make the MTR kill all server processes violently without waiting for them to gracefully shutdown. The test run restarts the MariaDB server hundreds of times, so saving half a second on every shutdown results in the main suite completing 20 seconds faster.&lt;/p&gt;
&lt;p&gt;The parameter &lt;code&gt;--mem&lt;/code&gt; instructs MTR to make the directory &lt;code&gt;var/&lt;/code&gt; a symbolic link to a subdirectory on the shared memory device (&lt;code&gt;/dev/shm&lt;/code&gt;). This works if the container is started with &lt;code&gt;--shm-size&lt;/code&gt; and has at least 350MB of space on the ramdisk. On my laptop, this further reduced the main test suite duration down to 2½ minutes.&lt;/p&gt;
&lt;h2 id="optimize-the-mtr-run-for-logging"&gt;&lt;a href="#optimize-the-mtr-run-for-logging" class="header-anchor"&gt;&lt;/a&gt;Optimize the MTR run for logging
&lt;/h2&gt;&lt;p&gt;When running a single test, one might use &lt;code&gt;--verbose&lt;/code&gt; as an additional argument to see the commands that run in the test. It is also possible to define &lt;code&gt;--verbose --verbose&lt;/code&gt; twice, but that makes the test run so verbose that it is unusable.&lt;/p&gt;
&lt;p&gt;When running a suite of tests, you only want to have extra output visible if the test fails. If the server fails to start and a particular test doesn&amp;rsquo;t run at all, using &lt;code&gt;--verbose-restart&lt;/code&gt; might be beneficial. If running the test in an automated system, one might want to save results in a JUnit-compatible XML file that can, for example, be &lt;a class="link" href="https://docs.gitlab.com/ee/ci/testing/unit_test_reports.html" target="_blank" rel="noopener"
&gt;rendered by GitLab CI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is the command that several CI systems run MTR with:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-7"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-7" style="display:none;"&gt;export MTR_PRINT_CORE=detailed
eatmydata perl -I. ./mariadb-test-run \
--force --testcase-timeout=120 --suite-timeout=540 --retry=3 \
--verbose-restart --max-save-core=1 --max-save-datadir=1 \
--parallel=auto --skip-rpl --suite=main \
--xml-report=mariadb-test-run-junit.xml&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;export MTR_PRINT_CORE&lt;span style="color:#f92672"&gt;=&lt;/span&gt;detailed
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;eatmydata perl -I. ./mariadb-test-run &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; --force --testcase-timeout&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;120&lt;/span&gt; --suite-timeout&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;540&lt;/span&gt; --retry&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;3&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; --verbose-restart --max-save-core&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; --max-save-datadir&lt;span style="color:#f92672"&gt;=&lt;/span&gt;&lt;span style="color:#ae81ff"&gt;1&lt;/span&gt; &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; --parallel&lt;span style="color:#f92672"&gt;=&lt;/span&gt;auto --skip-rpl --suite&lt;span style="color:#f92672"&gt;=&lt;/span&gt;main &lt;span style="color:#ae81ff"&gt;\
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;&lt;/span&gt; --xml-report&lt;span style="color:#f92672"&gt;=&lt;/span&gt;mariadb-test-run-junit.xml&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The command above also showcases use of &lt;a class="link" href="https://manpages.debian.org/unstable/eatmydata/eatmydata.1.en.html" target="_blank" rel="noopener"
&gt;eatmydata&lt;/a&gt;, which makes &lt;a class="link" href="https://manpages.debian.org/unstable/manpages-dev/fsync.2.en.html" target="_blank" rel="noopener"
&gt;fsync&lt;/a&gt; and similar system calls skip memory-to-disk guarantees, but in my testing with MTR, it didn&amp;rsquo;t affect speed.&lt;/p&gt;
&lt;h2 id="running-more-tests-for-mariadb"&gt;&lt;a href="#running-more-tests-for-mariadb" class="header-anchor"&gt;&lt;/a&gt;Running more tests for MariaDB
&lt;/h2&gt;&lt;p&gt;The above summarizes everything one typically needs to know for &lt;em&gt;running&lt;/em&gt; the mariadb-test-run.&lt;/p&gt;
&lt;p&gt;For a &lt;a class="link" href="https://en.wikipedia.org/wiki/Database_administration" target="_blank" rel="noopener"
&gt;DBA&lt;/a&gt;, there are also several other tools that ship with MariaDB, which can help with testing and validating one&amp;rsquo;s own environment, such as &lt;a class="link" href="https://dyn.manpages.debian.org/unstable/mariadb-test/mysql-stress-test.pl.1.en.html" target="_blank" rel="noopener"
&gt;mariadb-stress-test&lt;/a&gt; and &lt;a class="link" href="https://manpages.debian.org/unstable/mariadb-client/mariadb-slap.1.en.html" target="_blank" rel="noopener"
&gt;mariadb-slap&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="writing-mtr-tests-for-mariadb"&gt;&lt;a href="#writing-mtr-tests-for-mariadb" class="header-anchor"&gt;&lt;/a&gt;Writing MTR tests for MariaDB
&lt;/h2&gt;&lt;p&gt;If you want to &lt;em&gt;write&lt;/em&gt; a new test or fix an existing test, there are many more additional parameters to learn, such as &lt;code&gt;--record&lt;/code&gt; and &lt;code&gt;--gcov&lt;/code&gt;. The official &lt;a class="link" href="https://mariadb.org/get-involved/getting-started-for-developers/get-code-build-test/" target="_blank" rel="noopener"
&gt;contribution docs at mariadb.org&lt;/a&gt; list some of the most useful MTR parameters. The &lt;a class="link" href="https://mariadb.com/kb/en/generic-build-instructions/" target="_blank" rel="noopener"
&gt;mariadb.com knowledge base article&lt;/a&gt; lists them all. As with all commands in Linux, there is also the &lt;a class="link" href="https://manpages.debian.org/unstable/mariadb-test/mysql-test-run.pl.1.en.html" target="_blank" rel="noopener"
&gt;main page for mariadb-test-run&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The structure of the tests is actually quite easy, and &lt;strong&gt;requires no C/C++ skills to write&lt;/strong&gt;. Each test file (suffix &lt;code&gt;.test&lt;/code&gt;) consists mainly of SQL code which is executed by &lt;code&gt;mariadb-test-run&lt;/code&gt; (MTR), with the output compared (with &lt;a class="link" href="https://manpages.debian.org/unstable/diffutils/diff.1.en.html" target="_blank" rel="noopener"
&gt;diff&lt;/a&gt;) to the corresponding file with the expected output in text format (suffix &lt;code&gt;.result&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;In my development &lt;a class="link" href="https://optimizedbyotto.com/post/develop-code-10x-faster/" &gt;workflow&lt;/a&gt;, writing a test and running MTR might look something like this:
&lt;img src="https://optimizedbyotto.com/post/quick-builds-and-rebuilds-of-mariadb-with-docker/mariadb-mtr-atom-autosave-entr-demo.gif"
loading="lazy"
alt="MariaDB test run automatic restart"
&gt;
&lt;/p&gt;
&lt;p&gt;If you want to contribute to the MariaDB open source project, extending the test coverage is a great place to start. To &lt;em&gt;scratch your own itch&lt;/em&gt;, think about a MariaDB bug you encountered while using it, and consider if that can be reproduced as a test and submitted upstream so that it becomes part of the body of tests and thus easy to catch if it ever regresses again.&lt;/p&gt;
&lt;p&gt;To learn more about writing mariadb-test-run tests, read the &lt;a class="link" href="https://mariadb.org/get-involved/getting-started-for-developers/writing-good-test-cases-mariadb-server/" target="_blank" rel="noopener"
&gt;test case authoring guide at mariadb.org&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Ensuring software quality with GitLab CI – case MariaDB in Debian</title>
      <link>https://optimizedbyotto.com/post/gitlab-mariadb-debian/</link>
      <pubDate>Sun, 02 Oct 2022 00:00:00 +0000</pubDate>
      <guid>https://optimizedbyotto.com/post/gitlab-mariadb-debian/</guid>
      <description>&lt;img src="https://optimizedbyotto.com/post/gitlab-mariadb-debian/mariadb-salsa-ci-example.png" alt="Featured image of post Ensuring software quality with GitLab CI – case MariaDB in Debian" /&gt;&lt;p&gt;Of &lt;strong&gt;all&lt;/strong&gt; CI systems I&amp;rsquo;ve used during my software development career, both as developer and manager, &lt;a class="link" href="https://docs.gitlab.com/ee/ci/" target="_blank" rel="noopener"
&gt;GitLab CI&lt;/a&gt; has proven itself to be the overall best system out there.&lt;/p&gt;
&lt;p&gt;First of all, for a CI system to fulfill its purpose, it needs to test every &lt;a class="link" href="https://optimizedbyotto.com/post/good-git-commit/" &gt;git commit&lt;/a&gt; to validate that no code change breaks the test suite no matter how small the change is. Having code hosting and CI integrated in the same system is the obvious way it should be, and GitLab CI does that integration well on all levels from &lt;a class="link" href="https://git-scm.com/" target="_blank" rel="noopener"
&gt;git&lt;/a&gt; command-line &lt;a class="link" href="https://docs.gitlab.com/ee/user/project/push_options.html#push-options-for-gitlab-cicd" target="_blank" rel="noopener"
&gt;option support&lt;/a&gt; to repository permission control to user interface in every view.&lt;/p&gt;
&lt;p&gt;For developers to pay attention to tests that stop passing after their code changes, there need to be automatic and easy to read notifications. GitLab CI does email and dozens of integrations, such as Slack messages.&lt;/p&gt;
&lt;p&gt;For developers to quickly find the error, root cause it and deliver a proper fix, the CI pipeline needs to be visually clean yet offer options to drill into logs and build artifacts. GitLab CI checks all the boxes here.&lt;/p&gt;
&lt;p&gt;Finally, when it is time to review a code change, the way GitLab CI integrates with &lt;a class="link" href="https://docs.gitlab.com/ee/user/project/merge_requests/" target="_blank" rel="noopener"
&gt;GitLab Merge Requests&lt;/a&gt; is seamless. For example, a human reviewer can, after reading the code change, choose the action &lt;em&gt;Merge automatically if CI pipeline passed&lt;/em&gt; without having to attend the pipeline. Brilliant time-saver.&lt;/p&gt;
&lt;p&gt;&lt;img src="https://optimizedbyotto.com/post/gitlab-mariadb-debian/gitlab-merge-request-example.png"
width="1200"
height="793"
srcset="https://optimizedbyotto.com/post/gitlab-mariadb-debian/gitlab-merge-request-example_hu1808563607855547059.png 480w, https://optimizedbyotto.com/post/gitlab-mariadb-debian/gitlab-merge-request-example.png 1200w"
loading="lazy"
alt="Example merge request"
class="gallery-image"
data-flex-grow="151"
data-flex-basis="363px"
&gt;
&lt;/p&gt;
&lt;p&gt;GitLab is also open source, so if it is missing a feature that is critical for your software development work, you can add that feature yourself (or pay somebody to do it). Being open source also brings many other benefits and ultimately sets it apart from GitHub, its traditional closed source rival.&lt;/p&gt;
&lt;p&gt;Last but not least, &lt;a class="link" href="https://docs.gitlab.com/ee/user/" target="_blank" rel="noopener"
&gt;GitLab has excellent documentation&lt;/a&gt; anybody can dive into easily. Therefore, instead of duplicating that by explaining the general &lt;a class="link" href="https://about.gitlab.com/features/" target="_blank" rel="noopener"
&gt;GitLab features and benefits&lt;/a&gt;, I will instead &lt;strong&gt;showcase how it is used in a real-life project: MariaDB Debian package maintenance&lt;/strong&gt;.&lt;/p&gt;
&lt;h2 id="salsa---debians-gitlab-instance"&gt;&lt;a href="#salsa---debians-gitlab-instance" class="header-anchor"&gt;&lt;/a&gt;Salsa - Debian&amp;rsquo;s GitLab instance
&lt;/h2&gt;&lt;p&gt;Debian launched &lt;a class="link" href="https://salsa.debian.org/" target="_blank" rel="noopener"
&gt;salsa.debian.org&lt;/a&gt; in early 2018 as a platform for Debian developers to host the source code of Debian packages. In July of 2018, &lt;a class="link" href="https://salsa.debian.org/salsa-ci-team" target="_blank" rel="noopener"
&gt;Salsa-CI&lt;/a&gt;, which provides a standardized GitLab CI pipeline template for Debian packaging quality assurance, was launched. I adopted this in August 2018 for all the packages I maintain in Debian, of which by far the biggest is the &lt;a class="link" href="https://mariadb.org/" target="_blank" rel="noopener"
&gt;MariaDB database server&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Over the years it has grown to a very extensive pipeline that, &lt;strong&gt;in addition to the inherited general Salsa-CI steps, also runs a variety of additional test jobs&lt;/strong&gt;, including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Building MariaDB in parallel on multiple Debian releases and processor architectures&lt;/li&gt;
&lt;li&gt;Building consumers of the MariaDB Client C library to ensure the interface stays stable&lt;/li&gt;
&lt;li&gt;Upgrading old versions of MariaDB to the latest one, both full server upgrades and partial small upgrades, such as the client library upgrades&lt;/li&gt;
&lt;li&gt;Upgrading various versions of MySQL, Percona and others to ensure that cross-upgrades from MariaDB variants work&lt;/li&gt;
&lt;li&gt;Upgrading various combinations of Debian releases and MariaDB, simulating full system upgrades&lt;/li&gt;
&lt;li&gt;Running static analysis to detect security issues and general software quality issues&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src="https://optimizedbyotto.com/post/gitlab-mariadb-debian/mariadb-salsa-ci-example.png"
width="2648"
height="1335"
srcset="https://optimizedbyotto.com/post/gitlab-mariadb-debian/mariadb-salsa-ci-example_hu10652549863109246822.png 480w, https://optimizedbyotto.com/post/gitlab-mariadb-debian/mariadb-salsa-ci-example_hu9306486898252685304.png 1024w, https://optimizedbyotto.com/post/gitlab-mariadb-debian/mariadb-salsa-ci-example.png 2648w"
loading="lazy"
alt="Example pipeline"
class="gallery-image"
data-flex-grow="198"
data-flex-basis="476px"
&gt;
&lt;/p&gt;
&lt;p&gt;Not only does the pipeline do all this, but it is also optimized to use &lt;a class="link" href="https://ccache.dev/" target="_blank" rel="noopener"
&gt;ccache&lt;/a&gt; and other techniques to run as fast as possible. For details on exactly what the pipeline does, one can simply read the file &lt;a class="link" href="https://salsa.debian.org/mariadb-team/mariadb-server/-/blob/debian/latest/debian/salsa-ci.yml" target="_blank" rel="noopener"
&gt;&lt;code&gt;debian/salsa-ci.yml&lt;/code&gt;&lt;/a&gt;. Normal GitLab CI uses the file &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; in the project root, but since in Debian packaging one is only allowed to modify files under the &lt;code&gt;debian&lt;/code&gt; sub-directory, the file resides at this customized path.&lt;/p&gt;
&lt;p&gt;The fact that the structure and all the steps the CI runs are defined in the code repository itself is very powerful. &lt;strong&gt;Anybody inspecting a pipeline run of a specific git commit can always find the specific version of the GitLab CI definition in the source code of that exact git commit itself.&lt;/strong&gt; This is vastly superior to the structure e.g. Buildbot or Jenkins uses, where the pipeline is defined separately from the code it tests.&lt;/p&gt;
&lt;p&gt;Not only does this make it much easier to read the pipeline steps, but it also makes contributing to the pipeline code as straightforward as filing a Merge Request on the repository, just like with any other file. The fact that the CI code and actual software code are together in the same repository makes it much easier to enforce a rule that CI must always pass, as any commit that changes the software behavior can at the same time also update the CI pipeline to account for that intentional change in behavior. Needless to say, GitLab CI works seamlessly with the &lt;a class="link" href="https://salsa.debian.org/help/user/project/protected_branches" target="_blank" rel="noopener"
&gt;protected branches&lt;/a&gt; feature and Merge Requests in GitLab to ensure easy and sensible rules to &lt;strong&gt;enforce that the mainline always stays green&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Using standard GitLab CI features, there is also a &lt;a class="link" href="https://salsa.debian.org/mariadb-team/mariadb-server/-/pipeline_schedules" target="_blank" rel="noopener"
&gt;scheduled monthly rebuild&lt;/a&gt; that reveals if an update in any of the dependencies causes the pipeline to fail in the absence of new code commits.&lt;/p&gt;
&lt;h2 id="case-example-mariadb-1069-incompatibility-with-percona-xtradb-57-temporary-table-format"&gt;&lt;a href="#case-example-mariadb-1069-incompatibility-with-percona-xtradb-57-temporary-table-format" class="header-anchor"&gt;&lt;/a&gt;Case example: MariaDB 10.6.9 incompatibility with Percona XtraDB 5.7 temporary table format
&lt;/h2&gt;&lt;p&gt;To illustrate GitLab CI in action, let&amp;rsquo;s take a look at a recent example in which it prevented breaking upgrades for (some) Debian users. In June 2022, the &lt;a class="link" href="https://salsa.debian.org/mariadb-team/mariadb-server/-/pipelines/386929" target="_blank" rel="noopener"
&gt;Salsa-CI pipeline for MariaDB 10.6.8&lt;/a&gt; was all green and upgrades from Percona XtraDB 5.7 were passing flawlessly. However, after importing a new upstream minor maintenance release on August 16th, the &lt;a class="link" href="https://salsa.debian.org/mariadb-team/mariadb-server/-/pipelines/411764" target="_blank" rel="noopener"
&gt;Salsa-CI pipeline for MariaDB 10.6.9&lt;/a&gt; started failing on the Percona upgrade. From the &lt;a class="link" href="https://salsa.debian.org/mariadb-team/mariadb-server/-/jobs/3110875" target="_blank" rel="noopener"
&gt;CI job log&lt;/a&gt;, it was easy to see that MariaDB failed to start with the &lt;code&gt;/var/lib/mysql&lt;/code&gt; data directory from Percona XtraDB 5.7. From the build artifacts, it was easy to inspect the precise error message from the MariaDB server (as build artifacts are configured to expire after 30 days, I can&amp;rsquo;t link to them for reference).&lt;/p&gt;
&lt;p&gt;&lt;img src="https://optimizedbyotto.com/post/gitlab-mariadb-debian/mariadb-percona-job-3110875-failure.png"
width="1548"
height="1302"
srcset="https://optimizedbyotto.com/post/gitlab-mariadb-debian/mariadb-percona-job-3110875-failure_hu8037768173750809726.png 480w, https://optimizedbyotto.com/post/gitlab-mariadb-debian/mariadb-percona-job-3110875-failure_hu2608142498116434987.png 1024w, https://optimizedbyotto.com/post/gitlab-mariadb-debian/mariadb-percona-job-3110875-failure.png 1548w"
loading="lazy"
alt="MariaDB Server startup failure on upgrade from Percona XtraDB Server"
class="gallery-image"
data-flex-grow="118"
data-flex-basis="285px"
&gt;
&lt;/p&gt;
&lt;p&gt;This quickly led to filing &lt;a class="link" href="https://jira.mariadb.org/browse/MDEV-29321" target="_blank" rel="noopener"
&gt;MDEV-29321&lt;/a&gt; on August 18th. As the failure was caught by CI, it was easy to provide the steps to reproduce in the bug report, along with logs and CI job references. This helped the upstream developer to immediately pinpoint the issue and post a patch to fix it, which was &lt;a class="link" href="https://salsa.debian.org/illuusio/mariadb-server/-/jobs/3122466" target="_blank" rel="noopener"
&gt;validated by a Salsa-CI test run&lt;/a&gt; on a temporary development branch. The fix was &lt;a class="link" href="https://salsa.debian.org/mariadb-team/mariadb-server/-/commit/39fe420b64afa157108dbaced14821cc9652ff3d" target="_blank" rel="noopener"
&gt;applied on mainline&lt;/a&gt; in the Debian packaging repository of MariaDB on August 24nd.&lt;/p&gt;
&lt;p&gt;Such a quick turnaround time would not have been possible without a good CI system. &lt;strong&gt;The process clearly benefited from the very clear user interface of GitLab CI&lt;/strong&gt; that made it easy for all parties – even those who didn&amp;rsquo;t have prior experience of GitLab CI – to read the pipeline and inspect the logs.&lt;/p&gt;
&lt;h2 id="computers-are-good-at-repeating-the-same-tasks-over-and-over-humans-are-good-at-exploring-visual-things"&gt;&lt;a href="#computers-are-good-at-repeating-the-same-tasks-over-and-over-humans-are-good-at-exploring-visual-things" class="header-anchor"&gt;&lt;/a&gt;Computers are good at repeating the same tasks over and over; humans are good at exploring visual things
&lt;/h2&gt;&lt;p&gt;Through the years, Salsa-CI (GitLab CI) has proven incredibly valuable – it has been able to catch the tiniest packaging mistake immediately as the commit is pushed to Salsa (GitLab) and the git mainline stays in a condition that can be shipped at any time. This makes it possible to import new upstream releases at any given time, and to upload them to Debian with a high confidence that nothing will break. Before Salsa-CI, the MySQL and MariaDB packages had hundreds of open bugs in Debian (and also Ubuntu, which inherits the packages from Debian). &lt;strong&gt;Now genuine new bugs are rare, staying consistently in the lower tens.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;If you are developing software professionally but not using CI in all your projects, you should definitely start now. Computers excel at running repetitive tasks over and over, and CI is exactly that. No human would have the diligence to always test everything. Humans tend to test code changes only when they have doubts, and thus most &lt;em&gt;bugs slip in when a human makes a small change they don&amp;rsquo;t think can break anything – and then it breaks&lt;/em&gt;. These cases always come as a surprise, and you don&amp;rsquo;t want to find it out in production use but rather delegate it to a CI system to validate everything.&lt;/p&gt;
&lt;p&gt;What humans are good at is visual inspection. A large part of our brain cortex is devoted to vision, so we should leverage it. GitLab CI does a great job converting the repetitive CI test run results into pipelines with various colors and symbols, perfect for human consumption. Humans also have an eye for beauty and elegance, and I personally enjoy exploring the GitLab CI pipelines. If you haven&amp;rsquo;t already, please try it out, and enjoy the warm fuzzy feeling of seeing all green pipelines!&lt;/p&gt;
&lt;p&gt;&lt;img src="https://optimizedbyotto.com/post/gitlab-mariadb-debian/mariadb-salsa-ci-badges.png"
width="1542"
height="498"
srcset="https://optimizedbyotto.com/post/gitlab-mariadb-debian/mariadb-salsa-ci-badges_hu14464022739993467323.png 480w, https://optimizedbyotto.com/post/gitlab-mariadb-debian/mariadb-salsa-ci-badges_hu5879156277011565549.png 1024w, https://optimizedbyotto.com/post/gitlab-mariadb-debian/mariadb-salsa-ci-badges.png 1542w"
loading="lazy"
alt="GitLab badges on the Salsa-CI MariaDB project page"
class="gallery-image"
data-flex-grow="309"
data-flex-basis="743px"
&gt;
&lt;/p&gt;
&lt;h2 id="so-easy-and-intuitive-you-can-start-using-it-without-reading-lengthy-manuals"&gt;&lt;a href="#so-easy-and-intuitive-you-can-start-using-it-without-reading-lengthy-manuals" class="header-anchor"&gt;&lt;/a&gt;So easy and intuitive you can start using it without reading lengthy manuals
&lt;/h2&gt;&lt;p&gt;This blog was just a sneak peek into what GitLab CI can do – there are so many useful features, such as scheduled pipeline runs (to detect regressions introduced from updated dependencies), automatic repository mirroring, and many UI goodies, such as badges. I recommend skimming through the &lt;a class="link" href="https://docs.gitlab.com/ee/ci/" target="_blank" rel="noopener"
&gt;GitLab CI documentation&lt;/a&gt; and in particular the &lt;a class="link" href="https://docs.gitlab.com/ee/ci/yaml/" target="_blank" rel="noopener"
&gt;&lt;code&gt;.gitlab-ci.yml&lt;/code&gt; reference&lt;/a&gt; and then just start playing around with it. GitLab.com has a free plan for basic use which (unlike GitHub.com) also includes private repositories.&lt;/p&gt;
&lt;p&gt;In short, GitLab CI makes the life of a programmer (or a team of programmers) significantly more productive by ensuring that tests run all the time, failures are quick to detect, and the whole test system is handy to maintain and evolve together with the code. Using it feels like a breeze, both because the features work just like one would expect and because the user interface is very easy to navigate. There is rarely a need to read documentation to get started – just try GitLab CI today and discover its power yourself!&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Want to read more? See also the &lt;a class="link" href="https://about.gitlab.com/blog/2023/09/19/debian-customizes-ci-tooling-with-gitlab/" target="_blank" rel="noopener"
&gt;GitLab.com blog post &amp;ldquo;Debian customizes CI tooling with GitLab&amp;rdquo;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;</description>
    </item>
    <item>
      <title>Stop the senseless killing</title>
      <link>https://optimizedbyotto.com/post/stop-senseless-killing/</link>
      <pubDate>Sun, 18 Sep 2022 00:00:00 +0000</pubDate>
      <guid>https://optimizedbyotto.com/post/stop-senseless-killing/</guid>
      <description>&lt;img src="https://optimizedbyotto.com/post/stop-senseless-killing/featured-image.jpg" alt="Featured image of post Stop the senseless killing" /&gt;&lt;p&gt;In over 22 years of working with Linux systems, I have often seen people use excessive force to kill various computer programs, causing unnecessary suffering.&lt;/p&gt;
&lt;p&gt;A typical example would be:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-0"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-0" style="display:none;"&gt;$ killall -9 mysqld&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ killall -9 mysqld&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;Please &lt;strong&gt;stop&lt;/strong&gt; using this command. Both &lt;code&gt;killall&lt;/code&gt; and the parameter &lt;code&gt;-9&lt;/code&gt; are harmful when dealing with programs that store data, like the MySQL or MariaDB database, and better alternatives exist.&lt;/p&gt;
&lt;h2 id="avoid-killing-in-vain"&gt;&lt;a href="#avoid-killing-in-vain" class="header-anchor"&gt;&lt;/a&gt;Avoid killing in vain
&lt;/h2&gt;&lt;p&gt;The &lt;code&gt;9&lt;/code&gt; means signal 9, which is SIGKILL. All standard Linux signals can easily be listed with:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-1"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-1" style="display:none;"&gt;$ kill -L
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ kill -L
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 1&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGHUP 2&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGINT 3&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGQUIT 4&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGILL 5&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGTRAP
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt; 6&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGABRT 7&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGBUS 8&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGFPE 9&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGKILL 10&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGUSR1
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;11&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGSEGV 12&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGUSR2 13&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGPIPE 14&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGALRM 15&lt;span style="color:#f92672"&gt;)&lt;/span&gt; SIGTERM&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The Linux kernel sends most of these signals to the program itself, and we expect programs to have code to handle various signals. One exception is signal number 9 (&lt;a class="link" href="https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html#index-SIGKILL" target="_blank" rel="noopener"
&gt;SIGKILL&lt;/a&gt;). We use the SIGKILL signal to terminate the program immediately. The program cannot handle, block, or ignore it. Therefore, it is always fatal. If &lt;code&gt;kill&lt;/code&gt; is issued without parameters, it will default to signal 15 (&lt;a class="link" href="https://www.gnu.org/software/libc/manual/html_node/Termination-Signals.html#index-SIGTERM" target="_blank" rel="noopener"
&gt;SIGTERM&lt;/a&gt;) and the Linux kernel will request the running process to terminate itself and clean file pointers and other resources it was using. Thus, always &lt;em&gt;prefer SIGTERM&lt;/em&gt; and &lt;em&gt;only use SIGKILL as a last resort&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Violently killing programs that deal with data storage might cause writing into a file to abruptly stop halfway, leading to inconsistent data or even unusable corrupted files. For example, even if the program is not a database or similar, senseless immediate killing leads to everything dropping mid-flight, potentially causing unnecessary harm to other programs communicating over the same network. In some cases, albeit rare, poorly terminated programs may turn into zombie processes, showing up in the Linux process listing as &lt;code&gt;&amp;lt;defunct&amp;gt;&lt;/code&gt;. If that happens, the only way to clean them is to restart the entire operating system. So, please, do not kill without trying other means first.&lt;/p&gt;
&lt;h2 id="dont-be-senseless"&gt;&lt;a href="#dont-be-senseless" class="header-anchor"&gt;&lt;/a&gt;Don&amp;rsquo;t be senseless
&lt;/h2&gt;&lt;p&gt;Let&amp;rsquo;s dive into the first part of the command in the opening paragraph, which is also wrong.&lt;/p&gt;
&lt;p&gt;The command &lt;code&gt;killall&lt;/code&gt; has been in Unix and all its descendants, such as Linux, since 1983. It does the job. However, we also have modern tools, which I prefer, like &lt;a class="link" href="https://en.wikipedia.org/wiki/Pkill" target="_blank" rel="noopener"
&gt;pkill&lt;/a&gt; from 1998.&lt;/p&gt;
&lt;p&gt;The program &lt;code&gt;pkill&lt;/code&gt; is superior because it has the parameter &lt;code&gt;-e&lt;/code&gt; to display what is killed (or terminated). Those who still use &lt;code&gt;killall&lt;/code&gt; but don&amp;rsquo;t want to be senseless also use variations of &lt;code&gt;ps ax | grep &amp;lt;processname&amp;gt;&lt;/code&gt; to see which processes are running before and after the killing.&lt;/p&gt;
&lt;p&gt;Compare the clarity in these identical examples:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-2"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-2" style="display:none;"&gt;$ killall mysqld
$ killall mysqld
mysqld: no process found&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ killall mysqld
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ killall mysqld
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mysqld: no process found&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code&gt;killall&lt;/code&gt; command remains silent if it did something and only reports errors. In contrast, &lt;code&gt;pkill&lt;/code&gt; reports which process it terminated and is only silent if it didn&amp;rsquo;t do anything.&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-3"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-3" style="display:none;"&gt;pkill -e mysqld
mysqld_safe killed (pid 3911)
mysqld killed (pid 4011)
$ pkill -e mysqld
(nothing)&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;pkill -e mysqld
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mysqld_safe killed &lt;span style="color:#f92672"&gt;(&lt;/span&gt;pid 3911&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mysqld killed &lt;span style="color:#f92672"&gt;(&lt;/span&gt;pid 4011&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pkill -e mysqld
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;nothing&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;h2 id="the-bonus-of-being-sensible"&gt;&lt;a href="#the-bonus-of-being-sensible" class="header-anchor"&gt;&lt;/a&gt;The bonus of being sensible
&lt;/h2&gt;&lt;p&gt;A bonus for system administrators using &lt;code&gt;pkill&lt;/code&gt; is they could learn something valuable by observing the effects of their commands. For example, a database sysadmin could encounter the following:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-4"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-4" style="display:none;"&gt;$ pkill -9 -e mariadbd
mariadbd killed (pid 5281)
$ pkill -9 -e mariadbd
mariadbd killed (pid 5383)
$ pkill -9 -e mariadbd
mariadbd killed (pid 5412)
$ pkill -e mariadbd
mariadbd killed (pid 5497)
$ pkill -e mariadbd
(nothing)&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pkill -9 -e mariadbd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mariadbd killed &lt;span style="color:#f92672"&gt;(&lt;/span&gt;pid 5281&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pkill -9 -e mariadbd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mariadbd killed &lt;span style="color:#f92672"&gt;(&lt;/span&gt;pid 5383&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pkill -9 -e mariadbd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mariadbd killed &lt;span style="color:#f92672"&gt;(&lt;/span&gt;pid 5412&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pkill -e mariadbd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;mariadbd killed &lt;span style="color:#f92672"&gt;(&lt;/span&gt;pid 5497&lt;span style="color:#f92672"&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pkill -e mariadbd
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#f92672"&gt;(&lt;/span&gt;nothing&lt;span style="color:#f92672"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;With MariaDB, if the main server abruptly dies (as with signal 9/SIGKILL), the wrapper &lt;code&gt;mysqld_safe&lt;/code&gt; (if used) will detect that and automatically restart the server because it assumes it died during a crash and knows getting it back up and running is desirable. However, when the proper signal 15/SIGTERM is used (default in &lt;code&gt;pkill&lt;/code&gt; when no signal is defined), the &lt;code&gt;mariadbd&lt;/code&gt; process intentionally shuts itself down. The wrapper respects that and understands that automatically restarting it would not make sense.&lt;/p&gt;
&lt;h2 id="the-procps-package"&gt;&lt;a href="#the-procps-package" class="header-anchor"&gt;&lt;/a&gt;The procps package
&lt;/h2&gt;&lt;p&gt;The command &lt;code&gt;pkill&lt;/code&gt; is part of the &lt;a class="link" href="https://gitlab.com/procps-ng/procps" target="_blank" rel="noopener"
&gt;procps suite&lt;/a&gt;. You can find it by default on most Linux systems, but if you don&amp;rsquo;t have it, run &lt;code&gt;apt install procps&lt;/code&gt; or &lt;code&gt;yum install procps&lt;/code&gt; to get it. The suite also includes the command &lt;code&gt;pgrep&lt;/code&gt;, which replaces manual &lt;code&gt;ps ax | grep &amp;lt;processname&amp;gt;&lt;/code&gt; invocations, as mentioned above.&lt;/p&gt;
&lt;p&gt;An example of &lt;code&gt;pgrep&lt;/code&gt; in action:&lt;/p&gt;
&lt;div class="codeblock "&gt;
&lt;header&gt;
&lt;span class="codeblock-lang"&gt;shell&lt;/span&gt;
&lt;button
class="codeblock-copy"
data-id="codeblock-id-5"
data-copied-text="Copied!"
&gt;
Copy
&lt;/button&gt;
&lt;/header&gt;
&lt;code id="codeblock-id-5" style="display:none;"&gt;$ pgrep -af mysqld
5577 /bin/sh /usr/bin/mysqld_safe
5676 /usr/sbin/mariadbd --basedir=/usr --datadir=/var/lib/mysql --plugin-dir=/usr/lib/mysql/plugin --user=mysql --skip-log-error --pid-file=/run/mysqld/mysqld.pid --socket=/run/mysqld/mysqld.sock
5677 logger -t mysqld -p daemon error&lt;/code&gt;&lt;div&gt;&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;"&gt;&lt;code class="language-shell" data-lang="shell"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;$ pgrep -af mysqld
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;5577&lt;/span&gt; /bin/sh /usr/bin/mysqld_safe
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;5676&lt;/span&gt; /usr/sbin/mariadbd --basedir&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr --datadir&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/var/lib/mysql --plugin-dir&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/usr/lib/mysql/plugin --user&lt;span style="color:#f92672"&gt;=&lt;/span&gt;mysql --skip-log-error --pid-file&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/run/mysqld/mysqld.pid --socket&lt;span style="color:#f92672"&gt;=&lt;/span&gt;/run/mysqld/mysqld.sock
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#ae81ff"&gt;5677&lt;/span&gt; logger -t mysqld -p daemon error&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;&lt;/div&gt;
&lt;p&gt;To see the complete list of options, run &lt;code&gt;pkill --help&lt;/code&gt; and &lt;code&gt;pgrep --help&lt;/code&gt; or &lt;code&gt;man pkill&lt;/code&gt; to read &lt;a class="link" href="https://man7.org/linux/man-pages/man1/pgrep.1.html" target="_blank" rel="noopener"
&gt;the man page&lt;/a&gt;. I recommend all system administrators make using &lt;code&gt;--help&lt;/code&gt; and &lt;code&gt;man &amp;lt;command&amp;gt;&lt;/code&gt; from the command line a general habit to act more sensibly in all command-line actions.&lt;/p&gt;
&lt;p&gt;Most importantly, don&amp;rsquo;t use signal 9 (SIGKILL) on databases other than as the last resort. Please avoid any senseless killings!&lt;/p&gt;</description>
    </item>
    <item>
      <title>About me</title>
      <link>https://optimizedbyotto.com/about/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://optimizedbyotto.com/about/</guid>
      <description>&lt;p&gt;&lt;img src="https://optimizedbyotto.com/about/otto-kekalainen.jpg"
width="395"
height="600"
srcset="https://optimizedbyotto.com/about/otto-kekalainen.jpg 395w"
loading="lazy"
alt="Otto"
class="gallery-image"
data-flex-grow="65"
data-flex-basis="158px"
&gt;
&lt;/p&gt;
&lt;p&gt;I am a results-driven technology executive with 25+ years of professional experience and a rich blend of strategic leadership, product development expertise, and deep-seated passion for open-source software. I am currently working as an independent consultant. I was previously a Software Development Manager for the core engine team delivering the Amazon RDS for MySQL and MariaDB database services. Before that, I was the CEO of &lt;a class="link" href="https://seravo.com" target="_blank" rel="noopener"
&gt;Seravo&lt;/a&gt; until 2021, and the CEO of &lt;a class="link" href="https://mariadb.org/" target="_blank" rel="noopener"
&gt;MariaDB Foundation&lt;/a&gt; until 2018.&lt;/p&gt;
&lt;p&gt;I have a strong bias for action and a proven history of transforming and growing organizations by leveraging a unique blend of technological acumen and business strategy, which I hope to share in this blog. My goal is to help readers gain a deeper understanding of open source software, software engineering in general, management in technical fields, business improvement, life hacks, and much more.&lt;/p&gt;
&lt;p&gt;I like spending my free time hiking, running and contributing to various open source projects. I am an active Debian and Ubuntu developer. See my &lt;a class="link" href="https://github.com/ottok" target="_blank" rel="noopener"
&gt;GitHub&lt;/a&gt;, &lt;a class="link" href="https://gitlab.com/ottok" target="_blank" rel="noopener"
&gt;GitLab&lt;/a&gt; and &lt;a class="link" href="https://salsa.debian.org/otto" target="_blank" rel="noopener"
&gt;Salsa&lt;/a&gt; profiles for recent contributions.&lt;/p&gt;
&lt;p&gt;You can follow me on &lt;a class="link" href="https://mastodon.social/@ottok" target="_blank" rel="noopener"
&gt;Mastodon&lt;/a&gt;, &lt;a class="link" href="https://twitter.com/OttoKekalainen" target="_blank" rel="noopener"
&gt;Twitter&lt;/a&gt;, &lt;a class="link" href="https://warpcast.com/ottok" target="_blank" rel="noopener"
&gt;Farcaster&lt;/a&gt;, &lt;a class="link" href="https://bsky.app/profile/ottoke.bsky.social/" target="_blank" rel="noopener"
&gt;Bluesky&lt;/a&gt; or connect on &lt;a class="link" href="https://linkedin.com/in/ottokekalainen" target="_blank" rel="noopener"
&gt;LinkedIn&lt;/a&gt;.&lt;/p&gt;
&lt;h2 id="lets-connect"&gt;&lt;a href="#lets-connect" class="header-anchor"&gt;&lt;/a&gt;Let&amp;rsquo;s Connect
&lt;/h2&gt;&lt;p&gt;Interested in discussing open source strategy, Debian contributions, or how I can help your organization?&lt;/p&gt;
&lt;p&gt;&lt;a class="link" href="https://cal.com/ottok" target="_blank" rel="noopener"
&gt;&lt;strong&gt;Book a chat with me on Cal.com&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;You can schedule a quick 15-minute introduction call for free, or book a 1-hour consultation for in-depth problem-solving.&lt;/p&gt;
&lt;p&gt;You can also reach me by e-mail to &lt;em&gt;otto at debian.org&lt;/em&gt;.&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
