Chapter 15
Distributed Version Control with git

 15.1 Prerequisites
  15.1.1 Assumed Knowledge
  15.1.2 Linux and Network Setup
 15.2 Version Control Concepts
 15.3 Setup a Git Repository
  15.3.1 Example Scenario
  15.3.2 Setup the Repositories on Server
 15.4 Using Git
  15.4.1 Clone an Existing Repository
  15.4.2 Configure the Git Client
  15.4.3 Common Git Operations

File: nsl/git.tex, r1669

Many organisations today have computer files worked on by teams. Keep tracking of the different versions and changes to those files is a difficult but important task. For software files, e.g. source code, distributed version control systems are often used to automate the tracking of versions and changes. Git is one distributed version control system. This chapter shows you how to setup a git server that can track files. This demonstrates one of the many different server applications that system administrators may be responsible for in an organisation’s network.

15.1 Prerequisites

15.1.1 Assumed Knowledge

This chapter assumes you have knowledge of:

Basic Linux command line skills, as covered in Chapter 4, are assumed. You will need to be able to:

15.1.2 Linux and Network Setup

While the Git server is installed on only a single Linux computer, for testing purposes it is useful to have multiple Linux computer. If you are using virtnet (Chapter 3) the select a topology with multiple nodes. In the example we use topology 5, however other topologies (e.g. 2, 3, 4) are also suitable.

15.2 Version Control Concepts

When developing software, version control is an important technique for managing source code. As software developers create source code, a version control system will automatically track changes and versions (as opposed to manually keeping track of version by file naming, e.g. app-v1.java, app-v2.java). With projects involving multiple people, a version control system adds the extra benefit of tracking who made the changes, and merging code when multiple people work on the same code segments. While version control systems are well suited to software development involving text files, they can also be used to store any file type (including binary files).

Two basic models of storing files are used in version control. Client/server model stores the repository of files on a server, and clients access the files. Examples of such systems are: Subversion (SVN), CVS, Visual SourceSafe, and Team Foundation Server. In a distributed model, each user stores the repository on their computer, and algorithms/protocols are used to keep them consistent. Examples include git, mercurial and bazaar.

Even with distributed version control, one or more publicly accessible Internet servers are commonly used so developers can share code among project team members. There are several companies that provide such servers, the most popular being GitHub. However, self-managed servers can also be used. In the following we demonstrate setting up a simple self-managed server for using git for distributed version control.

15.3 Setup a Git Repository

15.3.1 Example Scenario

We have a server, with IP 192.168.2.21 and referred to as server in the prompt, that will act as the main repository for all our files. Each software developer has an account on that server. Developers use their own computers to maintain their local repository, and occasionally synchronise that with the main repository on the server. In our example there is a single client computer with IP 192.168.1.11 and referred to as client in the prompt.

15.3.2 Setup the Repositories on Server

We first setup the server machine to support clients to access the Git repository.

Install the SSH server and Git software (they may already be installed; if so, attempting to install again won’t hurt):

steven@server:~$ sudo apt install openssh-server git

We assume the server machine has multiple users already with accounts. If not, add the users now using adduser (Section 7.3). In the following example, we assume there are users steven, ken, lily and scott.

We will restrict which users on the machine that can also access the git repository by creating a specific group called developers (e.g. steven, ken and lily are developers; scott is not). Create the group, and add the users to that group:

steven@server:~$ sudo addgroup developers
steven@server:~$ sudo adduser steven developers
steven@server:~$ sudo adduser ken developers
steven@server:~$ sudo adduser lily developers

Now create a directory for storing the git repository. Similar to a website or database, a good location to store the repositories is in /var. For example:

steven@server:~$ sudo mkdir /var/git-repo

Now set the ownership and permissions on the repository directory so only developers can write to it:

steven@server:~$ sudo chown -R root:developers /var/git-repo
steven@server:~$ sudo chmod -R g+rwx /var/git-repo/
                                                                                      
                                                                                      
steven@server:~$ sudo chmod g+s /var/git-repo

The last command above makes sure all sub-directories inside /var/git-repo also have developers as the group owner. For the group changes to take effect, log out and log back in again.

Finally, initialise a bare Git repository. For example, if you want two different repositories, one for a mobile app and another for a website:

steven@server:~$ git init --bare /var/git-repo/mobileapp.git
steven@server:~$ git init --bare /var/git-repo/website.git

Create as many repositories as needed. (For the above two commands, you may need to exit and login again before running them for the permissions to take effect).

Now, any user with an account on the server and in the developers group should be able to connect with a git client. Let’s try it.

15.4 Using Git

15.4.1 Clone an Existing Repository

On a client machine, login as one of the users in the developers group, e.g. ken. We will store all our git repositories in a directory called git.

ken@client:~$ cd
ken@client:~$ mkdir git
ken@client:~$ cd git

First we clone the entire repository from the server to the client:

ken@client:~/git$ git clone ssh://ken@192.168.2.21/var/git-repo/mobileapp.git mobileapp
Cloning into 'mobileapp'...
The authenticity of host '192.168.2.21 (192.168.2.21)' can't be established.
ECDSA key fingerprint is SHA256:RmHkmQgsb2SVRT4pRSCelLm/N4jxYu3r7358S1MgzQM.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '192.168.2.21' (ECDSA) to the list of known hosts.
ken@192.168.2.21's password:
warning: You appear to have cloned an empty repository.
Checking connectivity... done.

The above command uses ssh to connect to the server, prompts for confirmation that the server is really trusted, and then clones the files from the server to the client (in this example, the repo was empty).

15.4.2 Configure the Git Client

Before we continue, lets configure some git parameters, such as your name and email address:

ken@client:~$ git config --global user.email "ken@cqunix.com"
ken@client:~$ git config --global user.name "Ken CQUnix"

15.4.3 Common Git Operations

Let’s put some files in to the repo, first on the client, and then transfer (push) to the server.

ken@client:~/git$ ls
mobileapp
ken@client:~/git$ cd mobileapp/
ken@client:~/git/mobileapp$ ls
ken@client:~/git/mobileapp$

Create some example files, e.g.:

ken@client:~/git/mobileapp$ ls
example.java  README.txt

The basic workflow with git is to:

First add the files:

ken@client:~/git/mobileapp$ git add *

Now commit the files (you will be prompted for a commit message—enter a description of the changes you have made):

ken@client:~/git/mobileapp$ git commit
[master (root-commit) aa43b4d] Example mobile app started
 2 files changed, 2 insertions(+)
 create mode 100644 README.txt
 create mode 100644 example.java

Now push the files to the server:

ken@client:~/git/mobileapp$ git push
ken@192.168.2.21's password:
Counting objects: 4, done.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (4/4), 287 bytes | 0 bytes/s, done.
Total 4 (delta 0), reused 0 (delta 0)
To ssh://ken@192.168.2.21/var/git-repo/mobileapp.git
 * [new branch]      master -> master

Now lets switch to another user to access the same repository:

ken@client:~/git/mobileapp$ su steven
Password:
steven@client:/home/ken/git/mobileapp$ cd
steven@client:~$ mkdir git
steven@client:~$ cd git
steven@client:~/git$ git config --global user.email "steve@cqunix.com"
steven@client:~/git$ git config --global user.name "Steve CQUnix"
steven@client:~/git$ git clone ssh://steven@192.168.2.21/var/git-repo/mobileapp.git mobileapp
Cloning into 'mobileapp'...
steven@192.168.2.21's password:
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 4 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (4/4), done.
Checking connectivity... done.
steven@client:~/git$ cd mobileapp/
steven@client:~/git/mobileapp$ ls
example.java  README.txt

We see the two files have been downloaded in the initial clone. Now make some changes to the files, and add a new one:

steven@client:~/git/mobileapp$ nano README.txt
steven@client:~/git/mobileapp$ echo "person" > person.java
steven@client:~/git/mobileapp$ git add person.java
steven@client:~/git/mobileapp$ git commit
[master 18759bc] Added person class
 1 file changed, 1 insertion(+)
 create mode 100644 person.java
steven@client:~/git/mobileapp$ git push
steven@192.168.2.21's password:
Counting objects: 3, done.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 325 bytes | 0 bytes/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To ssh://steven@192.168.2.21/var/git-repo/mobileapp.git
    aa43b4d..18759bc  master -> master

Finally, switch back to the original user and pull the latest changes:

steven@client:~/git/mobileapp$ su ken
Password:
ken@client:/home/steven/git/mobileapp$ cd
ken@client:~$ cd git/mobileapp/
ken@client:~/git/mobileapp$ git pull
ken@192.168.2.21's password:
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From ssh://192.168.2.21/var/git-repo/mobileapp
    aa43b4d..18759bc  master     -> origin/master
Updating aa43b4d..18759bc
Fast-forward
 person.java | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 person.java
ken@client:~/git/mobileapp$ ls
example.java  person.java  README.txt

The pull downloads the changes from the server so now ken has the same files as steven.

From now on, the users can follow the workflow:

For other features of Git, see the documentation.