iTranslated by AI
How to Restrict Merging After Approval Until a Specific Label is Applied
In this article, I will explain how to prevent merging after being Approved until a specific label is applied.
Background
In a certain project, we have adopted a flow called GitFeatureFlow.
In this flow, we branch off a topic branch from the main branch for development, and once development is finished, we create a pull request targeting the main branch. After that, we request a reviewer to perform a code review. However, even if the pull request is Approved, it cannot be merged immediately. We request QA, and only after QA has passed can it be merged.
There was one concern with this operation: since an Approved pull request can be merged with a single click, there is a risk that features with incomplete QA might be merged by mistake.
Therefore, I created a mechanism to prevent merging after Approval until a specific label is added. This prevents mistakes where features with incomplete QA are merged. I hope this serves as a reference for those facing similar situations.
Actual Behavior
You can view pull requests where this is actually working from the links below.
Example without a label

Merge is blocked because the label is not attached.
Example with a label

Merge is possible because the label is attached.
Policy
- Prevent merging using Branch Protection rules until a specific label is added.
- Implement it ourselves without using GitHub Apps to reduce security risks.
Creating the Workflow
To achieve this, I created the following workflow:
When a specific label (in this example, マージOK [Merge OK]) is added, a success status is assigned to the Label Check check of the pull request. On the other hand, if the specific label is not added, a pending status is assigned to the pull request's checks.
name: Pull Request
on:
pull_request:
types:
- synchronize
- labeled
- unlabeled
- opened
- reopened
permissions:
statuses: write
jobs:
ready-deploy:
runs-on: ubuntu-latest
name: Label Check
steps:
- name: Set status check to success
if: "contains(github.event.pull_request.labels.*.name, 'マージOK')"
run: |
curl --request POST \
--url https://api.github.com/repos/${{github.repository}}/statuses/${{github.event.pull_request.head.sha}} \
--header 'authorization: Bearer ${{secrets.GITHUB_TOKEN}}' \
--header 'content-type: application/json' \
--data '{
"context": "Label Check",
"state": "success",
"description": "Ready to merge"
}'
- name: Set status check to pending
if: "!contains(github.event.pull_request.labels.*.name, 'マージOK')"
run: |
curl --request POST \
--url https://api.github.com/repos/${{github.repository}}/statuses/${{github.event.pull_request.head.sha}} \
--header 'authorization: Bearer ${{secrets.GITHUB_TOKEN}}' \
--header 'content-type: application/json' \
--data '{
"context": "Label Check",
"state": "pending",
"description": "Add the \"マージOK\" label to enable merging"
}'
on is configured to trigger on specific pull request events. By the way, synchronize triggers when a new commit is added. Since the status is tied to a commit, it is necessary to re-apply the status whenever a new commit is pushed.
In permissions, statuses: write is set. This configuration is necessary because the default GITHUB_TOKEN does not have permission to modify statuses. Conversely, other permissions like contents are not required.
In the step, the status is assigned by POSTing to the Statuses REST API.
Configuring Branch Protection Rules
Now that the Label Check check is successfully being applied, the next step is to configure the Branch Protection rule.
Branch Protection rules allow you to set requirements for merging into specific branches. In this case, we will make it a requirement that the Label Check check is in a success state before merging.
From Settings > Branches > Branch protection rules, set the Branch name pattern to main, and add Label Check to the Require status checks to pass before merging section.
Additionally, Require branches to be up to date before merging is a constraint that requires you to update your branch with the latest changes from main before merging the pull request. When using GitFeatureFlow, this reduces the risk of discovering conflicts with work merged earlier only after you merge your own changes. I recommend keeping this enabled.

Branch protection rule settings screen
If you are using Terraform, you can configure it as follows:
resource "github_branch_protection_v3" "repo" {
repository = github_repository.repo.name
branch = "main"
required_status_checks {
contexts = ["Label Check"]
strict = true # Require branches to be up to date before merging
}
}
Conclusion
In this article, I introduced a method to prevent merging after Approval until a specific label is applied. By writing a simple workflow, I was able to create a mechanism for safer development without compromising the developer experience.
Discussion