Version control with git

Aims

  • Initialise a local git repository
  • Add files to track
  • Commit some changes

Learning outcomes

  • Understand the general principles of version control
  • Mastery of how git implements the main features of version control

General ideas about version control

Version control is an approach to coding that allows you to keep track of the code evolution.

You may think of coding as a linear process, where a first version is followed by another more advanced version, which is again followed by a successive more refined version and so on.

flowchart LR
    A[Version 1] -->  B[Version 2] --> C[Version 3]--> D[...]

This is not at all the case. In fact, as we develop our code we tyically try various ideas, similarly to what you would do if you were writing a novel, perform an experiment, or explore an uncharted territory.

flowchart LR
    A[Version 1] --> B
    B[Version 2] --> C[Version 3]--> D[...]
    A-->Aa[Variant 1.a]-->B
    A-->Ab[Variant 1.b]-->E[Alternative version 2]-->C

This is even more evident when collaboration is at play: different developers will try different approaches and require a system to keep track of their respective modifications and that helps them with bringing them together into a unified project. In fact, regularly, the various ideas need to come together and merge for the project to keep its unitary structure.

Version control tools serve precisely this purpose, and git is the most popular of such tools.

It is powerful, but its usage can be subtle at times, as illustrated by the following cartoon:

Git according to the celebrated comic strip xkcd

Version control therefore solves two problems:

  1. keeping track of the code changes performed by a single performs
  2. allow to harmonise and synchronise the code changes of various collaborators

We are going to focus mostly on the first part, but it is important to realise that git is an essential tool for code development in large projects.

Terminology

Repositories

Version control use repositories. These are a database of code versions, stored in an efficient manner, focusing on the changes between a version and another.

Clones

Each user of the repository has their own working copy of all the files (any kinds of files) of the project. This clone of the repository is typically stored on the local machine.

Changes to the local clone are not reflected in the repository unless the users explicitly require this to be the case.

Distributed version control

In distribute version control each user has a complete copy of the repository, and they can perform their changes independently from other users, work locally and offline and eventually do collaborative work by merging their own versions with the one of others.

In principle, this can be done without a central server (e.g. peer to peer). In practice, one often uses some form of online repository, e.g. Github, Gitlab etc.

Branch

Branching in git allow you to explore various ideas in parallel, developing in different directions and experimenting new features. Branching is a backbone ides in git.

A repository typically has a main branch where the functional code is stored. When we want to develop our code we create new feature branches

    %%{init: { 'logLevel': 'debug', 'theme': 'default' , 'themeVariables': {
              'git0': '#ff0000',
              'git1': '#00ff00',
              'git2': '#0000ff',
              'git3': '#ff00ff',
              'git4': '#00ffff',
              'git5': '#ffff00',
              'git6': '#ff00ff',
              'git7': '#00ffff'
       } } }%%
gitGraph
   commit id: "main"
   branch feature
   commit id: "main work"
   checkout feature
   commit id: "feature work"
   checkout main
   commit id: "more main work"
   merge feature

On every branch, we can store out individual advancements as commits (see below). Eventually, when we are happy for our feature to be integrated with the main branche, we merge the feature branch with the main branch.

Commits

When you want a change to be registered in the repository’s database, your commit your changes to the repository. This means that a new entry in the database is added, keeping track of a timestamp associated with your changes and (often) an explanatory description of what the modification entails.

Pushing [with the remote repository only]

If you also have a remote repository (e.g. on GitHub), you can synchronise the changes between the local branch and the remote branch via the push operation.

Fetching [with the remote repository only]

Fetch allows you to retrieve the changes from a remote repository, see them and decide whether to merge such changes with your local repository (or not).

Pulling [with the remote repository only]

Pulling is simply fetching, followed by automatic merging.

Bundling

An efficient way to produce a package out of a git repository is to construct a bundle. This is a single file that contains a collection of commits, branches and logs allowing you to transfer or store the repository’s content without requiring access to a remote server.

Scheme

Hands-on approach to git

We start off working locally and creating a local project.

To-dos

Previously, you should have created a project folder with a README.md file. We now want to setup our local git repository.

Task 1: initialise the repository

Go to the project folder vicsek-cpp and initialise the git repository.

Use the information above or git --help to find the correct command to use.

Task 2: create a .gitignore file and add it to the staging area

We want to tell git not to keep track of specifc files. For, example we want to ignore hidden files that are specific to MacOS. A hidden file/folder haas a name that starts with . .

To provide git with a list of files to ignore, we create a (hidden) configuration file inside vicsek-cpp called .gitignore.

Create such file and enter the following string

.DS_Store

Then add the .gitignore file to the staging area.

Check git status to see if your .gitignore is ready to be committed and then commit it with a suitable comment.

You should also get a message concerning your README.md file. What os the best course of action here?

Task 3: ignoring files and directly committing the changes

Suppose now that we also want to ignore all files that end with .txt. The .gitignore file accepts the wildcard *.

Modify the .gitignore to ignore all .txt files. With a suitable option to the git commit command, stage and commit the changes in a single go.

Then create two new files:

  • a notes.txt file
  • a notes.md file

Add all new files in the current folder with git add ., commit your changes to the repository and then check the files added to the repository with git ls-files.

Is notes.txt in your list?

Task 4: branching

We want to now start developing our code. For this purpose, we create a new branch called develop. To do so we use the command

git branch develop

To check which branches now exist in your repository just type

git branch

A * should appear on the branch you are on (which should be main). You leave the view using theQ key on your keyboard.

To switch to the develop branch use

git checkout develop

Check that you are on the right branch now (see above).

Once you are on your develop branch, create a new folder src where we will put the C++ code (do not remember how to create a folder? go back to Using the shell).

Inside src, create our C++ main file main.cpp, e.g. using a suitable editor (e.g. nano , pico or vim).

The minimal content should be the following

#include <iostream>

int main(){
    return 0
}

Now, add the src folder with its content to the git repository and commit the changes.

Switch back to the main branch: what happened to the src folder?

Task 4: merging

Now that you have your develop branch set up, attempt to merge it back with the main branch using the git merge command. If you are not sure about how to use it, check the documentation with git merge --help.

Task 5: bundling

Use now the command

git bundle create myrepo.bundle --all

to create a single bundle file conatining all of the repository. Move it to another folder (or even another machine with git, e.g. your Noteable account) and unpack it with

git clone myrepo.bundle

Can you check the branch structure? and the status?