Git Patches: The Alternative Solution

Git is awesome. I’ve been relying on it ever since I started my journey into software engineering and have found a new feature or neat little trick around every corner. One of the more recent ones is git patch files!

When you’re working on a large project and have a long-running branch, often you have to rebase to a more recent version of your master branch. This is great — you keep your code up to date, make sure that you’re not accidentally introducing bugs or unintended behavior into your code, and are able to see how your changes will reflect in the latest version of your application.

There are a couple ways git helps you avoid these nasty events, and one of them is through merge conflicts. A merge conflict is basically whenever you rebase on (or merge in) a branch where a change on your branch “conflicts” with a change that has been applied to said base branch since you last rebased on it.

Sample git commit/branch tree

Let’s say you’re working on feature/crazy-big-project and you decided to edit a file called my-custom-input.js. BUT in commit 123abc on master, someone’s edited that file in the same place! Maybe they added some functionality to a formatter in there or something, I don’t know. Now when you go try to rebase feature/crazy-big-project onto master, you get a merge conflict saying that you tried to update a section of code that has also been modified by them (I use stylings on them and you because of how git treats theirs and ours when rebasing. It’s a little backwards from what you’d think; check it out here if you want to learn more about that).

This is exactly what you want. It’s now up to you (the rebaser) to decide how to best deal with this conflict, whether you want to integrate your change into the new code, or maybe make a new util that’s just for your new functionality.

There’s a caveat though. What if you simply moved my-custom-input.js and didn’t make any changes to it? The file is the exact same, it’s just in a different place. This actually also causes a merge conflict, since it’s technically “deleting” that file and making a new one with the same content. This is where git patches come in.

So what is a patch file? It’s super simple: a git patch is the output of a git diff in a file. For a file rename (a specific kind of file move), it might look something like this:

diff --git a/my-custom-input.js b/my-custom-input/index.js
similarity index 100%
rename from my-custom-input.js
rename to my-custom-input/index.js

One key aspect of git diff's (and patch files) is the similarity index. In the git documentation for git-diff-index, the similarity index is defined as:

The similarity index is the percentage of unchanged lines, and the dissimilarity index is the percentage of changed lines. It is a rounded down integer, followed by a percent sign. The similarity index value of 100% is thus reserved for two equal files, while 100% dissimilarity means that no line from the old file made it into the new one.

What this tells us is that, because we’re only moving the file and not changing the contents, the similarity index is 100% — this is great! Because similarity index is used when determining if a patch file can be applied, this similarity index means that we can always apply this change as long as the file exists. Let’s generate a patch file for our file rename change-set:

$ git diff > move-input.patch

(Note: if you have a branch that has tons of these merge conflicts instead of just one commit, you may need to use git-merge-base and the alternate syntax of git diff a..b in order to get the full diff of your branch. Just watch out, this will effectively squash your branch into one commit)

Now that you have your patch file, you can go and check out your master branch:

$ git checkout master

and apply your newly created patch! This will replay your changes onto whatever branch you want to rebase on (in this case master)

$ git apply move-input.patch

Because my-custom-input.js still exists and the similarity index is 100%, when you re-apply your changes, git is totally fine with moving this file to my-custom-input/index.js again.

Now that you’re familiar with patch files, you can actually use them for many different purposes. One of my favorites is using them to store workflow optimizations that require code changes. An example is, let’s say you’re working in a codebase that uses webpack to compile its assets. Maybe they use cheap-eval-source-maps as their devtool config, but you want to have the original source! In addition, you want to change the stats that are output from your compilation process and also add a logger to your server for whenever a request is made to your asset server. You can make all these optimizations, store them in a git patch file, and apply them whenever you need them.

That’s pretty much it! Although there is no official definition, patch files are a way of re-applying (and un-applying with git apply -R) change-sets in git. You can read more about how to leverage patch files and git-apply in their documentation.

Git is a powerful tool with a near-infinite number of features — how you use them often guides how you develop software and communicate with your team. Hopefully this empowers you to work more efficiently and adds another tool to your git toolbelt! Use it with caution.

Disclaimer: know you can solve the “you moved a file that someone else changed” by adding some rebase options; that was just an example of how you could use a patch file


Git Patches: The Alternative Solution was originally published in Building VTS on Medium, where people are continuing the conversation by highlighting and responding to this story.

Source: VTS