Prevent commits in master branch

GitMergeFast Forward

Git Problem Overview


(For simplicity) I have a master branch and a dev in my Git repository. I want to ensure the master branch is always working, so all work I do should be in the dev branch.

However, when I merge my changes in with a --no-ff merge, I tend to stay in the master branch, and just continue working in it (because I forget to checkout my dev branch).

Can I put up a rule for the master branch, which states I can't do commits, and fast-forward merges, but only --no-ff merges from another branch?

This must work for private hosted repositories (ergo, not GitHub or Bitbucket).

Git Solutions


Solution 1 - Git

Yes, it is possible. You must create a pre-commit hook which rejects commits to the master branch. Git doesn't call a pre-commit hook when you call the merge command, so this hook will be rejecting only regular commits.

  1. Go to your repository.

  2. Create a file, .git/hooks/pre-commit, with the following content:

    #!/bin/sh
    
    branch="$(git rev-parse --abbrev-ref HEAD)"
    
    if [ "$branch" = "master" ]; then
      echo "You can't commit directly to master branch"
      exit 1
    fi
    
  3. Make it executable (not required on Windows):

    chmod +x .git/hooks/pre-commit
    

To disable fast-forward merges, you must also add the following option to your .git/config file:

[branch "master"]
    mergeoptions = --no-ff

If you want also protect the master branch on your remote, check this answer: How to restrict access to master branch in Git

Solution 2 - Git

You can use the pre-commit utility to do this. It has a built-in no-commit-to-branch hook that can be used to prevent commits to one or more branches.

Setup

The basic setup process is:

  • Install using pip or Homebrew (instructions at https://pre-commit.com/#install)
  • Create a .pre-commit-config.yaml file in the root of your project (see below for a first draft)
  • Install the hooks into your Git configuration by running pre-commit install.

Basic configuration for protecting branches

Here is a basic configuration that includes just the no-commit-to-branch hook:

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
  rev: v3.3.0
  hooks:
    - id: no-commit-to-branch
      args: ['--branch', 'master']

If you want to protect multiple branches, you can use include multiple --branch arguments in the argument list:

repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
  rev: v3.3.0
  hooks:
    - id: no-commit-to-branch
      args: ['--branch', 'master', '--branch', 'staging']

Isn't this all overkill?

Pre-commit has many other built-in hooks, and a large collection of community-built hooks that will transform the way you clean up and validate your commits. The reason I mention this is because, while this tool may be overkill for just preventing commits to a protected branch, it has many other features that make it a compelling and simple addition to any Git project.

Solution 3 - Git

It may make sense to install it globally via

git config --global core.hooksPath ~/githooks

and moving that pre-commit file into that directory

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRasmus BækgaardView Question on Stackoverflow
Solution 1 - GitqzbView Answer on Stackoverflow
Solution 2 - GitJGCView Answer on Stackoverflow
Solution 3 - GitMichel SamiaView Answer on Stackoverflow