Power Git

Table of Contents

1 Introduction

1.1 Hi!

This workshop was prepared and delivered by the CMU Computer Club, sponsored by Green Hills Software. This talk series focuses on giving you, the developer of software, more power and understanding of your tools. And also to showcase awesome technologies and tools that you may not know about.

1.2 Version control with git

Version control is kind of like fancy, souped-up undo. It's called version control because it give you control and access over many different versions of your content. These can be historical versions that build up as you make changes, or different sets of patches from different contributors, or versions of the codebase with added features. Those second two are usually known as "branches".

Git is the most popular version control system. It was created by Linus Torvalds for the development of the Linux kernel. Some older version control systems were centralized; that means a central server maintained the data about what versions there were. Git is distributed; every copy of a codebase, known as a "repository" or "repo", which might live on your personal machine, contains a complete history of at least one "branch" (a series of changes); and every "repo" can compare and merge their versions and changes.

You've probably heard of "github"; github is a popular hosting site for git repositories. But actually you can maintain your own git repositories, and push and pull from them without having to host it them on github. In this workshop, we'll be using repositories that are located on the unix.andrew.cmu.edu servers (in your home directory on AFS, for those who came to our first talk this year).

Why would you want to use git? Three reasons.

  1. It allows you to keep track of your history in the code base. If you introduce a bug in some change, you can track it down. If you accidentally erase or mangle your files, you can trivially recover them.
  2. It allows you to easily collaborate with others. If multiple people make changes to a common codebase, git will help you merge them together. If you want to accept contributions from more than one person, git will help you sort out the good patches from the bad patches.
  3. It allows you to keep multiple versions of your code. If you have some features you want to add, but you're not sure if they'll be stable, you can keep the changes that introduce those features isolated and easily merge them into the main branch whenver you want, even if you've made changes in the rest of your codebase since working on the feature.

2 Getting started

2.1 Workshop explanation and IRC

git is very useful for collaboration. But there's too many of you to just collaborate with us, and you don't know git yet, so you can't collaborate with each other. So we made a virtual friend for you to collaborate with. They're waiting for you on IRC!

First, you need to login to the unix.andrew.cmu.edu servers. You should have done this before; if not, what you need to do is something like.

ssh yourandrewid@unix.andrew.cmu.edu

And enter your Andrew password.

Go to http://www.cmucc.org/irc to connect to the Freenode IRC network through a web interface; this will also connect you to the Computer Club IRC channel. Then, type the following in the space at the bottom, and press enter!

/query cclub-git-friend

Then say hello! (type "hi" and press enter)

2.2 Making a repo

You've gotta get your work done with cclub-git-friend! What's all this nonsense about a bare repo?

mkdir cclub-project
cd cclub-project
git init --bare
ls

Oh my! What's all this stuff? These are the folders and files that make up the guts of a git repository. Within them is stored all the data about the different versions you've got inside git. Or at least, that's what will be stored in them - it's pretty much totally empty right now. If you do this:

pwd

You'll get the path of the directory, which you can give to your friend so they can push and pull from this bare repo, and collaborate with you as you'll soon find out.

2.3 AFS permissions

But your friend will complain! They don't have write access yet. On AFS (which is the system hosting these files on unix.andrew.cmu.edu), you need a semi-magical invocation to give permissions to someone else. For people with Andrew accounts, if you're on an Andrew system, you can just do:

fs sa path_to_the_bare_repo_directory someandrewid write
# or, if you're already in the directory...
fs sa . someandrewid write
# . is a magic link to the current directory

This will give the person with the Andrew ID "someandrewid" the ability to read and write in that directory.

git-friend is accessing AFS remotely, so you need to put "@club.cc.cmu.edu" after their username.

fs sa path_to_the_bare_repo_directory git-friend@club.cc.cmu.edu write

OK actually it is more complicated than that. What you really want to do is:

find path_to_the_bare_repo_directory -type d -exec fs sa {} someandrewid write \;

This uses the find command to run fs sa on the main directory, and then all sub-directories. This gives write access to the main directory and also all sub-directories. Kind of a pain that the fs command doesn't have a built-in recursive option.

3 Getting work done

3.1 clone

OK, so seeing where your versions will be stored is great and all, but it might be handy to actually see ther versions. You need a regular git repo to do that; the bare repo is called "bare" because it doesn't actually show you the files. Only one of you needs to make a bare repo; both of you can then clone that bare repo, as long as you have AFS permissions.

cd ~
git clone path_to_the_bare_repo_directory working-cc

This copies, or "clones", the bare repo's files into another folder called working-cc. (git repos don't have names; the name of the folder holding them is irrelevant) You will notice there is nothing in working-cc. This is because there are no files in either of your repos.

Well, actually there is something in working-cc.

# -a shows all files and folders, even hidden ones
ls -a working-cc
# you should see ".git"
ls working-cc/.git
# hey, that looks familiar!

The .git folder is what makes this a git repo.

3.2 status

Let's put some files in working-cc.

cd working-cc
touch main.py
touch main.pyc

Nice.

Now we can do the following to check the status of our git repository:

git status

main.py and main.pyc are present, but untracked.

3.3 .gitignore

But wait, we don't want to version control the .pyc files - that's compiled Python code, it's just produced as a byproduct of running our main.py! We don't need to know about the changes in those files if we already know about the changes in the .py files. In fact we'd rather ignore those files completely.

Thank goodness! There's .gitignore!

man gitignore
touch .gitignore
vim .gitignore

.gitignore allows us to ignore files. You can read about the patterns in the man page. Let's ignore .pyc files! Add this line to your .gitignore file:

*.pyc

Now check your status again.

git status

Great. No more pyc. We do want to track .gitignore, as everyone who is working on our repository probably wants to ignore the same things, and if we start generating some new kind of garbage file with some changes to the code, we want to start ignoring that file at the same time we make the change.

3.4 add

Let's start tracking those files.

# . is a magic link to the current directory
git add .
# this adds everything in the current directory
# which includes those files
git status

Great!

This is actually what you'll do whenever you make a change. Rather than add the file, this command actually adds the current state of the file. Let's try making a change:

echo 'print "Hello world"' >> main.py
git status

When we ran git status, git noticed main.py had changed from the last time main.py was added, and it notified us.

This time we'll specify the file individually:

git add main.py
git status

3.5 commit

The next step is to permanently record these changes. This is easy!

# associate changes made in this copy of the repo with your name and andrewid
# you only need to do this once
git config user.name "Firstname Lastname"
git config user.email "yourandrewid@andrew.cmu.edu"

git commit -m "wrote hello world"
# the -m flag allows you to specify the change description on the command line
# if you didn't include -m, your editor would pop up and you could type one in

When you run commit, you're making a "commit", which is like a permanent record of the changes since you last committed. (Or, in the case of the first commit, the "initial commit", a permanent record of the changes from the empty repo you started with).

3.6 push

Finally, you can push your changes to the bare repo.

git push origin master

Since your working copy of this repo is a clone, it stores the location of the bare repo as "origin". "master" is the main branch - we'll talk more about that later. After doing this once, though, you can just do

git push

Easy!

4 Collaborating with others

4.1 pull

Okay, our friend pushed some things, let's check them out.

git pull

This pulls in changes that have been pushed to the bare repo since your last `git pull`. git status will also automatically check for you, so you don't have to be paranoid about checking.

4.2 log

What's been done, though?

git log

This gives us a log of the commits.

# show a log of commits, along with their associated patches
git log -p

This gives us a log of the commits and the changes associated with them.

5 Collaborating with yourself

5.1 branch and checkout

What's a branch?

# list branches
git branch -l

There's a master branch; that's where most changes will eventually end up. But you can make additional branches, for special changes!

# make a new branch called cool_feature
git branch cool_feature
git branch -l

Now if you want to add some new features, you can put them in coolfeature!

You just checkout a copy of the branch to switch to it.

# git status tells us which branch we're on
git status
# check out cool_feature
git checkout cool_feature
git status

Now we can make some changes, and they'll only be in this branch!

git log
echo 'print "goodbye world"' >> main.py
git add main.py
git commit -m "added goodbye world"
git log

Nice, my commits are there.

But if I switch back to master…

git checkout master
git log

The commits are gone! Actually, they're still there, just on the coolfeature branch and not the master branch.

If you want to pull those coolfeature branch commits in to the master branch, just merge.

git merge cool_feature
git log

Great!

6 Advanced topics

6.1 add -p

Add only part of a file! Useful to organize your commits by subject!

# add just a part of somefile - you'll be prompted to select what part
git add -p somefile

6.2 rebase -i

Rewrite history, combining or splitting or rearranging commits!

# rewrite the last 3 commits
git rebase -i HEAD^3

6.3 bisect

Automatically find bugs! Run

# assuming test_code.sh will fail (return non-zero) when your code is bad
git bisect run test_code.sh

and git will automatically run the test to find the first commit where testcode.sh fails!

Author: Spencer Baugh

Created: 2014-09-17 Wed 19:52

Emacs 24.3.93.1 (Org mode 8.2.6)

Validate