Git Repository

Part 1, Chapter 3

Initial Setup

First things first -- let's create a new project:

$ mkdir talk-booking
$ cd talk-booking
$ git init

Add a new .gitignore file. Then, add the contents from the Python .gitignore template found here.

Add the .gitignore to git and commit:

$ git add .gitignore
$ git commit -m 'Initial commit'

Although you could add the .gitignore to git later, it's a great idea to do that right away to avoid adding unwanted files to git.

Create a new account on GitLab (if you don't have one already). Next, log in to GitLab and add an SSH key to your account (again, if you don't have one already). Go back to the home page and click on "New project". Next, select "Create blank project" and set its name to talk-booking.

After your project is created, copy it's SSH URL.

Next, add the new remote and push your initial commit:

$ git remote add origin [email protected]:<your-gitlab-username>/talk-booking.git
$ git push -u origin master

Mono-repo vs Poly-repo

The decision here is simple: Always start with a monorepo. It doesn't matter whether you're building a Django full-stack monolith, a JavaScript SPA with a backend RESTful API, or a serverless microservice -- each new repository is a new thing to create and, more importantly, maintain. It's much easier to track issues, PRs/MRs, commits, and deploys when things are kept in a single place. That doesn't mean you should never split your single repository up into multiple repositories; just not at first. Once you start splitting services into separate repositories, it's very, very difficult to go back.

If some part outgrows the monorepo you can move it into a new repository. It makes sense when the development for this part becomes completely independent. For example, an internal Python library that's used across multiple projects. It should have its own development cycles, releases, issue tracking, and so forth. Once it's moved, other projects can then install it directly from PyPI.

Repository Structure

Building high quality, full-stack software requires much more than just putting together a web app. We have to build libraries, manage infrastructure, develop APIs and UIs, and write scripts, etc. Therefore, we need a repository structure that will allow us to match that complexity without making a mess. We'll use the following folder structure:

  • lib
  • infrastructure
  • services
  • ci_cd
  • tools


The "lib" folder should contain internal library packages that are deployed to private registries -- e.g., PyPI, NPM, and Maven. Services should install those packages as third-party dependencies -- they should not install it from path.


The easiest way to manage servers, subnets, load balancers, managed databases, etc. is by using Infrastructure as Code (IaC). Inside the "infrastructure" folder we'll store configuration files for our tool(s) of choice. These are usually long YAML, JSON, or HCL files.


Anything that is long-running or talks to our end users is considered a service. It can be monolithic Django application, VueJS UI, or a couple of microservice APIs -- all will reside in this folder.


We need to configure our CI/CD pipeline. That's usually done via a YAML file, which will be stored in the "ci_cd" folder. You may also need some special Docker images to run your CI/CD jobs, so there will be a number of Dockerfiles in this folder when all is said and done.


You're a developer, so you don't want to repeat tasks over and over again. Put your tools here and make them available to your teammates too. All scripts that don't have a home go here.


When and how often should you commit? What should you write as a commit message?

Another topic that usually increases the heat in a room full of developers. While there are many guides on this, let's keep it simple. For commit messages, why do we add messages to a commit in the first place? After all, each commit has its unique hash. The answer is quite simple: To know what changes we did in the commit. Simple as that. So do just that in your messages:

Increased max body size from default 2.5 MB to expected 10 MB

Ref talk-booking/#123

Describe what you did and add reference to the issue so you can keep track of it. The reference in this example is from an issue on GitLab but you can do something similar for Jira or any other issue tracker.

Next, when and how often should you commit? Commit as early as possible. If you're following Test-driven Development (TDD), commit after each test passes. Make sure your commits are small; it will be much easier to track changes and perform code reviews.

What Have You Done?

In this chapter, you created a new git repository for your project and added a .gitignore template designed for Python projects. At this point, your project structure should look like this:

└── .gitignore

Mark as Completed