A tutorial for the UPL Video Lecture Series
by Leo Rudberg
All of the commands below are prefixed by git
and are run inside your (Unix-like) terminal (bash, zsh, etc.).
Some commands will appear with a $
at the beginning of the line. Do not type this in, this is the terminal prompting you for input!
I'm assuming you have git installed as well. (Run git --version
to verify.) I'm also assuming you know how to use simple commands like cd
, pwd
, ls
, mkdir
, and open
(or their Window's equivalents) effectively.
Yes, there are GUIs for git, but I prefer the command line for most git-related things.
GUI Downloads:
Let's get started!
START THIS TUTORIAL BY CREATING NEW DIRECTORIES
$ mkdir git_tutorial
$ cd git_tutorial
$ mkdir phase_one
$ cd phase_one
git init
will create a new git repo in your current directory.
In other words, the folder becomes a "git folder".
This action creates a "hidden" sub-folder named .git
;
this is where all of the git metadata/magic is stored.
git status
let's you know what's going on in your repo
- What files are new, modified, or deleted
- What branch you're on (more on branches later)
- Where you are in relation to the remote repo
Open a new file (e.g. touch ilovegit.txt
).
Run git status
and you'll see git notices that you've created a new file.
git add ilovegit.txt
will add your file to the index (staging area).
This means that once you commit, git will start tracking changes to ilovegit.txt!
git add .
will add all of the modifications since your last commit
git add --patch
will let you add your changes in "hunks". I use it for rubber-ducking.
Try to run git commit
. You should get an error -- you need to supply a commit message.
(Your settings may open a text editor in this case.)
Commit messages let other developers (and your future self) the summary of changes for this commit.
Canonically, the first commit in any repo is "Initial commit". Let's do that!
git commit -m "Initial commit"
The commit should run without error now. If you want to run git add
and git commit -m
at the same time:
git commit -am "yolo"
For the sanity of people around you, please use coherent commit messages!
Let's use one git's future technologies: the ability to have a remote repo.
Go to GitHub, create a new repo.
Don't do any off the advanced settings, just a vanilla repo please!
GitHub should tell you some instructions on setting up your remote.
Look for a git add
command with a remote
keyword.
When I did it, it was the second set of git commands listed on the page.
Enter these commands in your terminal. These commands allow your computer to link to send changes to GitHub.
They have the "blessèd repo" (i.e. the remote).
To push (send) your repo data to the GitHub remote, just enter git push
.
Remember, the git mantra is (roughly):
- Edit
- Add
- Commit
- Push
Let's say you are working on a project and your friend just pushed some commits.
They usually write good stuff, so you'll take their word for it.
Let's incorporate their changes into your local repo:
Much like how you pushed your stuff earlier, you can git pull
their changes from the remote.
From my experience, git checkout
has two major uses:
- Undoing bad and dirty changes
- Switching branches
Let's create an "oh crap" moment.
Let's say that rm ilovegit.txt
doesn't "Run Magic" like you thought it did, it ReMoves your file!
Luckily, you're a cool person using git, and git notices that you derped.
Just run git status
. You can see that you've deleted "ilovegit.txt".
To get it back, just run git checkout ilovegit.txt
and your file is magically replaced
with the same contents as most recent commit.
Hooray! Yay git!
We can also switch branches using checkout
. The default branch is master
.
There's nothing inherently important about master
, just that it always is created in a new repo.
I've never attempted it before, but DO NOT DELETE master
OR YOU WILL HAVE A BAD TIME.
Some people prefer to put "stable" code on the master
branch and use custom branches for new features and such.
Other people like to keep development code on master
and use branches for stable releases.
Running git branch
will show you all visible branches on your local copy.
You should only have master
at this point. Let's create a new branch.
git checkout -b my-branch
will create a new branch named my-branch
and automatically check you "into" it.
Your new branch should look identical from the branch you just branched off of (in our case, master
).
However, any changes you make to it will only be applied to the current branch.
Let's create another file: touch mybranchfile.txt
Check the status, add, and commit.
So we've got done what we wanted to on my-branch
, let's merge the updates into master.
Get back to master by entering git checkout master
.
Now, merge the branch by running git merge my-branch
.
Since my-branch
is just a "fast-forward" of master
, the merge is easy!
There is another type of merge called a three way merge.
This type of merge occurs when your local repo has diverged from the remote repo, but has a common ancestor.
This is not just neanderthals becoming homo sapiens. This is:
-
Everyone is working on SomeAnimal.java
-
You go into hero mode and implement the Human class in SomeAnimal.java
-
However, your partner also cranked some energy drinks and though it was better to implement the Dog class in SomeAnimal.java
-
(Unfortunately) your partner pushes their code first
-
You can't fast forward (Humans and Dogs aren't compatible after all...), so you need to do a three way merge.
When you pull from the remote, git should alert you that a conflict occured in Animal.java.
It's time to sit down with your partner and talk over the changes.
Let's do this right now!
-
Get into groups of two
-
Have one person (A) create a new file called
mymerge.txt
-
A adds one line to the file:
octopus
-
Have the other person (B) clone A's tutorial repo (use
git clone
and the link provided by GitHub) -
B changes
octopus
tooctodad
, adds, commits, and pushes -
A changes
octopus
tooctocat
, adds, and commits -
NOW, A attempts to push (shouldn't work)
-
A first has to pull B's changes, however they've diverged
-
If you get a 403 error at anytime, or something is broken besides the conflict, A needs to add B as a collaborator to the project.
-
First, A navigates to the project on GitHub.
-
Then A clicks on the Settings link on the right hand side of the page.
-
There should be a Collaborators link on the left hand side of the settings page -- click it.
-
A adds B as a collaborator using B's GitHub username.
-
A pulls, git should complain about a merge conflict
-
Fire up your merge tool (
git mergetool
) and fix that conflict!
Time to interact with a human!
Running git mergetool
will open your mergetool, or a program that helps solve a merge conflict.
You can choose to solve the merge conflict by hand, but I don't trust myself enough.
On a Mac, you should have a rudimentary GUI. Meld is a popular tool.
If you're comfortable with vim, vimdiff is also a good tool.
Now, decide with your partner what octoxxx
you want. Once you've resolved the merge,
add, commit, and push to the remote.
If your OS doesn't come with a default mergetool, it's time to roll up your sleeves. (Or just look up how to get a mergetool and set it as a default... I don't know everything ...)
git identifies the conflicting code and puts markers around it. Here's GitHub's example:
the number of planets are
<<<<<<< HEAD
nine
=======
eight
>>>>>>> branch-a
Follow their guide and fix the merge by hand. This is equivalent to using a tool (like Meld). Feel free to make decisions based on your preferences!
So what are all of these commit messages for anyway?
Using git log
you can see all of the commit messages you've made,
plus a bunch of other useful information.
If you want less information, git shortlog
and git log --oneline
are good options.
As you saw earlier, git clone <url>
will
create a clone repo into a new directory with the repo's name.
This is a really easy way to join a group project (i.e. the codebase already exists).
Cloning also sets up the remote connection, so you can begin pushing and pulling right away!
There also exists the concept of "forking."
Forking is useful if you want to take an existing project, branch off, and do your own stuff with it.
For example, if I wanted to make Leonux, I would fork the Linux project instead of cloning it. This way, when I make changes, my commits will get pushed to my remote instead of Linus'.
However, if I made some changes to some of Linus' files that I though he would like, I can make a pull request, or PR. He can pull in my changes, which get merged in with his stuff. Yay open source!
Let's say the code you just pulled doesn't work. Oh no!
If only we could find the rascal who pushed broken code and make them pay...
Luckily, there's a nifty tool to do that: git blame
.
It shows you, line for line, who updated it last.
The reason I wanted to include it is that our very own Prof Ben Liblit helped create a blame-like tool back in the svn-days.
Commands I like:
- Clean up git-related garbage ->
git gc
- Nuke your repo back to head (last commit) ->
git reset --hard HEAD
- Remove untracked files from the working tree - >
git clean
Be sure to check out the manual pages too!
Ok, ok! Here's what you can do:
$ sudo rm -rf ./.git
This command looks scary because it is close to the computer-killing command.
All it's doing is forcefully destroying the .git
folder and its contents. It shouldn't touch anything else.
You can check that git is gone by running git status
and getting a fatal error about the current directory not being a git repo.
Please first check that the directory is not your home (~
) or root (/
) directory!
If there is anything important in it, DO NOT RUN THIS COMMAND!
If you are worried about the effects of this command, find your friendly neighborhood hacker to help you out!
Otherwise, run this command:
$ sudo rm -rf <directory_name, "git_tutorial" for example>
It should not exist anymore.