Each developer will inevitably come to the moment when he needs to upload his work to remote server. There are many options how you can accomplish this, you can use some FTP/SFTP client like FileZilla, rsync, scp or Git. I have been using FTP clients for a long time when I was starting, then I moved to terminal programs like scp. Everything was working quite good, but it was a bit tedious job, and there were moments when random errors would occur. With all of these programs you have no control over versions of your code, nor you can rollback to some previous version.
Git came as only viable solution for all of these issues. It is very easy to setup, it keeps track of modified files and if file is committed it will only upload difference between previous version of that file and current version. Because of this it's very fast. It also posses a bunch of advanced features so you can create all kinds of hooks, workflows or environments. Git posses great documentation with many useful examples.
Basic Git workflow for me is when I have local repository on my desktop, and some remote repository on live server where only I push commits. This is most used workflow for me, cause I always test my code on demo servers before I push any code to production servers or share with my team.
Few months ago I found really good explanation how to setup this basic Git workflow here. I will try to summarize it here. Basic idea is to have public folder on our server which will serve pages to visitors, and to have one more folder which is called bare Git repository which will act as a hub (address) for pulling and pushing changes.
Git needs to have intermediate hub folder cause it does not allow pushing changes directly to checked-out branch of live repository (folder). That hub folder is usually ending in .git (not needed) and that is the url which you will use as Git remote url.
Also it is good idea to move away this Git hub from public folder, so it can only be accessed by authenticated users.
From this graph you can see that I only communicate with Git hub on remote server, and in the back that Git hub communicates over Git hooks with public folder. If web server of your choice is Apache then default public folder is
/var/www/html/ and you can place this Git hub folder anywhere just take care it is outside of public folder.
Automated script described in this post will create empty public folder for application, create bare Git repository (Git hub), connect these 2 by defining Git bare repository as hub of public folder. After this it will create 2 Git hooks, post-update and post-commit. At the end it will configure permissions for hook files and the ownership over files.
Cause each week I create new repositories on remote servers multiple times, I find this script a great timesaver.
#!/bin/bash clear #take path of public folder and create it echo "Please enter ABSOLUTE PATH of web server public folder for this project, that will be your publicly visible web folder (for Apache /var/www/html/...)" read webFolderPath while true; do read -p "You entered: $webFolderPath is that correct path? y/n?" yn case $yn in [Yy]* ) mkdir -p $webFolderPath; break;; [Nn]* ) echo "Script stopped"; exit;; * ) echo "Please answer yes or no.";; esac done #cd into public folder and initialize git there cd $webFolderPath; git init; #take path of bare git repository and create it echo "Please enter ABSOLUTE PATH of bare git repo, that will be you main entry point for pushing/pulling to remote server, one that ends with .git: " read gitBareRepo while true; do read -p "You entered: $gitBareRepo is that correct path? y/n?" yn case $yn in [Yy]* ) mkdir -p $gitBareRepo; break;; [Nn]* ) echo "Script stopped"; exit;; * ) echo "Please answer yes or no.";; esac done #cd into git bare repository and initialize bare repository there cd $gitBareRepo; git init --bare; #define bare repository as hub of public folder cat <<EOT > $webFolderPath"/.git/config" [remote "hub"] url = $gitBareRepo fetch = +refs/heads/*:refs/remotes/hub/* EOT #create post-update hook in git bare repository, for syncing files with public folder cat <<EOT > $gitBareRepo"/hooks/post-update" #!/bin/sh echo echo "**** Pulling changes into Live [Hub's post-update hook]" echo cd $webFolderPath || exit unset GIT_DIR git pull hub master exec git-update-server-info EOT #create post-commit to sync back with bare repository, #if you decide to change something directly from public folder cat <<EOT > $webFolderPath"/.git/hooks/post-commit" #!/bin/sh echo echo "**** pushing changes to Hub [Live's post-commit hook]" echo git push hub EOT #take username that will use this repository echo -e "Please enter server username of user that will be using this repository: \c " read username #add execute permission to 2 hooks sudo chmod +x $webFolderPath"/.git/hooks/post-commit"; sudo chmod +x $gitBareRepo"/hooks/post-update"; #customize ownership over files sudo chown -R $username $webFolderPath; sudo chown -R $username $gitBareRepo;
Uploading script to remote server via scp
Idea is that you will activate this script on remote server so you need to have access to that server. I usually use scp program to upload similar Git workflow scripts. If we take that on my local desktop this script is located at /home/ivan/Documents/basic-git.sh and I want to upload it to /home/ivan/basic-git.sh on remote server I will use: scp /home/ivan/Documents/basic-git.sh demo-server:/home/ivan/basic-git.sh
SSH connection shortcuts
This demo-server word is actually shortcut for creating SSH connection to remote server. You can create these shortcuts inside ~/.ssh/config on your local desktop. Format of entries it following:
Host demo-server Hostname 220.127.116.11 User ivan IdentityFile /home/ivan/.ssh/tuts.pem IdentitiesOnly yes
From this configuration you see host (or as I call it SSH shortcut), ip address of the server or hostname, username on remote server, identity file or private RSA key and in last line declaration to only use key file for connecting to this host. After you save this config file you will be able to SSH into remote server with only ssh demo-server instead of typing full data like ip address, username and key file.
Creating RSA key (if you don't have it)
If you are unfamiliar with creating RSA keys you can generate new set of keys with ssh-keygen -t rsa -b 4096 -C "firstname.lastname@example.org" where you will enter your own e-mail address. Do not setup passphrase for this key so you can push/pull without distractions.
After you have generated new set of keys you need to upload public key to remote server. You will go into home directory of user you use to connect to remote server and visit ~/.ssh/authorized_keys file or create it if it doesn't exists. There you will copy on new line entire content of public key, one with content like ssh-rsa AAAAB3NzaC.... email@example.com
Running script on remote server
Once when you upload this script you can activate it with bash basic-git.sh from command shell (terminal) it will ask you for ABSOLUTE PATH of public folder that you want to create for this new project. Usually something under /var/www/html/...
Please enter ABSOLUTE PATH of web server public folder for this project, that will be your publicly visible web folder (for Apache /var/www/html/...) /var/www/html/tutorials-public You entered: /var/www/html/tutorials-public is that correct path? y/n?y Initialized empty Git repository in /var/www/html/tutorials-public/.git/
As you can see from the output it has created new /var/www/html/tutorials-public folder, confirmed that path is OK and initialized empty Git repository inside. First part is completed.
Please enter ABSOLUTE PATH of bare git repo, that will be you main entry point for pushing/pulling to remote server, one that ends with .git: /var/repositories/tutorials.git You entered: /var/repositories/tutorials.git is that correct path? y/n?y Initialized empty Git repository in /var/repositories/tutorials.git/
Second part of the script initialized Git bare repository and connected it with public folder in the back.
Last part is asking for username that will be using this Git hub.
Please enter server username of user that will be using this repository: ivan
Now we have empty repository on remote server with zero commits like when you create new repository on GitHub without initial README file.
Pushing code to remote server
First I need to setup Git remote on my local copy of my project, I will do that with following command:
git remote add origin demo-server:/var/repositories/tutorials.git
After I have committed all the changes I am ready to push my initial commit to remote system with:
git push origin master:master
Finally I have my code on remote public folder and my web server will start to serve that code to visitors.
You can find entire code used in this tutorial on Github.