1

We have three main branches in our workflow.

TEST (experimental), RELEASE (features going to next release), and MASTER (released only)

We take feature branches from RELEASE, merge feature branches first to TEST and if they are ok, merge those approved feature branches to RELEASE.

My problem is: as TEST branch contains some commits/features that we will not be releasing ever, we don't want it to merged into RELEASE or MASTER by mistake (or intentionally).

I read somewhere that it is not possible or feasible to prevent merges in local repositories, and i don't think it would solve my problem.

So, probably it is better to prevent updates to MASTER or RELEASE branch refs in main repository (by pushing to origin) when the new ref contains a specific commit ID of TEST branch in its commit log.

So i'll make a specific commit only to TEST branch, and record its Commit ID.

Whenever someone wants to push to master or release branch, i'll check if that push will update my refs/heads/master or refs/heads/RELEASE to a commit ref which contains that bad Commit ID in its history and abort.

As i'm no BASH or GIT master, does anybody have such an update hook that we can apply to our main repository?

Volkan Ceylan
  • 1,486
  • 13
  • 15

2 Answers2

3

Here's an update hook that should work for that. You can specify commits that shouldn't be allowed into your RELEASE or MASTER branch by giving them tags like forbidden/junk or forbidden/debugging. If a forbidden commit is found, the tag name will be included in the rejection message.

refname="$1"
oldrev="$2"
newrev="$3"
case "$refname" in
  refs/heads/RELEASE|refs/heads/MASTER)
    for forbidden in $(git tag -l 'forbidden/*'); do
      if [ $(git merge-base "$forbidden" $newrev) = $(git rev-parse "$forbidden") ]; then
        echo "Push to $refname contains commit $forbidden" >&2
        exit 1
      fi
    done
    ;;
esac
exit 0

Note that if you have a branch that contains several problem commits you must create a forbidden tag for the earliest one, not just the final commit in the series. So if history like the following where B,C, and D are all forbidden just tagging D as forbidden would not prevent E from being merged in and bringing B along with it.

A---B----C----D
     \
      ---E
qqx
  • 18,947
  • 4
  • 64
  • 68
  • thanks looks very promising, i'll test it and let you know. to clarify, i should apply this to master repo right? and do you think i'll have problems like 'platforms' stated in other answer, if i only merge into TEST and never merge back or branch from TEST? – Volkan Ceylan Nov 14 '12 at 21:02
  • Yes, that should be installed as the `update` hook on the master repository. I do not anticipate there being problems because of your `TEST` branch receiving many merges, but never being merged itself. – qqx Nov 14 '12 at 21:13
  • what if i tag a very old commit in TEST branch (for ex. a merge commit like merged 'feature-abcd branch into TEST') which is not in RELEASE branch. Will i still have to mark newer commits (they are usually also just merge commits) as forbidden as you wrote? – Volkan Ceylan Nov 14 '12 at 21:48
  • Tagging just the first of a series of forbidden commits would be fine, later commits would contain that one thus preventing the entire series from being pulled in. I've updated the answer to better reflect that. – qqx Nov 14 '12 at 22:07
  • Is it possible to use this strategy in conjuction with BitBucket (or GitHub or a similar service)? – Patrick Sanan Sep 03 '14 at 12:19
  • @TheNobleSunfish Probably not, this requires installing a script on the git server and I don't know of any hosting site which allows that. You could use a pre-push hook on the client side to help catch this, but that would need to be setup in every clone which would be pushing to the repository. This also wouldn't prevent merging forbidden commits with something like GitHub's auto-merge. – qqx Sep 03 '14 at 13:26
0

This issue needs to be solved as a management issue, not an automation issue. The problem is that TEST likely contains the majority of commits from the other two branches as well. So you won't be able to effectively identify commits that come from TEST. In our environment, for example, we regularly update experimental branches with newer commits from the master branch.

You need someone to act as a release manager, to ensure that if something bad does gets merged into master, then it doesn't get deployed before the issue is resolved. The problem isn't necessarily a bad merge, per se. The problem is deploying a bad merge.

One tool you might find useful is at Bitbucket.org, where they have a rudimentary approval mechanism for commits. It's only advisory, but could be helpful for you to track which commits have been approved and which might have gotten merged in by mistake.

platforms
  • 2,666
  • 1
  • 18
  • 23
  • yes it'd be better to get it managed, but we dont have such a release mgr yet (we should!), and using network share based master repo. it was hard for me to persuade team to exchange TFS with GIT, and had to apply a similar workflow to TFS. Now as they are all rookies with GIT, i have to prevent them from pushing by mistake, as once someone pushes, and some others pulls before i notice that, it will be very hard to fix things. – Volkan Ceylan Nov 14 '12 at 21:01