Version Control

Git

Introduction

Software projects often consist of large teams working on the design, implementation, and testing of a compex system, which consists of managing large range of files. Examples include program (e.g. Java) source code, design documents, and documentation. Additionally most software projects consist of configuration files, build systems, particular tools used to build the final product, and so on. The management and versioning of these files and other collections of information is often done via a software configuration management system, also know as version control.

You may well have already heard or used of popular version control systems, such as Linus Tovalds Git system or the older but still popular SVN system. If you plan to work in the area of software development, then even if you have not already comes across these particular systems or some other, then it is very likely you will in the near future. Version control systems are one of the key tools used in the development of complex software systems and most projects will use a particular instance from day one.

In this short series of videos we introduce the basic concepts of version control, why they useful, and the features they provide to aid the development process. Later videos introduce the version control system Git, which as noted above is a popular modern source control system.

After completing the videos some exercises are provided to allow the interested viewer to re-enforce what they have learned, getting to using Git in practice.

Videos

Version Control Part 1

In part one we discuss some common aspects of software development, motivating the need and use of version control systems.

The slides for this video are here.

Version Control Part 2

In part two we introduce the key features of version control and how they apply to software development.

The slides for this video are here.

Version Control Part 3

In part three we introduce the version control system Git, originally developed by Linus Torvalds, used today in millions of projects around the world.

The slides for this video are here.

Version Control Part 4

In part four we move away from slides and look at using Git in practice. In this case we use UWE's Gitlab server, but you can equally use Github, the public Gitlab, or maybe you have access to your own or your company's Git server. Additionally we use OS X and the Git command line tools, which are also accessble on Windows or Linux, along with plug-ins for popular IDEs such as Microsoft's Visual Studio, Apple's XCode, Netbeans, and editors such as Atom, Emacs, and Vim.

Exercises

Getting to Grips with Git

In this exercise you will use Git to

  • Login to UWE's Gitlab https server
  • Create a remote repo
    • connect it to your local repo
    • push changes remotely
  • Fork an existing repo
    • clone repo locally
    • make some changes locally
    • push changes to forked repo
    • generate a pull request to original (forked) repo
  • Local configuration
  • Create an empty repo
    • populate it the repo with some files
    • commit changes locally

Login in to UWE's Gitlab server

UWE provides a Gitlab server for both students and staff to used. The server can be used to host your own projects and also we will use it in this part of the CNOS course for all practial work.

To access UWE's Gitlab server simply click on the following link:

https://gitlab.uwe.ac.uk/

You should see a page similar to the following, assuming you have not login in previously. Now login using your UWE Windows username and password.

The first time you login you will be preseted with the so called Dashboard view. This is where you will see the status of all your projects, currently this is empty, as you have no projects yet, and will look similar to:

Create a remote repo

Let's begin by creating a new project, in Gitlab, which you will then clone on your local machine and begin adding files. Click on the new project button. You will be presented with a screen similar to the following:

Give the project the name my-test-project-username. Leave Namespace unchanged and add a short description, make the project internal, allowing it to be clone by other Gitlab members, and finally press the Create project button. You should see a page similar to the following.

We are going to use HTTPS access through out the course and so there is no need to configure an SSH key, unless you want to.

OK, now you have an empty repo and its time to make a copy on your local machine and beginning populating it. To do this, first open a command prompt window. (Remember, it is assumed that you are working on Linux, in the labs and at home, for the duration of the course. So if you have not done so already, login to Linux and open a command prompt window. Should look simliar to the following.

Before using Git it is a good idea to perform some basic global setup, with respect to your user account. Using git config you should set your user name and email, similar to the following, but using your own details.


      git config --global user.name "Benedict Gaster"
git config --global user.email "benedict.gaster@uwe.ac.uk"

Its a good idea to create yourself a working directory for this part of the CNOS course, calling it something like cnos_os. Change into the newly created directory.


mkdir cnos_os
cd cnos_os

Now to clone the project, simple copy the HTTPS link from the project page, you created in the previous step and use git clone to clone the repo locally, e.g something similar to:


git clone https://gitlab.uwe.ac.uk/br-gaster/my-test-project-username.git
  

You should see something like:


cloning into 'my-test-project-username'...
Username for 'https://gitlab.uwe.ac.uk': br-gaster
Password for 'https://br-gaster@gitlab.uwe.ac.uk':
warning: You appear to have cloned an empty repository.
Checking connectivity... done.

It is possible that due to the UWE Gitlab configuration, cloning will fail with a SSL error. If this is the case enter the following command and try cloning again:


  git config --global http.sslverify false
 

You should now have a directory, called my-test-project-username, which contains a copy, currently empty, of your repo. Change into that directory and list its contents, including hidden files (option -a):


     cd my-test-project-username
ls -a

You will see the output


 .	..	.git
 

The first two files are special "files", representing current and previous direcories, repsectively. The hidden directory .git is the place where Git keeps or the information about your repo. If you list the directory, e.g.


     ls -l ./.git
 

and you should see something like


     ls -lr ./.git
total 24
drwxr-xr-x 4 br-gaster 693207566 136 Nov 26 13:34 refs
drwxr-xr-x 4 br-gaster 693207566 136 Nov 26 13:34 objects
drwxr-xr-x 3 br-gaster 693207566 102 Nov 26 13:34 info
drwxr-xr-x 11 br-gaster 693207566 374 Nov 26 13:34 hooks
-rw-r--r-- 1 br-gaster 693207566 73 Nov 26 13:34 description
-rw-r--r-- 1 br-gaster 693207566 324 Nov 26 13:34 config
drwxr-xr-x 2 br-gaster 693207566 68 Nov 26 13:34 branches
-rw-r--r-- 1 br-gaster 693207566 23 Nov 26 13:34 HEAD
-rw-r--r-- 1 br-gaster 693207566 0 Nov 26 15:59 FETCH_HEAD

Let’s go over some of the normal files that you may see living in the base directory:

  • config: Contains settings for this repository. Specific configuration variables can be dumped in here (and even aliases!) What this file is most used for is defining where remotes live and some core settings, such as if your repository is bare or not.
  • description: If you’re using gitweb or firing up git instaweb, this will show up when you view your repository or the list of all versioned repositories.
  • FETCH_HEAD: The SHAs of branch/remote heads that were updated during the last git fetch
  • HEAD: The current ref that you’re looking at. In most cases it’s probably refs/heads/master
  • hooks: A directory that will fast become your best friend: this contains scripts that are executed at certain times when working with Git, such as after a commit or before a rebase. An entire series of articles will be coming about hooks.
  • info: Relatively uninteresting except for the exclude file that lives inside of it. We’ve seen this before in the ignoring files article, but as a reminder, you can use this file to ignore files for this project, but beware! It’s not versioned like a .gitignore file would be.
  • logs: Contains history for different branches. Seems to be used mostly with the reflog command.
  • objects: Git’s internal warehouse of blobs, all indexed by SHAs. rebase-apply: The workbench for rebasing and for git am. You can dig into its patch file when it does not apply cleanly if you’re brave.
  • refs: The master copy of all refs that live in your repository, be they for stashes, tags, remote tracking branches, or local branches.
  • Excellent now its time to add your first file to you currently empty repo. Create an empty readme file, called README.md (.md is Markup filetype), in the top-level directory of the repo. A simple way to do this is to use Linux's touch command:

    
         touch README.md
     

    Alternatively we could pipe nothing to README.md

    
         > README.md
     

    Add some text to README.md. At this point the README.md file on the Linux filesystem, however, Git does not know about our file yet. To see this we can use the Git command, status, which displays the difference between the current state, i.e. HEAD, known to Git, and files within the repo.

    
         git status
     
    
         On branch master

    Initial commit
    Untracked files:
    (use "git add ..." to include in what will be committed)

    README.md

    nothing added to commit but untracked files present (use "git add" to track)

    This tells you there are not files to commit and Git has found one file that is untracked, our README.md. We want Git to track this file and we can use git add to do this and then do run git status again:

    
         git add README.md
    git status

    which resulting in the output

    
         On branch master

    Initial commit

    Changes to be committed:
    (use "git rm --cached ..." to unstage)

    new file: README.md

    This time we see that README.md has been added as a new file, whose changes are now ready to be commited. To do this run the following command, which commits the changes locally.

    
         git commit -m "Added README.md"
     

    which will result in the output

    
     master (root-commit) dd7bbf2] Added README.md
    1 file changed, 1 insertion(+)
    create mode 100644 README.md

    The README.md file is now under version control and the intitial change has been timestamped, however, these changes have not been pushed to remote repo, on Gitlab. To do this use the git push command.

    
         git push
     

    restulting in output similar to

    
         Counting objects: 3, done.
    Writing objects: 100% (3/3), 232 bytes | 0 bytes/s, done.
    Total 3 (delta 0), reused 0 (delta 0)
    To https://gitlab.uwe.ac.uk/br-gaster/my-test-project-username.git
    * [new branch] master -> master

    Now the changes have been pushed to your remote repo, you should switch back to the browser to see the effect. In your browser open the HTTPS link used to clone the repo, which should be similar to

    
         https://gitlab.uwe.ac.uk/br-gaster/my-test-project
     

    You should see something similar to

    Notice the text from the readme is displayed in the middle of the screen. This is due to the fact that Gitlab, like make git servers, reconizes Markdown files (i.e. files with the extensions .md) and displays them using the described markup. Markdown is a simple markup language, similar but simpler than HTML, and the Gitlab variant is documented here:

    https://github.com/gitlabhq/gitlabhq/blob/master/doc/markdown/markdown.md

    Fork an existing repo

    Often you will want to work on an existing project, which maybe be you created but more than likely it will be a shared project, one that was possibly created by another user or group. Git provides the abilty to clone any project, not just one you created, assuming the project's permissions allow it.

    Similar to above we could simply clone the project locally, however, if we want to do more than simply build and use the project, in particular, if you expect to commit your own changes, then it is common to first fork the repo into you over namespace, i.e. Gitlab area, and work on that version. Once you have a setup changes to be murged into the original repo, you can create a pull request, which creates a dialog between yourself and the maintainer so that they will merge ("pull") you changes. This is a common pattern in industry, when using Git, and we will use this approach for later worksheets and the assignment.

    Let's fork a test project from one of your fellow students, student-user-name, add a line to the README.md, commit the changes locally and in your remote repo, and finally create a pull request for the maintainer. To begin open the link with the students user name, which will be something like:

    
         https://gitlab.uwe.ac.uk/student-user-name/my-test-project-username
     

    You should see a screen similar to the folllowing

    To fork the repo into your own space simply press the "fork" button. You should see a screen similar to:

    Simply click the button (here with bg-dummy, but in your case will have your user name) to fork a copy of the repo. You should now see a screen similar to the following:

    Notice that you now have a new repo, which is a forked copy of your fellow students repo. You can work on this as though it is your own repo, checkout local copies, commit changes locally on your machine, push changes to your copy in the remote depo, and so on. Additionally, once you have a set of changes that you would like to appear in the original repo, then you can create a pull request for owner to check and merge into their repo.

    To see how this works, checkout out a local copy, add your name to the README.md, commit the changes locally, and then push them to your external repo. Once you have pushed the changes to your external repo, then you should see a screen similar to

    Assuming you name is correct showing in the README.md, then it is time to generate a pull request, which will in effect ask the owner of the original repo to consider your changes for merging into their version. To do this select Merge Request from the menu on right hand side of your Gitlab window, which should result in a screen similar to:

    Currently there should be no outstanding merge requests. To create one, for the README.md change, simply press the button:

    This will result in a screen similar to the following, which allows you to compare the source branch, i.e. your changes, against the destination branch, i.e. where the resulting merge will be applied.

    In general, you can request a merge from any branch you have been working on, to any branch in the destination repo. For our current needs we need to select the branch master as the source branch. Doing so should display a screen similar to:

    To create a merge request press the button:

    You should now see a screen similar to:

    This screen allows you to enter a description for the merge request, which you should do now, and also doing actions, such as assign someone to perform the merge and so on. For now we will enter only a description and then press the button:

    Once the merge request is submitted you will see a screen similar to the following, which shows that the request is open, allows for additional comments to be added, and also to close the request.

    At this point it is the job of the original owner to review the merge request. To do this go, first, to the owner's Gitlab home page and the screen should show something similar to:

    Notice that the home page displays a list of recent events and in particular the top one should show that your fellow student has opened a merge request (#1). Click on the #1 to review the merge, you should see a page similar to:

    This screen allows the requested merge to be reviewed, comments in respose to be added, and finally to accept the merge request. Before accepting the merge click on the changes tab to review the submmitted changes, you should see something similar to:

    The lower part of the screen displays what is called a diff, based on the Unix tool of the same name, and shows, in green, the lines that will be added after the merge. If any lines has been removed from the original, then these would be displayed in red. In our case the merge is trivial, i.e. a single line has been added, but in general, merges can be very complicated and include conflicts, e.g. the original has changed in the mean time, and thus line changes one do not reflect changes in the other. In these cases a manual merge, where the user goes through line by line accepting or refusing changes, would be necessary, however, in our case an automatic merge can be applied. To do this simply click the button:

    This may take a moment and will result in a screen similar to:

    At this point the merge request is complete and will be closed automatically.

    There is a lot more to Git and Gitlab than covered in this short introduction, e.g. branches and issue tracking, but this should be enough to give you an idea of what is possible. Using Git is the best why to get used to the more advanced features. Version control and in particular source control is a very powerful tool, allowing you to work on projects with 10s or 100s of developers, sharing source code and documents, as well as simply a way to ensure that your own projects are backed up safely!