xczkaq

FTP is so 90's. Let's deploy via Git instead!

Update: This article has been published in Hacker Monthly issue 42.


First, create a directory on your server and initialize an empty git repository. I like to serve my websites from ~/www/, so that's what I'll do in this example.

mkdir ~/www/example.com && cd ~/www/example.com
git init

Next, let's set up your server's git repo to nicely handle deployment via git push.

git config core.worktree ~/www/example.com
git config receive.denycurrentbranch ignore

Finally, we'll set up a post-receive hook for git to check out the master branch so your web server can serve files from that branch. (Remember, ^D is Control+D, or whatever your shell's EOT character is.

cat > .git/hooks/post-receive
#!/bin/sh
git checkout -f
^D
chmod +x .git/hooks/post-receive

Keep in mind that you can add whatever you like to the post-receive hook if you have a build process. For example, one of my sinatra projects uses the following post-receive hook:

#!/bin/sh
git checkout -f
bundle install
touch ~/www/example.com/tmp/restart.txt

Back on your local machine, let's get your git repo ready for deployment.

cd ~/www-dev/example.com
git remote add origin \
ssh://user@example.com/home/user/www/example.com

For the first push to your server, run the following command.

git push origin master

Now, whenever you want to deploy changes you've made locally, simply run the following command!

git push

37 Responses
Add your response

502
Fc98a096fb23cd5f5231b4f25abfcd7e

Awesome tips. Thank you.

over 1 year ago ·
856
Dsc 8066v square

This is literally the first straight-forward walkthrough on how to do this that I've seen. Excellent work, man!

over 1 year ago ·
893
C452638be206345b2c22e09031c68f50

This post-receive hook method is going to cause problems when
(a) there is more than one server (a remote for each)
(b) the deploy is not fast-forward (conflicts)
(c) there is any "build" involved in making the code ready to run
(d) there are other artifacts in the working tree not from the code repo that need to be updated as well

over 1 year ago ·
1018
2956e2cd2664630aa968b92bbb645f2f

@gpoulter

(a) I Haven't looked into multi-server deployment, sorry.
(b) Just use git push origin master -f to force when it's not a fast-forward.
(c) If there's a build, script it and add it to the post-receive hook. It's just a shell script.
(d) That's true, but this assumes all your files are in the git repo. If not, you'll have to update those manually (such as via scp), or add something in the post-receive hook to take care of it.

over 1 year ago ·
1310

Using an SCM (be it GIT, svn, hg or whatever) is an excellent means of distributing all kinds of assets - images, control files, scripts. I even know people who keep their .bashrc and .profile files (and other portable tools) in github and pull them down as they move to different client sites. The efficiency that comes with versioning, hosting and accessing through these tools can make you look super-organised

over 1 year ago ·
3108
C5c54a86bda8ef40b570eacf7b9be078

+1 for the principle. Reminds me of a blog post about using a git repo from blogging. It has all the concepts of editing, posting etc.

over 1 year ago ·
3392
7dc85c0da8496aa25b227be94fe1c40e

More tips:

If you're working with a team and you're the one who deploy the code:

  1. init and setup the deploy server repo

  2. on your git repo, use git remote add deploy %serverdeployurl%

  3. optional: setup a branch for deployment if you have some extra configuration, or just use master. If you use a branch, make sure you checked out the correct branch in post-receive hook

  4. use git push deploy master (or name of your deployment branch)

over 1 year ago ·
4222
70e1167dbde5397557b0ec6fabb3d90a

Great method. I prefer using a bare repo outside of my public directory that has its working tree inside the pub directory.

This way there is no .git dir there and it tells you in pro git that this is the recommended way.

I made protip about this.

over 1 year ago ·
6775
3c87f46f8957315b07a64f91723e04e4

Why even FTP? Just develop live on the web server.

over 1 year ago ·
6856
723e458e33dea7e25e15e0ae9b1e8782

Great post. I plan on writing something similar in the future; essentially, how to "roll your own" git deployments.

For anyone still confused, here's something I wrote that is even more simple and involves much less command line knowledge:

http://adamjohnsondesign.com/blog/moving-ftp-git-deployment-designers-guide/

over 1 year ago ·
7361

It's a good post, but i must ask, why? FTP is in use over Git because it's simple to use, just like Windows is used by the majority even though Linux is technically better.

over 1 year ago ·
7362
D5036b21a633e42fdef897edfea88b53

Or Shell script:
$ export name=mynewrepo; curl -L -s tiny.cc/gitdeploy

Save to alias:
$ echo -e "\n alias scr='curl -L -s \$1'\n" >> ~/.bashrc
$ export name=mynewrepo2; scr tiny.cc/gitdeploy | sh

over 1 year ago ·
7363
Ccc2696b05a0650afe3f82375525d754

This is so wrong. This is looks like PHP-dev discovered git, but didn't read much about it.

1) If you going to deploy via git, at least do git export.
2) Capistrano exists for a reason

over 1 year ago ·
7364

The problem with this is the committed files are updated in a potentially long process, so the application may be broken for a few seconds or minutes if it contained large files.

I would suggest Capistrano as well or a CI instead depend on the size of the project.

over 1 year ago ·
7365
17a27d13d2195b4d6d273eb18c96d3a1

Checkout https://github.com/slimjim - my attempt at making this processes a little more easier

over 1 year ago ·
7366
6e1b896f6c4807aa4223acc428c57760

I came up with deliver https://github.com/gerhard/deliver to address this very problem. It's bash utility that automates git-based deploys and comes with pre-built strategies for the most common deployment scenarios: generated sites (think Jekyll), shared (WordPress, PHP etc.), ruby, node-js, S3 etc. I did a talk on it at my London Ruby User Group in March: https://speakerdeck.com/gerhardlazu/deliver

over 1 year ago ·
7369
121dcfb4f05ed316247772545e2cd590

It's pretty cool, although pull deploys scale better. Simples implementation of pull deploy would be with cron job fetching the git repo and more advanced way is to use Chef or Puppet for it, so that you can also introduce configuration changes in line with code changes.

over 1 year ago ·
7376
144314100b686db946ff68c7ae1065d1

@andoriyu 99, 400 people can't be wrong.

over 1 year ago ·
7377
Ccc2696b05a0650afe3f82375525d754

@NARKOZ They actually can be wrong.

over 1 year ago ·
7382

Oh, how cool is that? Not really. Used it years ago with subversion and other SCM. You can also use Dropbox and other methods. Your tip is so 2000.
But coming back to git or better SCM: never ever use the Master branch. I say never. That is so wrong. Use a dedicated branch or a tag or similar, especially in a multiuser environment. You need someone who has the knowledge who will guarantee, that the final deploy will work. You cannot guarantee that in the master, when several users have write access. You need someone who gives the final go after review.

over 1 year ago ·
7384
44df94106f92a3f506f5ad346918ba8f

The biggest problem with git is the scalability. We currently use it in an awsautoscaled environment. When the servers come up, obviously nothing is on /mnt. This causes git pack to cause high com and high io in the master as it computes from commit 0. This can be solved using shallow copy, however, there are major bugs with that if you use branches and you risk deploying the wrong code to the wrong server.

So what is the solution? We are still working on a good one. Right now wend up mounting an nfs mount when the server bootstraps and copy over a base image of the repository avoiding git pack-objects and the delta overhead which goes with it. Is it the answer? No. The hunt for that continues.

over 1 year ago ·
7393
6f68bcccc0e7a69763df4e6b114fc8db

Just doing a git pull --rebase in another directory (that isn't your webroot), copy to webroot, then remove the .git/ directory (plus any other sanitizing you'd like) is both low-risk and easy to script via something like Fabric or Capistrano.

over 1 year ago ·
7396
2cd3c6586f719bc64a324e8bf2d74333

Some additional explanation would be helpful.

  • What's the purpose of changing worktree? (I'm unfamiliar with the option, I've never needed to use it.)
  • Why are you calling the server remote origin? Seems more like "destination." (This could be very confusing to people users who aren't that familiar with git remotes.)
  • An explanation of the post-receive hook would be useful (I now get that after pushing you have to checkout on the remote to actually update the working dir but that wasn't immediately apparent).
over 1 year ago ·
7398
Aa81402492c6d39bc309b2a1b00766e8

Why wouldn't you just use a tool like Capistrano? Capistrano can deploy from Git as well, but it follows best practices like exporting a bare copy of the repo. It also provides niceties like rollback and ordered tasks (with before/after hooks) for that moment when you realize that you need to do something outside of dumping code in to a directory. Tacking on ad hoc bash scripts is what you do when better tools aren't available.

I'm all for exploring new ways to do the same old things, but this just strikes me as terribly incomplete and introduces some bad practices, like hosting a full copy of your git repo in the httpd document root.

over 1 year ago ·
8351
Ba916cb1c1327b700cf2f753684c2b4f

To be honest, this feels totally wrong. Writing 15 lines of command-line code, some of them totally cryptic, for a simple deployment, does not feel "simple", clean and professional. I would recommend professional Continious Integration tools and doing deployments with one click/command AND having the possibility to roll-back anytime.

over 1 year ago ·
9619
D9314e008d15617514278285a320099a

I think it makes more sense to deploy onto a stage, and archive the deployment files, then push them to the server in some way that is simple.That way they are assured to have been created.

We have been using VCS to do deployments of Wow addons for years, that has worked great - but you still have to wait for the built product to be prepared so you can post it ti alternate sites. It is nice though to have your build updated every time you commit.

over 1 year ago ·
10052
D842ec3b23a23afb16c1bafac0e2a274
git config core.worktree $(pwd)

Saves some time

over 1 year ago ·
11438
1249b517ac30f9a7d5b60049f3e4d972

This works really well for an event space site I manage. It's a simple site that deploys to two places; one prod server, and github. I have two remotes set up in git config:
eg:

[remote "origin"]
url = https://github.com/natalieolivo/suite116.git
fetch = +refs/heads/:refs/remotes/origin/
[remote "prod"]
url = "ssh://suite116@suite116.com/var/chroot/home/content/33/7051533/html"
fetch = +refs/heads/:refs/remotes/prod/

So when I need to deploy to the prod server I do a "git push prod". When I deploy to github I just do a "git push". No more ftp!

over 1 year ago ·
12257
1c5643af128c7ebffee890d24aefbdb8 normal

Love it, nice job with this.

over 1 year ago ·
12258
F357a1149b38270ad0d3aa0ec70aef0d

it works with GoDaddy Shared Hosting
(note: GoDaddy Shared hosting is come with git v1.8)

over 1 year ago ·
12568
Fc40847cc8bfa2442e47afb4b99b0d85

just use beanstalkapp :)

over 1 year ago ·
13525
Il 340x270.622268562 pge6

This is excellent. Thank you.

over 1 year ago ·
15093
Poolpog normal

Also what is wrong with this post, though probably a problem with the blog platform not the post: Not dated, and comments are also not dated. Was this posted in 2006, 2010, or 2014? It matters.

over 1 year ago ·
16806
David

ftp is still the easiest and more convenient way for noob like me..=)

over 1 year ago ·
17209
None

Trying to get this to work and I've gone through the entire process but I still get a "'/html/newproject' does not appear to be a git repository" when I try to push. I'm ssh into godaddy shared hosting. I try to do ssh://username@hostname/html/newproject but apparently that's not right. All the git files show up if I ftp into it.

Anyone have a solution for this?

over 1 year ago ·
21685
15

Finally time to kill FTP! Also @jore no no no, developing live on the server is not always a brilliant idea, develop locally, use git to a git server with backups and then use git to deploy!!

over 1 year ago ·
27756

Never knew git was able to do this....awesome!

4 months ago ·