The Problem
Merging code into a branch could be a really time consuming task, especially on big projects with many developers, or anyway when you have a big number of Pull Requests that have to be reviewed, approved, and merged in the correct order.
And it’s not just the merge itself... for each pull request you have to decide who the reviewers are, assign the labels, perhaps rebase your branches to the most updated version that was merged in the meantime, and much more.
Wouldn’t be nice if we could have a free automation tool which works with any CI, integrates natively with GitHub, and can do for us all the things I’ve just mentioned?
Well, today I have that very tool for you. Let’s talk about it.
Video
As usual, if you are a visual learner, or simply prefer to watch and listen instead of reading, here you have the video with the whole explanation and demo, which to be fair is much more complete than this post.
Link to the video: https://youtu.be/jb9wnpqNzEo
If you rather prefer reading, well... let's just continue :)
The Solution: Mergify
What I have for you today is the review of a tool that promises to revolutionize the way we work with our Pull Requests and we do the merges: Mergify!
Mergify is a tool that helps prioritizing, queuing and automatically merging your pull requests, and which can also rebase and update your branches, while commenting, labeling, assigning and closing your pull requests.
If it sounds really powerful it’s because it is.
I know what you're thinking: can’t I do some of these things in GitHub directly? Well, yes and no.
As we will see in a minute, GitHub does have some of same the features that Mergify has, but you need to either activate them manually, or they are not as powerful and complete as the ones in Mergify. Plus, there are many other features that are simply not present in GitHub, at least at the time of writing this. You’ll soon see what I mean.
Mergify Onboarding
Let’s start with quickly seeing how to setup the tool the first time you use it.
All you have to do is going to mergify.com and click on sign up. You will then need to insert you GitHub username and password, Mergify in fact uses the GitHub authentication, and you’re in.
To interact with GitHub, Mergify requires the installation of a GitHub App.
As always happens when installing GitHub Apps, you can pick and choose the organizations and accounts where you want to install the app, and then you can choose if you want it to access all your repos in that organization or only the hand-selected ones.
And when it is done, you’ll be redirected to the Mergify Dashboard where a message will welcome you saying the setup of Mergify on your account is completed, and that to fully utilize the service you should create a config file in the root directory of your repositories with the rules that you want to apply. We will see how to do all of this in just a moment, but let’s go back to the dashboard and see what we have here out of the box.
Mergify Dashboard
As you can see the dashboard is quite minimalistic.
On the left hand side, we have the selection of the account or organization we want to work on. It shows the organizations/accounts where we have installed the app, but we can always add more organizations.
Then we have the list of repositories currently visible to Mergify in the selected account. We can pick the repo we want to work on using the dropdown list, and we can add additional repos if we have enabled only a subset of repositories in the App.
Next is the Application Keys menu, where, as the name says, we can create API keys to be used for integration with other tools that require API access.
We then have the billing section, which we will explore later on when we talk about pricing, and the Usage section, which shows you the active users in your selected repos. It is important to note that, for Mergify, they count every user that have write access to your repos as a seat.
We will take a look at the different plans later on, but don’t worry... they do have a free forever plan.
🤑 If you decide you like to tool and you want to subscribe to their paid plans, you can use the coupon code
CODERDAVE22
to get 2 months for free for any offer.
Initial Configuration and Config Editor
Let’s get now into the beefier stuff about Mergify and let’s configure the first set of rules.
🎦 Check out this part of the video for a full demo.
Mergify relies on a configuration file called .mergify.yml
in the root of your repo. We can create this from scratch or we can use the Config Editor
in the UI.
Just select the repo you want to work on, click on the Config Editor Tab, and there you are with the first default rule.
Let's take a closer look at it:
pull_request_rules:
- name: Automatic merge on approval
conditions:
- "#approved-reviews-by>=1"
actions:
merge:
method: merge
As you can probably see, the rule is very simple. It will just wait for a PR to be approved from at least 1 reviewer, and then automatically merge it.
Analyzing the YAML we can see the general structure of it. First off, this is a Pull Request Rule (we will see later that there can be different types of rules), it has name (which can be anything we want), some conditions and some actions. As you probably thought already, the actions are executed when the conditions are verified.
Also you've probably noticed the #
character in front of the condition. That is part of the Mergify grammar and it means number. If we were to use approved-reviews-by
instead (without #) we would have the list of reviewers.
Test Your Configuration
One thing I love about Mergify is that it allows you to test the configuration before even creating the config file.
Just write in the textbox the number of the PR in that repo which you want to test your configuration rules against, and see the result!
In the example above, you can see that the summary says 1 potential rule. This means that the rule we have tested can potentially be applied to that pull request if the conditions apply. This is because the condition specify that the PR must be approved, while it is currently not.
If I were to change the condition to 0 (this wouldn't make sense in practice, but for demo purposes...) and re-test the rule:
The rule would be marked as "matching" because all the conditions.
When you are ready to push your config to the repo, you can just click on the Create a pull request with this configuration button and... well, I think the button text is descriptive enough :)
ℹ️ Please note that if a configuration is pushed to a repo and some rules matches already, the actions will be executed immediately
More Pull Request Rules
Of course, we can write much more complex rules.
pull_request_rules:
- name: Automatic merge on approval PRs targeting README.md
conditions:
- "#approved-reviews-by>=1"
- files=README.md
actions:
merge:
method: merge
The rule above, for example, will execute on all and only the PRs that are approved and target the README.md
file.
As you've probably noticed, by default all the conditions have to match for the actions to be executed. So, what if we want one or the other?
pull_request_rules:
- name: Automatic merge
conditions:
- or:
- "#approved-reviews-by>=1"
- files=README.md
actions:
merge:
method: merge
I can use a "modifier", like you see above, to add an or
condition to the rule. The rule will now work on all PR that are either approved or target the README.md file.
And in fact, if we try and validate the rule, we can see that the summary looks a little different.
You can in fact see that now we have the any of clause there. And of course we can nest and combine those conditions. Let take a look at this rule:
pull_request_rules:
- name: Automatic merge with and and or
conditions:
- and:
- "#approved-reviews-by>=1"
- or:
- files=README.md
- "#files=1"
actions:
merge:
method: merge
What will it do? It will automatically merge all the PRs that are approved and target either a README.md file or target only 1 file (whatever it is).
Multiple Rules and Multiple Actions
All we have seen so far included a single rule and a single action in that rule. Config files tho can get much more interesting. We can have multiple rules, and each can have multiple actions.
🎦 Check out this part of the video for a full demo.
pull_request_rules:
- name: Automatic merge on approval
conditions:
- or:
- files=README.md
- "#files=1"
actions:
merge:
method: merge
- name: Assign to n3wt0n if YAML and label as Enhancement
conditions:
- files~=\.yml
- -closed
actions:
assign:
add_users:
- n3wt0n
label:
add:
- enhancement
Let's analyze this example. First off, we have two Pull Request rules. The first one is the same we had before, the second one is a little more interesting.
On the conditions part, we want to target all the PRs that target .yml
files (this is what the files~=\.yml
means) and that are not closed (the -
in front of a condition is equivalent to not
).
On the actions side, instead, you can see we have two actions: assign
and label
.
Just as recap, what the rule does is assigning the PR to the user specified and labeling it, for all the PRs targeting YAML files and that are not closed.
And you can see it executing in the screenshot above.
Mergify Manual Command
Not bad right, and we’ve just scratched the surface of what this tool can do.
Mergify also exposes a set of Commands that you can trigger by commenting on the pull request.
🎦 Check out this part of the video for a full demo.
You can see the list of those commands on the Commands page in the docs, but what they do is basically run some action directly without leveraging the rule system.
At the time of writing this article, the available commands are:
- rebase
- update
- backport
- copy
- squash
- refresh
To execute a command all you need to is tagging the mergify bot in the Pull Request comment section and specify a command.
For example, if I want to update the branch associated with a pull request to include all the changes that have been made in the main branch, I will comment this:
@Mergifyio update
and Mergify will take care of the rest.
What Else?
Ok enough talking about Pull Request rules... let’s see what other actions and rules we can add to our configuration File.
First thing to mention is that there are 4 main sections of the configuration file:
- Pull Request Rules
- Queue Rules -
- Command Restrictions
- Defaults
And you can have config files with all four of them or as little as just one of them... And anything in between.
We have talked about Pull Request Rules until now. As the name says, they apply to pull requests. You can use them to govern how and when your merges will happen. As we have seen before, those rules need to have a name, some conditions, and some actions to be executed.
Command Restrictions
Command Restrictions are... well, as the name says, they allow you to put restrictions on the commands that you can execute via the Mergify bot by commenting on the PRs.
commands_restrictions:
backport:
conditions:
- base=main
For example, the rule above limits the execution of the backport
command for pull requests coming from the main branch.
Defaults
The Defaults section is used to define default configuration values for actions run by pull request rules and by commands. If the options are defined in pull_request_rules
they are used, otherwise, the values set in defaults
are used.
For example, the following configuration
defaults:
actions:
comment:
bot_account: Autobot
pull_request_rules:
- name: comment with default
conditions:
- label=comment
actions:
comment:
message: I 💙 Mergify
and this one
pull_request_rules:
- name: comment with default
conditions:
- label=comment
actions:
comment:
message: I 💙 Mergify
bot_account: Autobot
will produce the same results.
Queue Rules
To understand Queue Rules we need first to understand what merge queues are and what problem they solve.
Merge Queues and The Problem
Imagine that you have repository, you make some changes and you open a PR
You PR is valid so the CI and all the test pass.
While the pull request is open, another commit is pushed to main
either directly or from another pull request.
The tests are run against the main branch by the CI, and they pass as well.
The pull request is still marked as valid by the continuous integration system since it did not change. As there is no code conflict, the pull request is considered as mergeable by GitHub.
When you merge the PR, however, it is possible that the pull request that was once working breaks the main branch. The stalled pull request might introduce regression or breakages into the production system.
Using a merge queue solves that issue by updating any pull request that is not up-to-date with its base branch before being merged. That forces the continuous integration system to retest the pull request with the new code from its base branch.
If a merge queue were being used in the previous example, Mergify would automatically merge the main
in the base branch. The continuous integration system would have rerun and marked the pull request as failing the test, removing it from the merge queue altogether.
Mergify Queues provide this, but we can even take this a step forward, for example batching the merges of multiple PRs in the correct order, etc.
When multiple pull requests are mergeable, they are scheduled to be merged sequentially, and are updated on top of each other. The pull request branch update is only done when the pull request is ready to be merged by the engine, for example when all conditions are validated.
That means that when a first pull request has been merged, and the second one is outdated like you can see in this image, Mergify will make sure the pull request #2 is updated with the latest tip of the base branch before merging
With this, there's no way to merge a broken pull request into the base branch.
Queue Rules
Now that we have seen this in theory, let’s see how to configure and use merge queues in Mergify.
🎦 Check out this part of the video for a full demo.
Let's start with a simple example. This set of rules gives us the ability to enqueue our PR merges based on conditions.
queue_rules:
- name: CoderDave_queue
conditions:
- check-success=My CI Job
pull_request_rules:
- name: Merge using the merge queue
conditions:
- base=main
- "#approved-reviews-by>=2"
- check-success=My CI Job
actions:
queue:
name: CoderDave_queue
On the upper part we have the queue definition, and the condition for auto-merge (in this case the success of the My CI Job). Then we have a rule with the action of type queue
: this will send to the queue all the PRs that match the conditions.
This gives you a general idea of how this works: you need to define queues and have conditions to decide which PRs to enqueue.
Let's take a look at another, more complex example of a Queue Rule.
queue_rules:
- name: urgent
conditions:
- check-success=My CI Job
- name: default
conditions:
- check-success=My CI Job
pull_request_rules:
- name: move to urgent queue when 2 reviews and label urgent
conditions:
- base=main
- "#approved-reviews-by>=2"
- label=urgent
actions:
queue:
name: urgent
- name: merge using the merge queue
conditions:
- base=main
- "#approved-reviews-by>=2"
- check-success=My CI Job
- label!=urgent
actions:
queue:
name: default
In this case we have two queues: urgent and default.
The concept here is to be able to enqueue PRs base on their priority (for example hotfixes vs features), based on their label. If a PR is labeled as urgent then it will be sent to the urgent queue, otherwise it will be sent to the other queue. In this case, the urgent PRs will be merged more quickly because, if you look at the rule, they require the CI to pass only while in the queue. The normal PRs, instead, need the CI to be successful also as prerequisite for them to be enqueued.
Finally, let's talk about another feature that is part of the Queue Rules, and that makes Mergify offering quite appealing. I'm talking about the Speculative Checks.
If your continuous integration system takes a long time to validate the enqueued pull requests, it might be interesting to enable speculative checks. This will allow Mergify to trigger multiple runs of the CI in parallel. In the following example, by setting the speculative_checks
option to 2, Mergify will create up to 2 new pull requests to check if the first three enqueued pull requests are mergeable.
ueue_rules:
- name: default
speculative_checks: 2
conditions:
- check-success=My CI Job
pull_request_rules:
- name: merge using the merge queue and speculative checks
conditions:
- base=main
- "#approved-reviews-by>=2"
- check-success=Travis CI - Pull Request
actions:
queue:
name: default
Multiple pull requests can be checked within one speculative check by settings batch_size
.
For example, by settings speculative_checks: 2
and batch_size: 3
, Mergify will create two pull requests: a first one to check if the first three enqueued pull requests are mergeable, and a second one to check the three next enqueued pull requests.
queue_rules:
- name: default
speculative_checks: 2
batch_size: 2
conditions:
- check-success=Travis CI - Pull Request
pull_request_rules:
- name: merge using the merge queue and speculative checks
conditions:
- base=main
- "#approved-reviews-by>=2"
- check-success=Travis CI - Pull Request
actions:
queue:
name: default
At this point, I should mention that both the multiple queues and speculative checks features are not present in the free plan, they are part of the paid plans.
ℹ️ It is also important to note that, in general, a PR will be automatically removed from a queue if the conditions don't match anymore. For example, if one of the conditions is that the PR must be approved and someone removes the approval, that PR will be taken off the queue (if it has not been already merged, of course)
Pricing and Save Some Money
Finally, let’s talk about prices and how you can save some money on Mergify.
As I’ve mentioned before, they do have a forever free plan you can use for your repositories, and that covers the use on public repos with unlimited actions and rules, and even basic merge queues.
If you want more, like using Mergify on private repos, advanced queue features, batch merge or even having a dedicated bot account to act on your behalf, you can subscribe to one of their paid plans. And as I’ve mentioned before, if you want to get 2 months off any of their paid plans you can use the code CODERDAVE22
(all uppercase) at purchase. But be quick because this is valid only for the first 50 people who will use it.
Mergify Startup Program
And if you are part of a startup it gets even better, because you can get up to $21,000 value of Mergify services, free of charge.
The company has in fact launched their startup program, a 12-month partnership between new ventures and Mergify which gives access to all Mergify features for free.
If you want to apply to it, you can do it from their Startup Program page (link in the description below) or email them at startup@mergify.io.
Conclusions
Let me know in the comments below what you think about Mergify and if you’ve had a chance to use it already.
Also, check out this video, in which I explain how to properly manage Pull Requests in GitHub.
Like, share and follow me 🚀 for more content:
📽 YouTube
☕ Buy me a coffee
💖 Patreon
📧 Newsletter
🌐 CoderDave.io Website
👕 Merch
👦🏻 Facebook page
🐱💻 GitHub
👲🏻 Twitter
👴🏻 LinkedIn
🔉 Podcast