Drupal 9 Upgrade: Patching Modules 101

Not all contributed D8 modules have D9 compatibility built into their latest releases. More than a few, however, will have a patch available in their open issues that will get you there. I've had several occasions to patch a module, but it's not something I do with enough frequency to immediately recall how it's done. On the command line I often forget which is the right way to do it: git apply or patch?

Prepping for a Patch

As with all things Drupal--attention to detail is paramount. It's easy to get ahead of yourself when looking for and applying a module patch, but one of the first things you'll want to do when you find one is to ensure that the patch was built for the module version you're using. A patch is a file that applies very specific changes to an already existing file. If the existing file you have on your site (say, the info.yml file associated with a module) differs from the one the patch was created for, the patch will likely fail. You may need to update to the version listed in the issue in order to ensure the patch applies...

Drupal 9 Readiness issue for Facebook Pixel Module
Pay careful attention to the version listed in the issue documentation. Another important item will be the status of the issue. The status here is listed as "Needs review". In most cases, I wouldn't apply a patch that needs review, but it looks like the patch has been confirmed as working in comments and maintainers simply haven't updated the status.

Based on that screen grab, you can probably guess I've got a solid example to run with here: I'd like to get the Facebook Pixel module into D9 compatibility, but the best the module contributors can offer is a patch (for the time being). They've built the patch for the 8.x-1.x-dev version of the module, but the version I'm running is 8.x-1.0-alpha4. Let's do a quick update with Composer:

$ composer require 'drupal/facebook_pixel:1.x-dev'

Okay, now that that's out of the way, I can go ahead and download the patch. In order to do this I usually just click the link to the patch and then right click to save it into the module directory. Like so:

saving a patch to the module root
The module path is too long for Ubuntu to show it clearly here, but this is the document root for the Facebook Pixel module.

Once it's saved, we'll head back to the terminal to get it applied.

Deciding how to Patch

Here's where it's easy to get turned around. There are two ways to apply a patch: with git apply, and with patch. Of the two, patch can never really go wrong. git apply, on the other hand, has more specific use cases. You can decide which to use by asking a couple of questions:

  • Is your site/project as a whole managed with Git version control?
    • If YES...
      • Are you patching a module tied to it's own git repository (i.e., it's a -dev version)?
        • If YES...
          • You can use git apply or patch
        • If NO...
          • You'll want to use patch
    • If NO (i.e, you don't use Git)...
      • You'll want to use patch

Patching with git apply

Understanding git apply means understanding git--to a certain extent; most Drupal patches will be created relative to a repository root. In my case, Git already knows of one repository root: my Drupal root (i.e., docroot/). By installing the -dev version of the Facebook Pixel, I essentially initialize a second repository below my project root--that root will reside at docroot/modules/facebook_pixel. This is why things can get complicated if I don't install the version of the module the patch was built for. If, for example, I tried to apply the patch to the 1.0-alpha4 version of Facebook Pixel that I previously had on the site, git apply would try and run the patch relative to the only repository root it knows of: docroot/. It won't find the files it needs to patch there, and everything falls apart.

If you're at all unsure whether a module is set up as a repository, you should be able to run git status from it's root folder and see that your HEAD is detached at a commit outside your local branch. Running git log would also show you the commit history on the module.

Since, in my case, I've got the right module version installed, all I need to do is get the patch into the module directory and I can run git apply. I'll start by checking to make sure the directory is all in order:

checking the module directory
I need to get a color theme for Ubuntu's terminal; I'm getting tired of purple. But yea... you can see the patch in the directory

Now I can run a git apply--something like this:

// the -v option tells git to run the command with verbose output
$ git apply -v 3122781-6.patch

Afterwards, of course, I'll want to cd back into my project root so I can do a git status and verify that the affected files are ready to add and commit:

applying a patch with git apply
Since the patch obviously worked, I'm probably good to just remove the actual patch file.

And that should be that. We've patched the module with git apply.

Patching with patch

It seems like you can't go wrong with patch, although you still want to be sure you're patching the right module version. If the module you need to patch isn't a -dev version (i.e., it was an official release that got patched after the fact, and it's not tied to a repository), you'll have to use patch so you can avoid Git looking for files in the wrong place.
So long as you're running the patch from the directory it's intended to be used in, the patch command is utterly simple:

$ patch < 3122781-6.patch
//you would also be successful with this -p otption
$ patch -p1 < 3122781-6.patch

TheĀ  -p option is a way to help specify the directory level of the file you'd like to patch. Since you're running from the root of the project, and the patch was built to run from that root, though, it's not much of a concern.

To Recap

Make sure you're running the module version the patch was intended for; patch will always get the job done. If you're module is tied to a repository, you can use git apply.