Question

Is there a git hook or some other way to prohibit branching from and merging of specific branches. We want to make sure that we don't merge a "dirty" integration branch into our clean deployment branch.

The major goal is that people cannot execute something like this:

git checkout integration
git checkout -b major_problem_branch

or

git checkout deployment_or_hotfix_or_feature_branch
git merge integration
Was it helpful?

Solution

You can use branch permissions on the server by adding this to the config file in your bare repository:

[hooks]
        allowedtomerge = user1,user2,user3
        protectedbranches = master

That will allow user1, user2, and user3 to merge to master branch, but no one else.

Or you could create a pre-commit hook:

#!/bin/bash

if [[ `git symbolic-ref HEAD` == "refs/heads/master" ] -a ["$USER" != "user1"]] then
    echo "You cannot commit in master!"
    exit 1
fi

Then you have people that evaluate and allow changes to go forward.

Ideally, I would use a system that you like, for instance gerrit or assembla or github. They have nice ways of controlling a master branch through Merge Requests.

OTHER TIPS

In general, you can't reliably prevent anyone from making changes in their local repositories. Unless you trust your developers to never make any mistakes (in which case you wouldn't need this), you have to run your checks in hooks on your server.

That means you can't count on preventing people from branching, and I'm not sure why you'd really want to anyway. What you can do is keep people from pushing work that hasn't been somehow "approved" into the server's deployment branch (which I'm going to call deploy).


Now the first question is how to express that approval.

If you want a workflow where an authorized person has to review work before it's deployed, then I'd have the reviewer do these steps, if the work is currently living on a branch named review:

  1. Ensure deploy is fully merged into review, so that later deploy can be fast-forwarded to review.
  2. Do any appropriate verification on review.
  3. Create and push a signed tag (git tag -s), using an authorized key, for the contents of review.
  4. Fast-forward deploy to review (git checkout deploy, git merge --ff-only review) and push it.

If instead you want anyone to be able to deploy, but you want them to have to think about it first, you could do the same thing but relax the signature requirements. Or you could bless a particular branch (tested, say) and require that all work be merged and pushed to tested before being pushed to deploy.


How can the server verify that this approval has been given for the protected deploy branch? The basic plan is to use the update hook to accept or reject ref-updates for refs/heads/deploy according to the acceptance criteria you've decided on.

If you want a tag that satisfies particular criteria, like being signed by an approved key, then you can find all tags that point to the new object proposed for deployment using git for-each-ref refs/tags. Remember to accept the update if any tag meets the criteria, or else sooner or later somebody's going to push a bad tag that blocks deployment. Verifying that the right key was used is left as an exercise for the reader, but gpg --no-default-keyring --keyring=approved.gpg may help.

If you'll take any commit as long as somebody's tagged it, you can use git describe --exact-match <object>. If you want to limit to tags with a particular name pattern, add --match <pattern>. If you'll accept unannotated tags, add --tags.

If you want work merged to a blessed branch before being merged to deployment, you can check that the output of git rev-parse tested equals the proposed new object.

In all cases, you probably want to double-check that the push is a fast-forwarding push. You can check that git merge-base <old> <new> equals <old>.

I don't think Git has support for branch grained permission, you should consider using gitolite for such requirement.

You even has a very cool gitolite web interface, called GitLab with a look similar to github.

If you never, ever want to merge from the dirty integration branch to the clean deployment branch, you could clone the deployment repo, then perform the dirty integration work only on the clone (the non-deployment repo).

may I advise to use git flow by nvie.Model It keeps all your branches where they should be by using very simple commands. Here's a cheatsheet

Note that if you are willing to control access right at a central repo level, Assembla is one git hosting service which now (March 2013) allows for protected branches:

See "Put Down Your Forks - Introducing Protected Branches":

A Protected Branch is a branch with limited write access.
Specify members (or groups) of your team that will be able to submit code to a branch:

group

Now, only these people will be able to push to the Master branch.
Everyone else will have to contribute code through merge requests. They will be able to push to any other branch in the repo, but not Master.

protected master branch

With branch per feature (as explained here in my article: http://dymitruk.com/blog/2012/02/05/branch-per-feature/) you have the idea of a release candidate. You can add an update hook on the server to ensure that the merge-base of the release candidate and the development (aka integration branch) have a common base that is the iteration start tag. This ensures that all you have are the complete features themselves.

If you want to be even more sure, you can see if a feature is finished. You would have to have the hook script integrate with your issue tracking system. If the feature that is being integrated does not have a "complete" status, you can fail at that point too. Jira, for example, provides a way to interact with it via command line.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top