DEV Community

Cover image for Easy Automatic Code Deployment With Git
brandon_wallace
brandon_wallace

Posted on • Updated on

Easy Automatic Code Deployment With Git

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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/
Enter fullscreen mode Exit fullscreen mode

Set the permissions on the directory.

$ sudo chown $USER:$USER /var/repos/my_project.git/
Enter fullscreen mode Exit fullscreen mode

Move into the my_project.git/ directory.

cd /var/repos/my_project.git/
Enter fullscreen mode Exit fullscreen mode

Run the git init --bare command inside the /var/repos/my_project.git/ directory.

$ git init --bare
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Use any text editor to edit the post-receive file.

$ vim hooks/post-receive
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

The post-receive script is not executable.

$ ls -lF hooks/post-receive 

-rw------- 1 brandon brandon 0 Nov  2 21:19 hooks/post-receive
Enter fullscreen mode Exit fullscreen mode

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*
Enter fullscreen mode Exit fullscreen mode

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/
Enter fullscreen mode Exit fullscreen mode

Move into the directory.

$ cd my_project/
Enter fullscreen mode Exit fullscreen mode

Set up git in the project directory with a few basic files.

$ git init

$ touch .gitignore readme.md LICENSE
Enter fullscreen mode Exit fullscreen mode

Add content to the readme.md file.

$ echo '# My Auto Deploy Project' >> readme.md
Enter fullscreen mode Exit fullscreen mode

With any text editor add a simple index.html file to the project.

$ vim index.html
Enter fullscreen mode Exit fullscreen mode

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>
Enter fullscreen mode Exit fullscreen mode

Add all the files to Git and commit the changes.

$ git add --all

$ git commit -m "First commit"
Enter fullscreen mode Exit fullscreen mode

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.

create-gh-repo.png

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
Enter fullscreen mode Exit fullscreen mode

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'.

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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)
Enter fullscreen mode Exit fullscreen mode

I will make some changes to the project and push those to the production server.

$ touch style.css
Enter fullscreen mode Exit fullscreen mode

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;
}
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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

Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

You get the error:

ssh: Could not resolve hostname github.com: Temporary failure in name resolution
fatal: Could not read from remote repository...
Enter fullscreen mode Exit fullscreen mode

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.

GithubDEV.to

Feel free to leave feedback, comments, or suggestions.

Discussion (2)

Collapse
itr13 profile image
Mikael Klages

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

Collapse
brandonwallace profile image
brandon_wallace Author

Mikael, That is a great idea.