Tutorial: Introduction to git and Github

Table of Contents

Preparation

Installing and configuring git

First install the git client on your machine (if it is not already installed). At first use, you need to configure your name and email address:

git config --global user.name "Your Name"
git config --global user.email "name@domain.com"

SSH keys

To avoid having to enter your password every time you interact with git, you can use SSH keys.

Creating a new SSH key

To create a new SSH key, open a terminal and type:

ssh-keygen -t ed25519

You will be asked to enter a file in which to save the key. Press enter to use the default location. You will then be asked to enter a passphrase.

Adding the SSH key to your Github account

To add the SSH key to your Github account, first copy the key to the clipboard. The key can be shown in the terminal by typing (if you used the default location):

cat ~/.ssh/id_ed25519.pub

Then go to your Github account settings, select “SSH and GPG keys” and click on “New SSH key”. Give it a name and paste the key into the “Key” field.

Using an SSH agent

To avoid having to enter the passphrase every time you use the SSH key, you can use an SSH agent. To start the SSH agent, type:

eval "$(ssh-agent -s)"

Then add the SSH key to the agent:

ssh-add ~/.ssh/id_ed25519

Initializing a repository

Git is a distributed version control system. This means that while there usually is a repository called a “remote” on a server, e.g., on Github,, every user has a local copy of the repository.

Creating a new repository

To create a new repository on Github, click on the “+” sign in the top right corner and select “New repository”. Give it a name and a description and click on “Create repository”. You will be redirected to the repository page.

Cloning a repository

Copy the SSH link to the repository by clicking on the green “Code” button and selecting “SSH”. Then open a terminal and navigate to the directory where you want to clone the repository. Then type:

git clone <SSH link>

Daily workflow

Pulling changes

Before starting to work on the code, you should always pull the latest changes from the repository to make sure that the local copy is up to date. To do so, navigate to the repository directory and type:

git pull

Making changes

After pulling the latest changes, you can start working on the code. Once you are done, you can check which files have been changed by typing:

git status

You can then add the files to the staging area by typing:

git add <file1> <file2> ...

or add all changed files by typing:

git add .

You can then commit the changes by typing:

git commit -m "Commit message"

where the commit message should be a short description of the changes you made. Finally, you can push the changes to the remote repository by typing:

git push

It is recommended to make separate commits for separate changes and to make the commit messages as descriptive as possible. The following is one possible convention for commit messages:

<category>: first thing; second thing

where <category> is one of the following:

The commit message should be written in the present tense and should not end with a period.

.gitignore

Often, there are files that you do not want to tracked by git. This includes, for example, temporary and binary files. To tell git to exclude certain files, the .gitignore file can be used. This is usually placed in the root of the repository, but can also be placed in specific subdirectories, in which case it only applies there. Specific files or directories are ignored by listing their names or paths in .gitignore; glob patterns can be used, leading to content like

*.<extension>
<subdirectory>
<subdirectory 2>/<filename>

It can be useful to add the .gitignore file to the repository as well, such that the same rules apply in each clone:

git add .gitignore

Branches

Branches are useful to work on new features without affecting the main code. The main branch is usually called “main” or “master”. To create a new branch, type:

git branch <branch name>

You can then switch to the new branch by typing:

git checkout <branch name>

You can check which branch you are currently on by typing:

git branch

You can then make changes to the code as described above. Once you are done, you can push the branch to the remote repository by typing:

git push -u origin <branch name>

Again, there are some conventions for branch names:

<category>/<reference>/<branch name>

where <category> is one of the following:

<reference> is a reference to an issue or pull request (or no-ref if there is no reference), and <branch name> is a short description of the branch in lower case and spaces replaced by -.

Merging branches

Once you are done working on a branch, you can merge it into the master branch. To do so, first switch to the master branch by typing:

git checkout master

You can then merge the branch into the master branch by typing:

git merge <branch name>

Conflicts

If you try to merge a branch into another and there are conflicts, you will be notified. You can then open the file that has conflicts and resolve them manually. Conflicts are marked by:

<<<<<<< HEAD
...
=======
...
>>>>>>> <branch name>

The part between <<<<<<< HEAD and ======= is the code in the current branch, more precisely in the workspace. The part between ======= and >>>>>>> <branch name> is the code in the other (“incoming”) branch. You can then decide which code to keep and which to discard. Once you are done, you can add the file to the staging area by typing:

git add <file>

You can then commit the changes by typing:

git commit -m "Commit message"

Advanced tools

This is just a selection and overview over some more advanced topics.

Large file storage (LFS)

If you are regularly working with large or binary files that you still need to be versioned, including them in the repository can lead to problems such as exceeding server limits and slow cloning/fetching. A possible solutio is to use git large file storage (LFS) which stores the (versions of the) files separately and replaces them with links in the actual repository, thus getting the best from both worlds. To set up git lfs for a new user, type

git lfs install

In the repository, files can be specified to be tracked by git lfs using

git lfs track <file/pattern>

This will add/modify the file .gitattributes which it might again be useful to add to the repository

git add .gitattributes

In case LFS is set up for a repository with existing versioned files that should be tracked by LFS instead, they can be migrated (after specifying the rules)

git lfs migrate

Github Actions

Github Actions can be used to automatically run commands on the server, e.g., to build, test, deploy etc. The corresponding “workflows” are set up using YAML files in .github/workflows/. A simple example might have the following structure

name: <name>
on:
  push:
    branches:
      - <branch name>
      - <branch pattern>
jobs:
  build:
    runs-on: <platform>
    steps:
      - uses: actions/checkout@v4
      - name: <name of the step>
        run: <command>

where the line uses: actions/checkout@v4 calls an action from the library, in this case one that checks out the repository such that all the files are actually available.

For example, to test the python script app.py using pytest on several Python versions whenever something is pushed to the master branch:

name: Python test
on:
  push:
    branches:
      - master
jobs:
  build:
    runs-on: ubuntu-latest
    strategy:
      matrix:
        python-version: [ "3.10", "3.11", "3.12" ]
    steps:
      - uses: actions/checkout@v4
      - name: Set up Python $
        uses: actions/setup-python@v5
        with:
          python-version: $
      - name: Install dependencies
        run: |
          python -m pip install --upgrade pip
          python -m pip install pytest
      - name: Test with pytests
        run: |
          pytest app.py

For more details, check the documentation.