I am hosting my code on Bitbucket. The webhooks are not adequate to solve my issue, so I am hoping git hooks will work. Since I don't imagine they will work server-side, the git hook should be propagated to each checkout on each developers machine. (I know this might be an issue since its normally a local file, but I can hopefully solve it using information from here)
I want to create a git hook that will push changes to staging branches.
Meaning, if I am a user named bob
and I want to push to production/master
, instead of it pushing to the production/master
branch it will push to a staging branch like staging/master/bob
. Same for another user roy
who pushes to production/master
it will go to staging/master/roy
. And the same for any production branch. So edd
pushing to production/2.0
would push to staging/2.0/edd
.
I have tried the pre-commit hook, but I can't find a way to direct the target of the push. I know this is possible.
I tried using GIT_WORK_TREE
, and I couldn't seem to get it to work.
Clarification
The whole process should be seamless for bob
the developer. He should pull from the master and push to the master. (or whatever branch he is working on) and the process will happen in the background. It will push his changes to a staging branch, which will then undergo a CI process, and if successful will be pushed into the main branch. This is the solution that I need.
That is a management better addressed with forks:
By forking a repo, bob can push to it without having to rename branches: master will be in
bitbucket.org/bob/repo/master
.He can then make a PR (Pull Request) to the staging repo (itself a fork of the prod repo), dedicated to consolidate contributions from developers.
Once the code behaves as expecting in the staging repo, a PR can be made to the prod repo (managed only by few people)
That workflow is easier than trying to fiddle with branch names and manage everything in one remote repo, for which there is no hook (only webhook).
You may use
pre-push
hook and run anothergit-push
command from within it. This way you can alter a destination ref, hence push data on a staging branch and abort execution of push on a production branch. Here is the sketch of a script:You need to consider some more complex cases, but I guess it should work after few adjustments .
Later you may run whatever tests you want on a CI server, push it to production and delete a staging branch. You probably want to configure each local repository so
git-fetch
prunes automatically:That way devs won't see outdated references to remote staging branches (if you choose to delete them).
Alternatively you could try to set master's upstream to an adequate staging branch. However it would probably get messy if you deleted a remote ref.
Bottom line
I don't think it's the most elegant solution, but I believe it answers your question directly. One of the drawbacks of this approach is the fact that ultimately it doesn't exit with 0. I don't know how it would be handled by some external tools. When you are using a command line it just generates an error line you can ignore.
You may want to consider @VonC's solution or some kind of other policy to prevent from pushing directly to a production branch.
EDIT:
A command line message would look like this: