CSE 374 git tutorial

git is a modern version control system for managing the sharing and versioning of your source code. git is a "distributed" version control system, as opposed to classical systems such as CVS and Subversion which are based on a single central repository. While distributed version control is very powerful, this tutorial will teach you to use git in a "client-server" fashion that mimics the classical version control systems that you may already be used to.

This tutorial assumes that you are using Linux.

Tip

git has many, many more advanced features than are presented in this tutorial. If you'd like to learn about them, git has a comprehensive set of man pages (man 1 git or git --help <command>), as well as the online Git Community Book. Try these references first if you get unexpected output or error messages from git commands. However, for most CSE 374 usage it's probably best to stick to the basics given here.

Cloning the repository

Run the following command to make a local clone a sample repository:

            $ git clone git@gitlab.cs.washington.edu:cse374-15au/sample.git
          

This will create a directory named sample in the current directory. The tutorial below assumes you're working with this sample repository, but the concepts and commands will work with your own repository as well.

Once you're done tinkering, and you would like to start making changes to your CSE374 group repository, clone that repository. To do so, you'll need to log on to Gitlab, add an ssh key, and then find your group's repository under the Projects tab.

Click your repository's name, and on the page that appears there should be a string you can copy of the form git@gitlab.cs.washington.edu:cse374-15au-students/cse374-15au-xx.git, where xx is your group code (aa, ab, etc.).

Copy that string, and run:

            $ git clone copied_string
          

If you would like to rename the local copy of the repository to something more descriptive, you can instead run:

            $ git clone copied_string descriptive_name
          

If you are prompted to enter your password that means you haven't set up your ssh keys in gitlab properly. Do that now to avoid repeated password prompts as you push and pull things from gitlab.

Note

If you are prompted for a password when you try to clone the sample repository, log in first and set up a ssh key so you can use GitLab without entering passwords.

Note

The GitLab instructions for adding ssh keys say it is a best practice to also create a password to go with the key. For our purposes doing that is mostly just a nuisance. We suggest you set up the ssh key with no extra password, and if you are still getting password prompts when you try to use GitLab, delete your existing ssh keys and repeat the key setup to get rid of it. Unfortunately that page of instructions is buried deep in the GitLab package and is hard to change, even though we would like to do so.

Committing to the repository

The commit and update process in git differs slightly from that of other version control systems that you may have used. To illustrate how it works, we'll make a minor change to one file and create a new file. Run the following commands from the top level of your copy of the sample repository (you may have to cd sample to get there):

            $ echo Hello >> CHANGES
            $ echo newfile >> newfile
          

Now run the git status command and observe its output:

            $ git status
            On branch master
            Your branch is up-to-date with 'origin/master'.
            Changes not staged for commit:
            (use "git add <file>..." to update what will be committed)
            (use "git checkout -- <file>..." to discard changes in working directory)

            modified:   CHANGES

            Untracked files:
            (use "git add <file>..." to include in what will be committed)

            newfile

            no changes added to commit (use "git add" and/or "git commit -a")
          

This output shows two things: first, you must explicitly add new ("untracked") files to the repository before they can be committed (as is true in other version control systems), and second, you must explicitly stage your changes before they will be committed (unlike subversion, which will automatically commit all of your changes if you just run svn commit). To further illustrate this, run the git commit command:

            $ git commit -m "Test commit."
          

This command will be a no-op: you should see the same output as from the git status command, ending in the same message: 'no changes added to commit (use "git add" and/or "git commit -a")'. To add your changes to the commit set, you must use the git add command on the changed files (whether they are new files or files already in the repository!):

            $ git add CHANGES
            $ git add newfile
            $ git status
            On branch master
            Your branch is up-to-date with 'origin/master'.
            Changes to be committed:
            (use "git reset HEAD <file>..." to unstage)

            modified:   CHANGES
            new file:   newfile
          

You can see that the change to the CHANGES file and the addition of newfile have now been staged for the commit. To commit all of the changes that you have staged, run git commit:

            $ git commit -m "Test commit"
            [master 41a5c0d] Test commit
            2 files changed, 2 insertions(+), 0 deletions(-)
            create mode 100644 newfile
          

Details

The -m argument to git commit is used to provide a commit message; if you forget to use it, then git will open a text editor for you to enter a commit message. The default editor is often vim. If you are not familiar with it, one command to know is :q, which is the magic incantation to quit.

You should not automatically add every new file listed by git to the repository. Source programs and other files needed to build the project should be added, but executable programs, compiler output (.o files), editor backup files (emacs ~ files) and other temporary files usually shouldn't be included. These are files that are built automatically from files that are in the repository or are transient files that should not be archived permanently. Similarly if you have other files in the directory that are not part of the project, like your grocery list, you do not want to put them in the git repo.

To make git behave more like subversion and automatically commit all of the changes you have made to files already in the repository (automatically commit all unstaged changes), use the -a flag with git commit. You may find, however, that the process of staging / unstaging changes is one of the most useful features of git: it allows you to make lots of changes to lots of files, but only commit the changes you want while leaving other files with in-progress changes uncommitted.

If you get a message like "file.c: needs merge" when you try to commit, then you have a conflict from a previous git pull that has not been resolved. See the Updating your local repository section below for more information about resolving conflicts.

However, at this point you have committed some changes, but your commit is not yet visible to the other users of the repository. git separates the notion of committing changes from the notion of "pushing" your update to the central repository. This can be useful for an individual developer that wants to make many changes to the code in many small logical commits before pushing all of them to the central repository, but for your CSE 374 projects you will probably just want to push after every commit.

To push your commits to the central repository, simply run git push:

            $ git push
            Counting objects: 4, done.
            Delta compression using up to 8 threads.
            Compressing objects: 100% (2/2), done.
            Writing objects: 100% (4/4), 312 bytes | 0 bytes/s, done.
            Total 4 (delta 0), reused 0 (delta 0)
            To git@gitlab.cs.washington.edu:cse374-15sp/sample.git
            eb27358..c3615e1  master -> master
          

This won't work on the sample repository, because you don't have write access. You'll need this command once you start working with your own group's repository.

Note

If your push fails, it may be because you need to run a git pull to update your repository first (and potentially resolve conflicts) before pushing your new commit. See Updating your local repository below.

Note

If you get a warning that push.default is not set, you can make that message go away by setting it to simple using the git config command given in the warning message.

Details

If you ever run the git status command and see the output "Your branch is ahead of 'origin/master' by N commits", then this means that you have local commits that have not been pushed to the repository yet.

Reminder

Remember to push your commits! If you are not used to using git, then this may be the hardest thing to get used to. Try not to forget to do this, or your group members will wonder why it seems like you're not doing any work.

Updating your local repository

To update your local copy of the repository with commits that other members of your group have made, simply use the git pull command. It will either show:

            $ git pull

            Already up-to-date.
          

or something like:

            $ git pull
            ...
            CHANGES               |    1 +
            newfile               |    1 +
            2 files changed, 2 insertions(+), 0 deletions(-)
            create mode 100644 newfile
          

Note

git will not allow you to pull updates into your repository while you have unstaged changes. Therefore, you must stage (git add) and commit all of your changes before pulling. If you have changes that you don't want to make visible to your group yet (because they cause the build to break, for instance) but you still want to update your local repository, you can just commit your changes, do not push them yet, and pull the updates. Then, when your changes are ready, you can commit again and then push to the central repository.

As with any version control system, pulling updates from the central repository may cause conflicts with changes that you have committed locally. Pay attention to the output from your pull command for instructions to resolve conflicts; generally, resolving a conflict entails opening up the conflicted file(s) in your editor, finding the conflicts (surrounded by the text markers <<<<<<<, =======, and >>>>>>>), fixing the conflicting code, staging the changes (git add) and committing and pushing again. For more information about resolving conflicts, the github user manual has a useful webpage.


If you find any bugs in this tutorial, please e-mail them to the CSE 374 staff. If you have any problems while using git that are not covered in this tutorial, try the man pages (man 1 git and git --help <command>) and the Git Community Book, and then contact the TAs. If you find any useful features of git that aren't mentioned here, post them to the class discussion board.

Author: Peter Hornyack (pjh@cs)

Edited by: Sunjay Cauligi (sunjayc@cs), Nat Mote (nmote@cs), Hal Perkins (perkins@cs)

Adapted from the CSE 451 git tutorial