Introduction
I will show you how to deploy code to a live server easily with Git.
Let's say you have already deployed your project to a live server. A few days later you receive valuable feedback on your project from another developer. You decide to make some improvements to the project. You work in your local Git repository to make the changes. You test everything to make sure it is working the way you intended it to work. Then you commit the changes in your code to your local Git repository. Then you push those changes to Github.
How do you go about getting those improvements to the live server? Would you log into the server and meticulously edit the file manually?
There is an easy way to deploy code to a live server - use Git. All you need it is the ability to SSH to the server.
Here is the syntax for the git push command:
$ git push <repository> <branch_name>
Example:
$ git push origin main
The origin
is first repository that is set up and usually represents the repository connected to the Github website.
To get code to a live server, I will create a second repository on the live server to push code to. I will call the second repository "prod" to represent the repository on the live production server.
After pushing code to the "origin" repository I will be able to push to "prod" any code ready for production.
When I am ready to push code to the production server I run this command.
$ git push prod main
On the server
We need two directories on the server, one for the application which holds the production code, and one directory for the Git bare repository.
Directory for production code:
/var/www/my_project/
Git bare repository:
/var/repos/my_project.git/
Set up a repository on the server.
The first step to set this up is to create a bare repository on the web server where you will run the application.
SSH to your server. My server has the user brandon
and the IP address 123.45.67.89
. So I use this command.
$ ssh brandon@123.45.67.89
Create the directory as a Git bare repository with a .git
at the end of the name.
$ sudo mkdir -p -v /var/repos/my_project.git/
Set the permissions on the directory.
$ sudo chown $USER:$USER /var/repos/my_project.git/
Move into the my_project.git/
directory.
cd /var/repos/my_project.git/
Run the git init --bare command inside the /var/repos/my_project.git/ directory.
$ git init --bare
The directory structure should look like this.
$ tree --dirsfirst -F
.
├── branches/
├── hooks/
│ ├── applypatch-msg.sample*
│ ├── commit-msg.sample*
│ ├── fsmonitor-watchman.sample*
│ ├── post-update.sample*
│ ├── pre-applypatch.sample*
│ ├── pre-commit.sample*
│ ├── pre-merge-commit.sample*
│ ├── prepare-commit-msg.sample*
│ ├── pre-push.sample*
│ ├── pre-rebase.sample*
│ ├── pre-receive.sample*
│ ├── push-to-checkout.sample*
│ └── update.sample*
├── info/
│ └── exclude
├── objects/
│ ├── info/
│ └── pack/
├── refs/
│ ├── heads/
│ └── tags/
├── config
├── description
└── HEAD
Creating a hook to perform an action.
A hook will allow you to run a script when a particular action occurs. There are hooks that run on the client and hooks that run on the server. I will set up the server-side hook post-receive
that will run once a git push has finished executing.
Create a file called post-receive
in the hooks directory.
$ touch hooks/post-receive
Use any text editor to edit the post-receive file.
$ vim hooks/post-receive
Add the following content, change the paths to reflect your set up.
#!/bin/sh
git --work-tree=/var/www/my_project/ --git-dir=/var/repos/my_project.git checkout -f main
The post-receive script is not executable.
$ ls -lF hooks/post-receive
-rw------- 1 brandon brandon 0 Nov 2 21:19 hooks/post-receive
Make the script executable by running the chmod
command.
$ chmod +x hooks/post-receive
$ ls -lF hooks/post-receive
-rwx------ 1 brandon brandon 0 Nov 2 21:19 hooks/post-receive*
On my laptop
Connect your local repository to the server repository.
On the client machine where my local repository is located I will connect that repository to the one I created on the live server.
Create a local repository with the same name as the directory on the server minus the .git
extension.
$ mkdir my_project/
Move into the directory.
$ cd my_project/
Set up git in the project directory with a few basic files.
$ git init
$ touch .gitignore readme.md LICENSE
Add content to the readme.md file.
$ echo '# My Auto Deploy Project' >> readme.md
With any text editor add a simple index.html file to the project.
$ vim index.html
Add the following content to the index.html file.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1" />
<meta name="description" content="My auto deploy project.">
<link rel="stylesheet" href="style.css">
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>
Add all the files to Git and commit the changes.
$ git add --all
$ git commit -m "First commit"
Create a new repository on Github without the readme.md, .gitignore, or LICENSE. We have already created those files for the Github repository. Name the Github repository the same as the local repository. My local repository is called my_project
so I use the same name to create the Github repository. See screenshot below.
Connect the local repository to Github. Make sure the branch is called main
.
$ git remote add origin git@github.com:brandon-wallace/my_project.git
$ git branch -M main
Set origin
as the default repository to push to.
$ git push -u origin main
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 4 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (5/5), 550 bytes | 550.00 KiB/s, done.
Total 5 (delta 0), reused 0 (delta 0), pack-reused 0
To github.com:brandon-wallace/my_project.git
* [new branch] main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.
I have successfully connected the local repository to Github. Now I will connect the local repository to the live production server. My server has the IP address 123.45.67.89
and SSH on port 22
so I run this command with the full path to the my_project.git
directory.
Syntax:
$ git remote add <remote_repository> ssh://<username>@<server_ip>:<port>/path/to/<project>.git
This is the command I run.
$ git remote add prod ssh://brandon@123.45.67.89:22/var/repos/my_project.git
When I want to push code to the production server. I run this command.
$ git push prod main
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 4 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (5/5), 550 bytes | 550.00 KiB/s, done.
Total 5 (delta 0), reused 0 (delta 0), pack-reused 0
remote: Switched to branch 'main'
To 123.45.67.89:/var/www/my_project_repo/my_project.git
* [new branch] main -> main
View the remotes. This shows that there are two remote repositories available, prod
and origin
.
$ git remote -v
prod ssh://brandon@123.45.67.89:22/var/repos/my_project.git (fetch)
prod ssh://brandon@123.45.67.89:22/var/repos/my_project.git (push)
origin https://github.com/brandon-wallace/my_project.git (fetch)
origin https://github.com/brandon-wallace/my_project.git (push)
I will make some changes to the project and push those to the production server.
$ touch style.css
Add some content to the CSS file with any text editor.
$ vim sytle.css
# Example content
html {
font-size: 100%;
}
body {
background: #FFFFFF;
font-family: sans-serif;
font-weight: 400;
line-height: 1.75;
color: #000000;
}
h1 {
margin-top: 0;
font-size: 3.052rem;
}
Add the new CSS file. Commit the changes to the repository.
$ git add style.css
$ git commit -m "Add CSS file"
# Output
[main 8881680] Add CSS file
1 files changed, 27 insertions(+), 3 deletions(-)
create mode 100644 style.css
Right now, on the server I can see four files in my_project/
.
$ /var/www/my_project/ $ ls -l
total 12
-rw-r--r-- 1 brandon brandon 319 Nov 7 10:25 index.html
-rw-r--r-- 1 brandon brandon 0 Nov 7 10:25 LICENSE
drwxr-xr-x 8 brandon brandon 4096 Nov 7 10:25 my_project.git
-rw-r--r-- 1 brandon brandon 25 Nov 7 10:25 readme.md
Push the changes to the production server.
$ git push prod main
Enumerating objects: 6, done.
Counting objects: 100% (6/6), done.
Delta compression using up to 4 threads
Compressing objects: 100% (4/4), done.
Writing objects: 100% (4/4), 623 bytes | 623.00 KiB/s, done.
Total 4 (delta 2), reused 0 (delta 0), pack-reused 0
remote: Already on 'main'
To 123.45.67.89:/var/repos/my_project.git
083f700..8881680 main -> main
Now on the server I can see the style.css
I just pushed to the prod
repository running on the live server.
/var/www/my_project $ ls -l
total 16
-rw-r--r-- 1 brandon brandon 362 Nov 7 10:56 index.html
-rw-r--r-- 1 brandon brandon 0 Nov 7 10:25 LICENSE
drwxr-xr-x 8 brandon brandon 4096 Nov 7 10:56 my_project.git
-rw-r--r-- 1 brandon brandon 25 Nov 7 10:25 readme.md
-rw-r--r-- 1 brandon brandon 365 Nov 7 10:56 style.css
Troubleshooting
First, check carefully for spelling errors is highly recommended.
If you get -bash: git: command not found
error install git
.
$ sudo apt update
$ sudo apt install git
You get the error:
ssh: Could not resolve hostname github.com: Temporary failure in name resolution
fatal: Could not read from remote repository...
You need to set up SSH keys on Github.
Conclusion
I hope you learn something new by reading this article. Using Git you can easily push changes to a project to a live production server.
Feel free to leave feedback, comments, or suggestions.
Latest comments (2)
A dumb but very simple and often good enough trick I used on some server specific discord bots I used to run, was to have a command to stop the bot, and a separate python script that did
git reset --hard
, then pulled, before starting the bot again.Ugly, but surprisingly durable
Mikael, That is a great idea.