Deploy git branches

2019-04-15 19:38发布

问题:

After struggling with and sorting out a workflow for web development with git, I've been tasked with adding in a staging server at the last second. We develop/test locally and push out to a repo, and now there needs to be a sandbox in between so people in other departments can play around and try out new things without breaking stuff.

Remote repo needs two long-running branches (in the spirit of nvie's branching model), master and develop.

We need to be able to push to one repo, and checkout the develop branch to test.site.com docroot, and when ready, merge develop into master and checkout master into site.com docroot

So on the server...

git init
git add .
git commit -m "Initial commit"
git checkout -b "develop"

And on our local machines...

git clone user@site.com:/repos/repo1.git
???
git push origin/develop (??? Updates test.site.com docroot)

And back to the server to make code live

git checkout "master"
git merge develop (??? Updates site.com docroot)
git checkout -b "develop"

And locally

git pull

Help with the question marks or alternative suggestions appreciated.

Edit: Am experimenting with some of the answers so far. Had come up with a completely hacky idea in the interim and thought I'd share:

One post-receive hook to rule them all.

We clone a bare repo and track develop. Push develop to origin/develop.

Post-receive - Set GIT_WORK_TREE to test.site.com, checkout -f develop

If the commit message contains "merge_master", sets GIT_WORK_TREE to site.com docroot,

git checkout master
git merge develop  
git checkout -f master (this would be for hotfixes)

Merge master back into develop and pull locally

After the dust settles, send email with difflog, wring your hands and have a sip of something strong.

How many different ways could that break?

回答1:

In git, you normally never push to repository that has checkout. At all. You can push to one except you can't push to the checked out branch, but you usually shouldn't. Mainly to keep things clearly separated and to avoid disrupting the central repository if the web server breaks and needs to be fixed up.

So you should have a bare (term used for repository without work tree) central repository. Everybody will be using that repository. It should live on your internal network and should not be in docroot of either public or test server. In fact I would strongly suggest not putting it on either server at all, but separate (possibly virtual) machine.

Now you have the web servers. They can be either working copies, or just exports created using git archive and can be updated either by cron, or post-update hook in the central repository.

Working copy is updated by git fetch central-repo-url master on site.com server and by git pull central-repo-url develop on test.site.com server (ok, the fetch + reset suggested in the other answer is probably better, because you are sure you don't have any changes there).

Export is updated by getting a zip or tar pack with git archive and extracting it. It's a bit more work.

Cron just runs the commands periodically. It's easier to set up, but the disadvantage is that there is a delay between push and the content appearing on the servers.

post-update hook is a more complicated to set up, but does not have that delay (there is obviously some delay since downloading the data takes some time too). Basically you create a script to run the update, that can be triggered either by ssh or web request on the servers. Than in the central repository you put script hooks/post-update, that will trigger the scripts on the servers. There should be no way to give them any parameters and the mechanism should not allow running any other code than those scripts for security reasons. You can make the hook more advanced by looking which branch was pushed (see git doc for where you find it) and triggering only the correct server.

Than git push origin develop will cause the test.site.com to be updated (but indirectly, via the scripts) and to make code live you'll do (on development machine; never work on server!)

git checkout master git merge develop git push origin master

and the last command will cause site.com to be updated, again indirectly via the scripts.



回答2:

My suggestion is to have both docroots be git working copies.

After this you have two options

  1. Have a cron job do something like git fetch development-repo; git reset --hard development-repo/branch for both. I've done stuff like this before, and the hard reset is a must: it'll nuke any random changes that have crept into your docroot somehow.
  2. Have a post-update hook in the development repo do the above every time somebody pushes something. Unfortunately I don't have a working example of this at hand.