CS61C Summer 2014 Lab 1


Registering Your Instructional Account

Your TA will give you a sheet of paper with your class login (cs61c-XX) and initial password.
Log into one of the lab machines.
Now start a Terminal session (PROTIP: use ctrl-alt-t) and change your password by typing ssh update and following the on-screen prompts.
Once you've changed your password type register and answer the following questions to associate your class account with your name and student ID number. If you run into difficulties with the register command, try ssh-ing into star.cs.berkeley.edu and running register from there.
If you already have a GitHub account and/or SSH key pair you can skip one or both of the following sections

Creating a GitHub Account

Start your browser of choice and navigate to github.com. Click on "Signup and Pricing" and select "Create a Free Account" on the next page. Fill in the required information.

Please don't use your class login as your GitHub username.

Generating an RSA Key Pair

Open a terminal, and type the commands

    $ cd ~/.ssh
    $ ssh-keygen -t rsa -C <email address>

replacing <email address> with your actual email address. This second instruction will ask you to provide a passphrase. Do so. This passphrase will be required in order to authenticate using your private key, making it harder for unscrupulous individuals to access your GitHub repos.

Once these instructions have finished you should have a file named id_rsa (private key) and a file name id_rsa.pub (public key) in your .ssh directory. You can confirm this with the command

    $ ls ~/.ssh

Registering your RSA Key Pair with GitHub

Open your id_rsa.pub file with your preferred text editor. If you're new to UNIX-like systems gedit is an intuitive, if weak, editor. You can launch it with the command

    $ gedit ~/.ssh/id_rsa.pub &

Copy the contents of the file to the clipboard. It shold look something like

ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDIjSa6myw36lilGWjhvOQt26gd1Veh4vsio2OLdp+ 0R3PbuHd89uWLiuz5xrYfUg6HLMIjZZY58BMVrZQiLzLCsB2o6O+REGiuJ48saJkKEdl/gSt2ht/TVEr vRqlY1b2/eWn2fFJuepUQ6M8QUr+x5iHmb4L5d4QcKs+sSM2NG2MI4e+73VG97ns50cx9Y17PaY lmGb+oM7BTQa1ZxG3585Huhb6SR8JgEr9+DfUSIBC2cTtwruBYG3RETKNvk90gCQ9o72CJ+HtOx1 5XyMc2ixdcGOJs+ubshvph01WlQiSxW6RKBvUDLaIqDl3H84jSvVgPRKgQqQFF4SZ3vLvZ you@example.com

Return to github.com and select "Account Settings" from the top right of the screen. Then select "SSH Keys" from the left hand side. Paste the contents of your public key into the key and click "Add key". You can verify that the key is working with the terminal command

    $ ssh -T git@github.com

Answer yes to the question about continuing to connect, and enter the passphrase for your private key. You should then see a message of the form

Hi USERNAME! You've successfully authenticated, but GitHub does not provide shell access.

Working with Git

Initializing your working repository

Execute the following commands, where it is assumed that you will be doing your code development in subdirectories of work (the name is inconsequential, name it something else if you like).

    $ mkdir work
    $ cd work
    $ git init
    $ echo "My name is <name> (<login>). This is the top level of my working directory" > README
    $ git add -A
    $ git commit -m "First commit."

Now let's walk through what we just did. The first two commands just made a work directory and moved us into it.
The third command, git init, places the current working directory under version control by placing the hidden directory .git inside of it. Now that work is version controlled you'll be able to return to pervious versions of your work if you muck something up while developing, among other things.
The fifth command, git add -A tells git that you think all of the changes to the repository since the last commit are worth tracking (git only tracks the files you tell it to). The jargon for the set of files whose changes are worth tracking is the index. So another way of expressing what git add -A did is to say that it placed everything in the directory in the index.
The final command you executed, git commit -m "First commit.", told git that this was a version of your code that you want to be able to get back to. The -m option told git to associate the message "First commit." with this version. On a side note, git will refuse to make a commit if there are no indexed changes, which is why we have the fourth command creating a README.

Pitfall Prevention: DO NOT RUN git init OR git clone FROM INSIDE A VERSION CONTROLLED DIRECTORY, INCLUDING ONE OF ITS SUBDIRECTORIES. This will cause "git in git" problems, which will almost definitely make someone's head hurt before they are resolved.

Pulling from another repository

Git provides the capacity for source materials to be shared between repositories. There are two main ways of doing this, the first of which is git pull, the other being git push, which we will cover later. git pull goes to the repository specified, at the specified branch or tag (line of development or labeled commit, respectively), and merges it into your repository. Basically it takes the code at the remote repository and sticks it in yours. Let's try it. We've placed the files for this lab in a git repository at ~cs61c/labs/su14/01/. You can pull the files into your repository with these commands:

    $ git remote add lab01 ~cs61c/labs/su14/01
    $ git pull lab01 master

So what does that do? The first instruction tell git to add ~cs61c/labs/su14/01 to its list of remote repositories under the alias lab01. This command only needs to be run once, even if you pull from a repository many times. The second line goes to the lab01 repository, and merges its master branch into your currently checked out branch. Of course, you have no idea what all this business with branches is, which is why we're covering that next.

Branching and Merging

OK, so this is going to get a little complicated, but the bare bones of it are pretty simple. If you find yourself getting lost, try to make sure you don't forget these two things. First, branches represent lines of development, like trains of thought. Second, a merge takes two of these lines of thought, and incorporates one into the other.

You can think of version control as being a bit like a singly linked list. Every time you make a commit a new version of your code gets prepended to your list, and has as its child the next most recent version. That way if you want to back track to an old version you just look back through the list until you get to the version you want. What branches do is allow for your list to take on a more general graph structure, with nodes having multiple parents (ie, spawning multiple newer versions of code). When we give a node(version) more parents(successors) we call it branching, because we are splitting, or branching, the code into separate development paths. Merging is a little bit more complicated than just spawning a single parent for two children. It would be a more accurate depiction to say that we copy the nodes that the mergee (branch being merged into) doesn't have, but the merger (branch merging into the mergee) does, and inject those into the mergee. After we do that we look at the differences between the head of the merger and the head of the mergee before we injected the nodes from the merger. If these differences are "good" we'll combine the two automatically and make a new commit to the mergee. Otherwise we'll ask the user to perform conflict resolution manually, and then commit the changes.

Now that you have some idea of how branching and merging works at a high level, you're going to try using it on this lab. You'll notice that the code you've pulled in has a Makefile and a hello world program, but that the code doesn't compile. There are two ways of getting the program working. Either you can change the Makefile to make the compiler less picky, or you can fix the C code to be compliant with stricter standards. You're going to do both. First you'll make a branch for each.

    $ git branch lab01c
    $ git branch lab01make

Next you'll switch to the lab01c branch (ie, you will checkout lab01c) and fix the C code. Be sure to commit all your changes when you finish.

    $ git checkout lab01c
    /* Whatever you need to do to make the C code work. */
    $ git commit -am "You should write a more meaningful commit message than this."

Then the same idea with the Makefile.

    $ git checkout lab01make
    /* Whatever you need to do to make the Makefile work. */
    $ git commit -am "You should write a more meaningful commit message than this."

Last merge in the improvements of both branches into master.

    $ git checkout master
    $ git merge lab01c
    $ git merge lab01make

And that's it, you've used branches to explore different lines of development. This example may seem contrived (it was), but for more complicated problems this approach can make your life a lot easier.

Tagging important commits

git tag, in essence, applies a label to a given commit. In the real world you may want to tag the versions of the code which were used as releases, or perhaps just mark a commit which made a major difference in the way the code behaved. Of more immediate concern to you is the fact that we'll be using tags to determine which version of your code to grade for homeworks and projects. Apply the tag "lab01" to your most recent commit using the following command.

    $ git tag lab01

Pushing to another repository

Pushing is the opposite of pulling. Where git pull took code from another repository and stuck it in yours git push takes your code and sticks it in another repository. In the real world it's not uncommon for teams to share work by pushing to a master repository which everybody else then pulls from. In this class it's how you'll be submitting your projects (this is the only lab for which you will be making use of this submission process, and we'll use the standard submit mechanism for homeworks). The remote repository to which you'll be pushing your submissions is at git@github.com:ucberkeley-cs61c/cs61c-XX.git, where cs61c-XX is your login. The following sequence of commands will take your work and push it into your GitHub repo.

    $ git remote add origin git@github.com:ucberkeley-cs61c/cs61c-XX.git
    $ git push -u --tags origin master

The -u option tells git to associate the master branch in your local repository with the master branch in your GitHub repository (you only need this option once). The --tags option tells git to send tags.

Confirming your Submission

Now that you've gone through an assignment you're going to confirm that the submission process didn't fail. There are two things that you need to check on a given submission. The first is that it is tagged correctly, and the second is that the commit to which the tag points contains what you expect it to. The following commands will help you do that for this assignment. For other assignments you will need to pull with the appropriate tag. DO NOT EXECUTE THESE COMMANDS INSIDE OF YOUR WORKING REPOSITORY.

    $ mkdir tmp
    $ cd tmp
    $ git init
    $ git remote add origin git@github.com:ucberkeley-cs61c/cs61c-XX.git
    $ git pull origin master
    /* Examine your code to make sure that everything is in order */
    $ cd ..
    $ rm -rf tmp

You can also check on the contents of your repository using GitHub's GUI if that's more your style.


Confirm your submission for your TA or Lab Assistant.

Show that in your working directory branch lab01c only modified hello.c.

Show that in your working directory branch lab01make only modified Makefile.

When Things Go Wrong

You've misentered a path when using git remote add alias path:
Use the command git remote rm alias and then re-add your alias.

You've version controlled a directory(let's call the directory oops) that you don't want to be version controlled:
Use the command rm -rf oops/.git

You've mangled a branch and just want to throw it out and start over.
Use the command git branch -D problemBranch
Where problemBranch is the branch you wanted to remove.