Implement branch merging restrictions

Completed

Branch merging restrictions in version control systems hosted by Azure DevOps and GitHub are essential for controlling code quality, facilitating collaboration, and enhancing stability in software development projects. They help organizations enforce code reviews, validate successful completion of automated tests, and prevent force pushes to designated branches. These constraints help maintain the integrity of the codebase, prevent accidental changes, and ensure that only verified and approved changes are merged into production branches.

The general concepts of branch merging restrictions are platform-agnostic. While their implementation differs somewhat between Azure DevOps and GitHub, there are also plenty of similarities, providing, for the most part, feature parity between them.

Azure DevOps

In Azure DevOps, you can implement branch merging restrictions by using branch protection-based policies.

To implement branch protection, navigate to your repository in the Azure DevOps portal and select the branch you want to apply merging restrictions to. Alternatively, you can scope protection to the current and future branches that match a specified pattern. As part of the protection configuration, you can apply the following branch policies:

  • Require a minimum number of reviewers: ensures that changes cannot be merged without the required number of approvals.
  • Check for linked work items: encourages traceability by checking for linked items on pull requests
  • Check for comment resolution: verifies that all comments have been resolved on pull requests
  • Limit merge types: controls branch history by limiting the available types of merge when pull requests are completed. This includes the option to selectively enable or disable the following merge types:
    • Basic merge (no fast forward): preserves history exactly as it happened during development.
    • Rebase and fast-forward: creates a linear history by replaying the source branch commits onto the target without a merge commit.
    • Squash merge: Creates a linear history by condensing the source branch commits into a single new commit on the target branch.
    • Rebase with merge commit: Creates a semi-linear history by replaying the source branch commits onto the target and then creating a merge commit.

Optionally, you can configure the following constraints:

  • Build validation: validates code by pre-merging and building pull request changes.
  • Status checks: require other services to post successful status to complete pull requests. Status checks are automated tasks that are triggered during the pull request process to verify certain criteria before allowing the pull request to be merged into the target branch. In Azure DevOps, status checks are associated with build pipelines and release pipelines.
  • Automatically include reviewers: designate code reviewers to automatically include when pull requests change certain areas of code.

You also have the option of locking a branch, effectively making it read-only.

Note that Azure DevOps provides two options to bypass policy requirements for a repository. To implement them, you need to alter the default security configuration of the repository by setting the permissions to perform the following actions to Allow:

  • Bypass policies when completing pull requests.
  • Bypass policies when pushing.

It is essential to ensure that these permissions are granted only to designated individuals that understand the implications of these actions on the compliance with organizational standards and can exercise sound judgment regarding their use.

GitHub

In GitHub, you can implement branch merging restrictions using branch protection rules. Branch protection rules define whether collaborators can delete or force push to the branch and set requirements for any pushes to the branch, such as passing status checks or a linear commit history. As with Azure DevOps, you can apply them to specific branches based on name pattern match.

To implement branch protection rules, navigate to your repository in the GitHub web interface, on the Settings tab, and, in the navigation, menu select the Branches menu item. This will allow you to access the Branch Protection rules configuration. As part of the protection configuration, you can apply the following rules:

  • Require a pull request before merging: requires that contributors submit pull requests for review and approval before merging their changes.
  • Require status checks to pass before merging: designates status checks that must pass before allowing merges. When enabled, commits must first be pushed to another branch, then merged or pushed directly to a branch that matches this rule after status checks have passed.
  • Require conversation resolution before merging: ensures that all discussions and comments related to code changes are resolved before merging pull requests.
  • Require signed commits: mandates that commit pushed to protected branches are signed with verified signatures, enhancing security, and ensuring the authenticity of code contributions.
  • Require linear history: prevents merge commits in protected branches, enforcing a linear history, which makes it easier to track and, if needed, reverse any changes. This effectively means that any pull requests must use a squash merge or a rebase merge.
  • Require deployments to succeed before merging: dictates that changes proposed in pull requests are thoroughly tested and validated before being integrated into the codebase.
  • Lock branch: as its Azure Devops equivalent, restricts write access to the branch, making it read-only.
  • Do not allow bypassing the above settings: eliminates the possibility of the other rules being bypassed by administrators and users granted the bypass branch protections permission.
  • Allow force pushes: allow users with the push privileges to force push changes. As with Azure DevOps, this is meant as an emergency measure only.
  • Allow deletions: allows users with push privileges to delete protected branches. While this flexibility can streamline branch management, it also poses a risk of accidental or malicious branch deletions and should be carefully controlled to prevent data loss and maintain repository integrity.