Produce a one-page "procedures" document - clearly, but simply lay out the process in moving code from the programmer's branch to the QA branch and into the production branch. Have everyone read and sign it.
The first time someone violates it, you give them an informal warning.
The second time they violate it, have them sit down with management and HR and tell them that if they violate the rules again, they'll be terminated.
The third time, you terminate them.
Easy...no automation required...you simply have to cause a change in the 'culture'. Programmers are very good at following rules - providing they are clearly stated and obviously put in place for a reason.
If you insist on there being an automated system...
When I've worked on setups like this, we give programmers the rights to do what they like in their own working branch(es) and into the QA branch - but deny them access to the production branch. QA get read-access to the QA branch and are the only people allowed to check stuff into the production branch. Generally programmers get their build together at the end of a sprint - then at the start of the next sprint, QA check it out and either release it or punt it back to the programmers...have two week sprints instead of six so that this doesn't add too much latency into the bug fix cycle. If you're spending more time fixing small bugs than adding large features, then you can temporarily drop the sprint cycle down to one week - if major features are being rolled out - then push the cycle up to at most 3 weeks.