Advanced Branch Protections with Mergify Workflow Automation

Go beyond GitHub's native branch protections and craft custom, advanced rules using Mergify.


GitHub’s branch protection is foundational, but its customization is somewhat limited.

For more advanced or specific scenarios, Mergify’s Workflow Automation can step in, enabling you to define nuanced conditions that cater to your project’s unique needs. This flexibility means you can design branch protection rules that the native system simply can’t handle.

Why Mergify Over Native GitHub Branch Protection?

Section titled Why Mergify Over Native GitHub Branch Protection?
  1. Advanced Conditions: Mergify supports a vast array of conditions, which means you can create extremely specific rules.

  2. No Conflicts: Using Mergify avoids potential conflicts with features like the Mergify Merge Queue.

  3. Streamlined Workflows: Combine branch protections with other workflow actions for a holistic approach.

There are two common ways of writing custom branch protection settings using Mergify:

  • Integrate your custom branch protection rules directly into your automatic merge rules;

  • Write custom checks that are posted by Mergify on pull requests like a CI would do. These custom checks can also be used as conditions in the automatic merge conditions.

Advanced Protection Rules for Automatic Merge

Section titled Advanced Protection Rules for Automatic Merge

Suppose you trust Dependabot’s PRs and feel a single review is sufficient, but other PRs require more scrutiny.

pull_request_rules:
  - name: Automatic merge
    conditions:
      - or:
        - "#approved-reviews-by >= 2"
        - and:
          - author = dependabot[bot]
          - "#approved-reviews-by>=1"
    actions:
      merge:

With this, Mergify will automatically trigger the merge of a pull request if author is Dependabot and has one approval, or if the PR has two approvals.

This is more flexible than GitHub protected branch which only offers a fixed number of approvals for any pull request.

You could auto-merge pull requests only modifying documentation.

pull_request_rules:
  - name: Documentation PRs
    conditions:
      # At least one modified file in the docs/ directory
      - files ~= ^docs/
      # No other files are modified
      # (note the - prefix to negate the condition), meaning:
      # if not (any files matches something else than docs/)
      - -files ~= ^(?!docs/)
    actions:
      merge:

Set rules based on the PR’s author, title, or reviewer. For instance, if an engineering manager submits a PR for a “hotfix”, one review is sufficient.

However, for other developers, an engineering manager’s review or any review for a fix/revert is necessary.

pull_request_rules:
  - name: Rules to merge hotfix PR automatically
    conditions:
      - check-success = my favorite CI
      - label = hotfix
      - or:
          - and:
              - author = @eng-mgr
              - "#approved-reviews-by >= 1"
          - and:
              # If the PR author is a member of GitHub "devs" team, they need
              # one approval from a manager unless PR is a revert/fix.
              - author = @devs
              - or:
                  - approved-reviews-by = @eng-mgr
                  - and:
                      - title ~= ^(revert|fix)
                      - "#approved-reviews-by >= 1"
    actions:
      merge:

This allows pull requests to be automatically merged with conditions that are finer-grained than GitHub generic branch protections.

You can schedule merges to happen only during office hours. For urgent fixes, bypass this restriction using the hotfix label.

pull_request_rules:
  - name: Schedule Merges
    conditions:
      - check-success = my favorite CI
      - "#approved-reviews-by >= 1"
      - or:
        - schedule = Mon-Fri 09:00-17:00[US/Pacific]
        - label = hotfix
    actions:
      merge:

Mergify offers an action named post check which allows to post custom checks. This allows to implement feedback to developers like a CI system would do, allowing to enforce extra rules on pull requests before merging.

Enforcing Conventional Commits

Section titled Enforcing Conventional Commits

You might want to enforce some guidelines as how to write pull request titles. The following rules add such a check, making sure your team follows Conventional Commits.

The check will be posted only on pull requests targeting the main branch. The check’s conclusion will be a success if the title contains a conventional commit type, otherwise it will be a failure.

pull_request_rules:
  - name: Conventional Commit
    conditions:
      - base=main
    actions:
      post_check:
        success_conditions:
          - "title ~= ^(fix|feat|docs|style|refactor|perf|test|build|ci|chore|revert)(?:\\(.+\\))?:"
        title: |
          {% if check_status == "success" %}
          Title follows Conventional Commit
          {% else %}
          Title does not follow Conventional Commit
          {% endif %}
        summary: |
          {% if check_status == "failure" %}
          Your pull request title must follow
          [Conventional Commit](https://www.conventionalcommits.org/en/v1.0.0/).
          {% endif %}

The result of this check will be visible in GitHub user interface, near the merge button.

Mergify Post Check

Checks posted by Mergify using this action are usable for any other conditions. Taking the, you could use the posted check as a condition to merge automatically your pull request:

pull_request_rules:
  - name: Automatic Merge
    conditions:
      - check-success = my favorite CI
      - "#approved-reviews-by >= 1"
      - "check-success=Rule: Conventional Commit (post_check)"
    actions:
      merge:
pull_request_rules:
  - name: PR Approval
    conditions:
      - base = main
    actions:
      post_check:
        success_condition:
          - or:
            # Regular approval is 2 reviews
            - "#approved-reviews-by >= 2"
            - and:
              # Conditions for hotfix PR
              - label = hotfix
              - and:
                # If author is an engineering manager, one approval is enough
                - author = @eng-mgr
                - "#approved-reviews-by >= 1"
              - and:
                # If the PR author is a member of GitHub "devs" team, they need
                # one approval from a manager unless PR is a revert/fix.
                - author = @devs
                - or:
                  - approved-reviews-by = @eng-mgr
                  - and:
                      - title ~= ^(revert|fix)
                      - "#approved-reviews-by >= 1"
          # You can default to neutral rather than failure if the rule does not succeed
          # (Note that if you're using this with GitHub branch protections,
          # neutral is considered as passing and won't prevent merging.)
          # neutral_condition: []
        title: PR Approval
        summary: |
          {% if check_status == "success" %}
          This PR has been approved.
          {% else %}
          This PR has not been approved yet.
          {% endif %}

This example defines a complex workflow for approval, based on different criteria. A pull request can be deemed approved when, either:

  • it received 2 approvals;

  • it has the label “hotfix”, the author is part of the eng-mgr team and it has been approved by somebody else;

  • it has the label “hotfix”, the author is part of the devs team and it has been approved by a member of the eng-mgr team;

  • it has the label “hotfix”, the author is part of the devs team and it has been approved by somebody else and it fixes an issue or reverts a commit.

If one of those scenarios is true, the check Rule: PR Approval (post_check) will be success; otherwise it will be failure.

You can then use this check as a condition for further automation, such as merging automatically a pull request:

pull_request_rules:
  - name: automatic merge when PR Approval matches
    conditions:
      - check-success = my-favorite-ci
      - "check-success = Rule: PR Approval (post_check)"
    actions:
      merge: