Use guilt, and don't feel any!

August 10, 2023

Guilt is pretty cool. I’m talking about the set of scripts to manage patch queues on top of a git branch, of course. Oh, you haven’t heard of it? Well, let me tell you all about it!

In this post I’m going to assume you know what git is and how to use it. If you don’t, let me know and I might write an “intro to git” article. Maybe I’ll write it even if nobody asks for it, we’ll see.

Intro to patching

If you’re not familiar with patches, it’s basically what git diff outputs:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
diff --git a/test.c b/test.c
--- a/test.c
+++ b/test.c
@@ -40,6 +40,11 @@ void hello(const char *) {
     {
         int i = 0;
+        int j = 4;
 
-        i = 4;
+        i = 5;
+        j = 4 * i;
+        i = sqrt(j);
+        i = sqrt(i);
+
        return i * 4;
     }
@@ -60,7 +65,7 @@ int sum(int i, int j) {
     {
         int sum;
         // the easy part
-        sum = i + i;
+        sum = i + j;
         // the tricky part
         return sum;
     }

In other words, it’s just some file that describes changes in some other files. This makes it simple to distribute and apply arbitrary changes to source code. Of course, it’s possible for a given patch to be inapplicable to your current version of the source code, and in that case you end up with something similar to a git merge conflict. But this is just the nature of these things. A tool that would allow you to avoid such conflicts completely probably lies in the domain of science fiction.

What is guilt?

The main idea of guilt is to allow users to store their commits as patch files. This provides the following benefits:

Of course, all of the above is possible with just plain git. However, guilt makes it all so much easier.

Taking it a step further

Everything I’ve written above applies to the last release of guilt. There were some features I wanted it to have, so I started my own fork. The original author has abandoned guilt quite some time ago (more than 5 years at the time of this writing), so all we have now is forks.

So far I’ve implemented some small quality of life improvements and one rather large feature: patch splitting. The idea is to allow the user to take some patch and split it into multiple ones based on some logic. The user can manually select the changes or rely on some rules, e.g. “move changes in different files to different patches”.

This feature enables a workflow where you do everything in one patch and then clean it up and turn it into a proper patch series before submitting it upstream or pushing to your repository. It may sound like extra effort, but it’s not always possible to plan ahead, especially when you’re not intimately familiar with the code base. You can look at the code all you want, but it’s very likely that you won’t have much progress until you start experimenting with the code. At some point one of these experiments will turn out to be what you need, and then you just need to clean up. That’s where this feature shines.

There is a lot more that can be said about patch splitting. e.g. how to set it up. I’m afraid, the process is a little bit involved right now, so I’ll leave this subject to another article.

The story of my fork doesn’t end here, though. I’ve got many more ideas I hope to implement at some point, so stay tuned!