diff --git a/content/posts/great-commits.md b/content/posts/great-commits.md
new file mode 100644
index 0000000..82c8a20
--- /dev/null
+++ b/content/posts/great-commits.md
@@ -0,0 +1,417 @@
+---
+title: Making great commits
+date: 2023-04-17
+tags: [programming, git]
+sources:
+ -
+ -
+ -
+ -
+ -
+---
+
+A well-structured git log is key to project's maintainability; it provides insight into when and why things were done,
+for future maintainers of the project, ... and yet, so many people pay very little attention to how their commits are
+structured.
+
+The problem isn't necessarily that they don't even attempt to write good commit messages, it's that the commit they
+made is not actually easy to compose a commit message for.
+
+Another, perhaps even bigger issue is that a lot of people don't even know that there's a reason to care about their
+git history, because they simply don't see a benefit in it. The problem with this argument is that these people have
+simple never explored git enough, and therefore aren't even familiar with the benefits they could gain.
+
+So then, in this post, I'll try to explain both what are the benefits that you can get, and how to make your commits
+clean and easy to read and find in git history later on.
+
+## Commit message
+
+The purpose of every commit is always to simply represent some change that was made in the source code.
+
+The commit message should then describe this change, however what many people get wrong is that they just state
+**what** was changed, without explaining **why** it was changed. There is always a reason for why a change is made, and
+while the contents of the commit (being the actual changes made in the code - diff) can tell you what was done, the
+only way to figure out why it was done, is through the commit message.
+
+Therefore, when thinking of a good commit message, you should always ask yourself not just "What does this commit
+change?", but also, and perhaps more importantly, ask "Why is this change necessary?" and "What does this change
+achieve?".
+
+Knowing why something was added can then be incredibly beneficial for someone looking at `git blame`, which allows you
+to find out the commit that was responsible for adding/modifying any particular line. In vast majority of cases, when
+you look at git blame, you're not interested in what that single line of code is doing, but rather why it's even there.
+
+Without having this information in the commit itself, you'd likely have to go look for the actual pull request that
+added that commit, and read it's description, which might not even contain that reason anyway.
+
+### Commit isn't just the first line
+
+A huge amount of people are used to committing changes with a simple `git commit -m "My message"`, and while this is
+enough and it's perfectly in many cases, sometimes you just need more space to describe what a change truly achieves.
+
+Surprisingly, many people don't even know that they can make a commit that has more in it's message than just the
+title/first line, which then leads to poorly documented changes, because single line sometimes simply isn't enough. To
+create a commit with a bigger commit message, you can simply run `git commit` without the `-m` argument. This should
+open your terminal text editor, allowing you to write out the message in multiple lines.
+
+{{< notice tip >}}
+I'd actually recommend making the simple `git commit` the default way you make new commits, since it invites you to
+write more about it, by just seeing that you have that space available. We usually don't even know what exactly we'll
+write in our new commit message before getting to typing it out, and knowing you have that extra space if you need it
+will naturally lead to using it, even if you didn't know you needed it ahead of time.
+{{< /notice >}}
+
+That said, not every commit requires both a subject and a body, sometimes a single line is fine, especially when the
+change is so simple that no further context is necessary, and including some would just waste the readers time. For
+example:
+
+```markdown
+Fix typo in README
+```
+
+In this case, there's no need for anything extra. Some people like to include what the typo was, but if you want to know
+that, you can use `git show` or `git diff`, or `git log --patch`, showing you the actual changes made to the code, so
+this information isn't necessary either. So, while in some cases, having extra context can be very valuable, you also
+shouldn't overdo it.
+
+### Make commits searchable
+
+It can be very beneficial to include some keywords that people could then easily find this commit by, when searching
+for changes in the codebase. As an example, you can include the name of an exception, such as `InvalidDataStreamError`,
+if your commit addresses a bug that causes this exception.
+
+You can then add an explanation on why this error was getting raised, and why your change fixed that. With that, anyone
+who found your commit by searching for this exception can immediately find out what this exception is, why was it
+getting raised and what to do to fix it.
+
+This is especially useful with internal API, whether it's custom exceptions, or just functions or names of classes.
+People don't search the commit history very often, but if you do encounter a case where you think someone might perform
+a search for at some point, it's worth it to make it as easy for them as you can.
+
+### Make it exciting to read
+
+I sometimes find myself going through random commit messages of a project, just to see what is the development like,
+and explore what are the kinds of changes being introduced. Even more often, I look there to quickly see what was
+changed, to bring myself up to date with the project.
+
+When doing this, I'm always super thankful to people who took the time to for example include the debug process of how
+they figured out X was an issue, or where they explain some strange behavior that you might not expect to be happening.
+
+These kinds of commits make the history a fun place to go and read, and it allows you to teach someone something about
+the language, the project, or programming in general, making everyone in your team a bit smarter!
+
+### Follow the proper message structure
+
+Git commits should be written in a very specific way. There's a few rules to follow:
+
+- **Separate the subject/title from body with a blank line** (Especially useful when looking at `git log --oneline`,
+ as without the blank line, lines below are considered as parts of the same paragraph, and shown together)
+- **Limit the subject line to 50 characters** (Not a hard limit, but try not going that much longer. This limit ensures
+ readability, and forces the author to think about the most concise way to explain what's going on. Note: If you're
+ having trouble summarizing, you might be committing too much at once)
+- **Capitalize the subject line**
+- **Don't end the subject line with a period**
+- \*Use imperative mood in subject\*\* (Imperative mood means "written as if giving a command/instruction" i.e.: "Add
+ support for X", not "I added support for X" or "Support for X was added", as a rule of thumb, a subject message
+ should be able to complete the sentence: "If implemented, this commit will ...")
+- **Wrap body at 72 characters** (We usually use `git log` to print out the commits into the terminal, but it's output
+ isn't wrapped, and going over the terminals width can cause a pretty messy output. The recommended maximum width for
+ terminal text output is 80 characters, but git tools can often add indents, so 72 characters is a pretty sensible
+ maximum)
+- **Mention the "what" and the "why", but not the "how"** (A commit message shouldn't contain implementation details,
+ if people want to see those, whey should look at the changed code diff directly)
+
+If you want to, you can consider using markdown in your commit message, as most other programmers will understand it as
+it's a commonly used format, and it's a great way to bring in some more style, improving readability. In fact, if you
+view the commit from a site like GitHub, it will even render the markdown properly for you.
+
+For example:
+
+```markdown
+Summarize changes in around 50 characters or less
+
+More detailed explanatory text, if necessary. Wrap it to about 72
+characters or so. In some contexts, the first line is treated as the
+subject of the commit and the rest of the text as the body. The
+blank line separating the summary from the body is critical (unless
+you omit the body entirely); various tools like `log`, `shortlog`
+and `rebase` can get confused if you run the two together.
+
+Explain the problem that this commit is solving. Focus on why you
+are making this change as opposed to how (the code explains that).
+Are there side effects or other unintuitive consequences of this
+change? Here's the place to explain them.
+
+Further paragraphs come after blank lines.
+
+- Bullet points are okay, too
+
+- Typically a hyphen or asterisk is used for the bullet, preceded
+ by a single space, with blank lines in between, but conventions
+ vary here
+
+If you use an issue tracker, put references to them at the bottom,
+like this:
+
+Resolves: #123
+See also: #456, #789
+```
+
+## Make "atomic" commits
+
+_Atomic: of or forming a single irreducible unit or component in a larger system._
+
+The term "atomic commit" means that the commit is only representing a single change, that can't be further reduced into
+multiple commits, i.e. this commit only handles a single change. Ideally, it should be possible to sum up the changes
+that a good commit makes in a single sentence.
+
+That said, the irreducibility should only apply to the change itself, obviously, making a commit for every line of code
+wouldn't be very clean. Having a commit only change a small amount of code isn't what makes it atomic. While the commit
+certainly can be small, it can just as well be a commit that's changing thousands of lines. (That said, you should have
+some really good justification for it if you're actually making commits that big.)
+
+The important thing is that the commit is only responsible for addressing a single change. A counter-example would be
+a commit that adds a new feature, but also fixes a bug you found while implementing this feature, and also improves the
+formatting of some other function, that you encountered along the way. With atomic commits, all of these actions would
+get their own standalone commits, as they're unrelated to each other, and describe several different changes.
+
+But making atomic commits aren't just about splitting thins up to only represent single changes, indeed, while they
+should only represent the smallest possible change, it should also be a "complete" change. This means that a commit
+responsible for changing how some function works in order to improve performance should ideally also update the
+documentation, make the necessary adjustments to unit-tests so they still pass, and update all of the references to
+this updated function to work properly after this change.
+
+So an atomic commit is a commit representing a single small (ideally an irreducible) change, that's fully implemented
+and integrates well with the rest of the codebase.
+
+### Partial adds
+
+Many people tend to always simply use `git add -A` (or `git add .`), to stage all of the changes they made, and then
+create a commit with it all.
+
+In an ideal world, where you only made the changes you needed to make for this single atomic commit, this would work
+pretty well, and while sometimes this is the case, in most cases, you will likely have say fixed some bug you found
+alongside, or a typo you noticed, etc.
+
+When that happens, you should know that you can instead make a partial add, and only stage the changes that belong into
+the commit you're about to make. The simple case is when you have some unrelated changes, but they're all in different
+files, and don't affect this commit. In that case, you can use `git add /path/to/file`, to only stage those files that
+you need, leaving the unrelated ones alone.
+
+But this is rarely the case, instead, you usually have a single file, that now contains both a new feature, and some
+unrelated quick bugfix. In that case, you can use the `-p`/`--patch` flag: `git add -p /path/to/file`. This will let you
+interactively go over every "hunk" (a chunk of code, with changes close to each other), and decide on whether to accept
+it (hence staging it), split it into more chunks, skip it, or even modify it in your editor, allowing you to remove the
+intertwined code for the bugfix from the code for your feature that you're committing now.
+
+You can then make the feature commit, that only contains the changes related to it, and then create another commit, that
+only contains the bugfix related changes.
+
+This git feature has slowly became one of my favorite tools, and I use it almost every time I need to commit something,
+as it also allows me to quickly review the changes I'm making, before they make it into a commit, so it can certainly be
+worth using, even if you know you want to commit the entire file.
+
+## Stop making fixing commits
+
+A very common occurrence I see in a ton of different projects is people making sequences of commits that go like:
+
+- Fix bug X
+- Actually fix bug X
+- Fix typo in variable name
+- Sort imports
+- Follow lint rules
+- Run auto-formatter
+
+While people can obviously mess up sometimes, and just not get something right on the first try, a fixing commit like
+this is actually not the only way to solve this happening.
+
+Instead of making a new commit, you can actually just amend the original. To do this, we can use the `git commit
+--amned`, which will add your staged changes into the previous commit, even allowing you to change the message of that
+old commit.
+
+Not only that, if you've already made another commit, but now found something that needs changing in the commit before
+that, you can use interactive rebase with `git rebase -i HEAD~3`, allowing you to change the last 3 commits, or even
+completely remove some of those commits.
+
+For more on history rewriting, I'd recommend checking the [official
+documentation](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History)
+
+### Force pushing
+
+{{< notice warning >}}
+Changing history is a great tool to clean up after yourself, it works best with local changes, i.e. with changes you
+haven't yet pushed.
+
+Even though changing already pushed history is possible, it requires a "force push" (`git push --force`). These kinds of
+pushes are something you need to be very careful about, as someone might have already pulled the changes, which you then
+overwritten with your force push. Now, they might've done some work from the point at which they pulled, but then they
+find out that this point is actually gone from the history, and they can't push their changes back. So now, they'll need
+to undo their changes, pull the force pushed branch, and carry the work over, which can be very annoying.
+{{< /notice >}}
+
+My recommendation to avoid force pushing is to reduce the amount of (regular) pushes you do completely. If your changes
+are only local, rewriting history is easy, and won't break anyone else's workflow, but the moment you push, the changes
+are public, and anyone might've pulled them already.
+
+This especially applies when you're pushing directly to master/main branch, or other shared branch which multiple people
+are working with. If this is your personal branch (like a feature branch you're responsible for), force-pushing there is
+generally ok, though you might still have people using your branch since they wanted to try out a feature early, or
+review the changes from their editor. So even with personal branches, it's not always safe to force-push.
+
+My rule of thumb is to avoid pushing until the feature is fully complete, as that allows you to change anything during
+the development. Perhaps some change you made no longer makes sense, because you realized you won't actually be using it
+in the way you anticipated, or you found a bug with it later on. You can now simply rewrite your local history, and
+rather than making a fixing commit, it'd be as if the bug was never there.
+
+Once you do finally decide to push, it's a good practice to run any auto-formatters and linters, and perhaps even
+unit-tests. You can also take a quick peek at `git log`, to make sure you didn't make any typos. Then, only if all of
+those local toolings passed should you actually push your version.
+
+{{< notice tip >}}
+If you do need to force-push, try to at least do it as quickly as possible. The more time that has passed since your
+normal push, the more likely it is that someone have already clonned/pulled those changes. If you force-push within just
+a few seconds after pushing, it's not very likely that someone has pulled already, and so you won't break anyone's
+version.
+{{< /notice >}}
+
+## Benefits
+
+Alright, now that we've seen some of the best practices for making new commits, let's explore the benefits that we can
+actually gain by following these.
+
+### A generally improved development workflow
+
+I can confidently say, that in my experience, learning to make good git commits made me a much better programmer
+overall. That might sound surprising, but it's really true.
+
+The reason for this is that making good commits, that only tackle one issue at a time naturally helps you to think about
+how to split your problem up into several smaller "atomic" problems, and make commits addressing that single part, after
+which you move to another. This is actually one of very well known approaches to problem-solving, called "divide and
+conquer" method, because you divide your problem into really small, trivially simple chunks, which you solve one by one.
+
+Learning and getting used to doing this just makes you better at problem solving in general, and while git commits
+certainly aren't the only way to get yourself to think like this, it's honestly one of the simplest ones, and you become
+good at git while at it!
+
+### Finding a tricky bug
+
+Imagine you've just came up with a new feature that you're really eager to implement for your project. So, the moment
+you think of how to do it, you start working on it. Then, a good bit of work, you're finally done, entirely. You now
+make a commit, with all of the changes.
+
+However, you now realize that as you pushed your commit to your repo, the automated CI workflows start to fail on some
+unit-tests. Turns out you didn't think of some edge-case, some part of your solution is suddenly affecting something
+completely unrelated. As you attempt to fix it, more and more other issues arise, and you don't really even know where
+to start. You have this big single diff for the entire feature, but you have no idea where in that is the bug.
+
+Figuring it out takes at best a lot of mental effort, analyzing and keeping track with all of the changes at once, or at
+worst, you'll spend a lot of time doing this, but you'll just keep getting lost in your own code, until you finally just
+give up, and start over. This time, only doing small changes at a time, and running the unit-tests
+for each one as you go.
+
+#### Same scenario, but with atomic commits
+
+Now, let's consider the same scenario, but this time, you're following the best git principles, and so you're splitting
+the problem up and making atomic commits for each of necessary changes, that will together make up the feature.
+
+Once you're done, you decide to push all of those commits, and see the CI fail. However this time, you have a much
+eaiser time finding where that pesky bug hides. Why? Because this time, you can just checkout one of those commits you
+divided your bigger task into, and run the tests there. If it fails, you can run the tests in the commit before that.
+You can just repeat this until you find the exact commit that caused these failures.
+
+At this point, you know exactly which change caused this, because the commit you discovered was pretty small, it only
+changed a few dozen lines and introduced a very specific behavior, in which after looking at it for a while, you find
+that there's indeed a completely unexpected fault, which you only found out because you knew exactly where to look.
+
+#### Git bisect
+
+This scenario is actually very common and can come up a lot while developing, because of that, git actually has an
+amazing tool that can make this process even easier! This tool is called `git bisect`.
+
+Essentially, you can give git bisect a specific start commit, where you know everything worked as it should've, and an
+end commit, where you know the fault exists somewhere. Git will automatically check out the commits in between in the
+most optimal way (binary search), and all you have to do is then check whether the issue exists in the checked out
+commit, or not. If it does, you tell bisect that this commit is still faulty, or if not, you say it's good.
+
+Since bisect is essentially a binary search, it won't take too many attempts to figure out exactly which commit is the
+faulty one, essentially automating the process above. Better yet, if the task of finding the bug can be uncovered by
+simply running some script/command (perhaps the unit tests suite), you can actually just specify that command when using
+git bisect, and it'll do all of the work for you, running that command on each of those check outs, and depending on
+it's exit code, if the command passed, marking the commit as good, or if not, marking it as faulty.
+
+So, even if the test suite takes a while, you can actually just have git find the bug for you, while you take a break
+and make a nice cup of coffee.
+
+### Git blame
+
+Git blame is a tool that allows you to look at a file, and see exactly which lines were committed by who, and in which
+commit. This can be very useful if you just want to check what that line was added there for. If it's a part of a larger
+spanning commit, you can then check the diff of that commit, to see why that line was relevant, with the context of the
+rest of the changes done.
+
+Having good commit history and using atomic commits makes doing this a great and easy experience, as you're not very
+likely to find that commit to be addressing 10 different issues at once, without providing any real description in the
+commit message, as to why, and perhaps not even as to what it's doing. With commits like those, git blame becomes almost
+useless, but if you do follow these best practices, it can be a great tool for understanding why anything in the code is
+where it is, without needing to check the documentation, if there even is any.
+
+### Cherry picking
+
+Cherry picking is the process of taking a commit (or multiple commits), and carrying them over (essentially
+copying/transferring them) to another branch, or just another point. So for example, you might have a feature branch, in
+which you fixed a bug that also affects the current release. Instead of checking out the release branch, and re-doing
+the changes there, you can actually use cherry-picking to carry the commit from the feature branch into the release
+branch. This will mean any changes made in that commit will be applied, fixing the bug in release branch and allowing
+you to make a release.
+
+However, if the commit that fixed this issue wasn't atomic, and it also contained fixes for tons of other things, or
+worse off, includes logic for additional features, you can't just carry it over like this, as you'd be introducing other
+things into the release branch which aren't supposed to be there (yet). So instead, you'd have to make the changes in
+the branch yourself, and create another commit, which is simply slower.
+
+### Pull request reviews
+
+When someone else is reviewing your pull request, having clean commits can be incredibly helpful to the reviewer, as
+they can go through the individual commits instead of reviewing all of the changes at once by looking at the full diff
+compared to the branch you're merging to. This alone can greatly reduce the mental overhead of having to keep track of
+all of the added/changed code, and knowing how it interacts with the rest of the changes.
+
+Atomic commits then allow for the reviewer to understand each and every atomic change you made, one by one, which is
+much easier to grasp. So even if when put together, the code is pretty complex, in these atomic chunks, it's actually
+pretty easy to see what's going on, and why. This is especially the case if these commits include great descriptions of
+what it is they're addressing exactly.
+
+This then doesn't just apply for pull-requests, this kind of workflow can actually be useful to anyone looking over some
+code in a file. You could use git blame to find out the commit, and follow the parent commits up, allowing you to see
+the individual changes as they were done one by one, which again, is then easier to understand, and allows you to then
+realize what the whole file is about much quicker.
+
+### Easy reverts
+
+Sometimes, we might realize that a change that we made a while ago should not actually have been made, but the change
+was already pushed and there's a lot of commits after it. That means at this point, we can't simply rewrite the history,
+and we will need to push a commit that undoes that change.
+
+The great advantage of atomic commits is that they should include the entire change, along with documentation it
+introduces, tests, etc. in a single piece, a single commit. Because of that, assuming there weren't any commits that
+built upon this change later on, we can use git's amazing `git revert` command.
+
+This will create a new commit that undoes everything another specified commit did, making it very easy to revert some
+specific change, while leaving everything else alone. This is much faster and easier than having to look at what the
+original commit changed line by line, and change it back ourselves, and while this isn't something you'll use all that
+often, when you do get a chance to use it, it's really nice and can be a good time saver.
+
+## Conclusion
+
+Git is something programmers use every day, learning how to do so properly is invaluable. There's a lot of rules I
+mentioned here, and of course, you probably won't be able to just start doing all of them at once. But I would encourage
+you to at least stop for a while before every commit you're about to make, and think of whether you really need to stage
+all of the files, or if you should do a partial add, and make multiple commits instead, and also take a while to think
+of a good commit message.
+
+For motivation, here's a quick recap of the most important benefits a good git workflow gives you:
+
+- Your development workflow becomes easier by allowing you to find issues a lot quicker
+- You can also help your team or whoever ends up reading your commits understand what's going on and bring them up to date with the project
+- You will be able to quickly find out who committed something and why
+- Your overall programming skills will improve, because you'll get used to dividing up your problems naturally