Setting up a git server on your Ubuntu Server for Continous Integration
Tags: backend, ci, git
Published: 2020-11-14 18:13:28

Hey there! 👋 In the spirit of modern dev practices, I am writing this blog to highlight a life saver for me. When I started out as a backend developer,  I used Heroku (and still use it occasionally) which has this amazing way of automatically building and deploying your apps whenever you push to the connected git repositories. I was forced to learn how to do it myself when my work started driving me to use bare-bone machines on AWS or Digital Ocean and I would always have to SSH into the server just to manually pull from my git repo and build it on my server before deploying. Coming from a lazy perspective, this was crazy work that I wasn't ready to do each time I make a change to the app and the spirit of automation started ringing in my ears.
The words that came into my head were "GIT SERVER"! I googled to see if it was a thing and luckily it was. I finally figured out how GitHub was able to do it. So I embarked on my own journey to make my own git server.
The next few paragraphs detail how I conquered that beast;
Well you do need git installed for starters so go do that first. This article assumes you have SSH set up on your ubuntu server.

### Step 1
The first thing we need to do is create a git bare repository on our server.
```bash
# incase you already have a codebase
git clone --bare remote_repo_url.git server_repo.git

# but if you wanna start from scratch you could just use init
mkdir server_repo.git && cd server_repo.git
git init --bare
```
A bare git repository isn't like a regular repository. It stores our git objects but not the actual source code. It's typically the `.git` folder in a regular repository. After that we need to create a directory on the server to store the actual source code:
```bash
mkdir server_source
```

### Step 2
Now, from a machine that has SSH Access to your ubuntu server you'll add your bare repository as a git remote:
```bash
git remote add production <username>@<machine>:server_repo.git

# You can now push to this remote
git push production master

# Or pull from it
git pull production master
```
basically `server_repo.git` has to be the location of your bare repo on the ubuntu server while `username` and `machine` are your login details just like when logging in with SSH.

### Step 3
Next is the feature that makes all this possible. GIT HOOKS! I have written about them in the past here: {% medium https://medium.com/faun/how-to-automate-tests-on-each-push-to-the-repository-378fdcca7f8e?sk=93593a45397474307b32ce67c46ba5ab %}
Feel free to check it out. So essentially the hook we would be needing is the `post-receive` hook.
As the name implies, It runs after (post-) git objects are received from a remote.
Below is a typical `post-receive` file:
```bash
#! /bin/bash

# we have to set GIT_DIR env var to the bare repo
WORK_TREE=$HOME/server_source
GIT_DIR=$HOME/server_repo.git

# next up we have to checkout from our bare repo
git --work-tree=$WORKTREE --git-dir=$GIT_DIR checkout -f

# from here on we can do any other processes like building and 
# deploying the app
cd $WORK_TREE
docker-compose up --build -d
```
Now all we need to do is add this file to our git hooks. In our bare repo `server_repo.git` we need to create a new file `post-receive` under the `hooks` folder and then store the above in it.
We also need to make it executable on linux using `chmod`.
```bash
chmod a+x post-receive
```
After this we are good to go! Anytime we push to our production remote from our local, it will run the `post-receive` script and deploy our app.

If you have any questions, I'll be waiting in the comment sections to deal with it 🏌️‍♂️🏌️‍♂️