This tutorial introduces just enough Git commands to make a project.
Be aware that it uses
trunk as the main branch instead of
It is important for people to know who you are when committing changes.
Create a file
~/.gitconfig (by typing
git config --global -e in a terminal) to contain some minimal information about yourself like:
[user] name = Alex Klinkhamer email = firstname.lastname@example.org [push] default = matching
If sharing your real email address on every commit feels weird, note that it can be fake. However, if going down this route, consider using a noreply address from GitHub to associate your commits with you (or at least to your GitHub account).
Code shouldn’t just be stored on one machine because the hard drive may crash or we may have multiple work machines.
Therefore, we should make a repository on a server that all of our machines can access.
Let’s assume you want to make a project named
$proj and store a copy of it on a remote server at
In this case, the
$remote_url is hosted on an SSH-accessible server, but it could be a path on your local machine like
If it’s a GitHub URL like
email@example.com:grencez/lace.git, then just use GitHub to create the repository and skip this section.
$remote_url repository used in this example.
First SSH in:
ssh firstname.lastname@example.org mkdir -p ~/repo/$proj.git cd ~/repo/$proj.git
Private. If this is a project just for you, then all we need to do is initialize the repository.
git init --bare
Public. If this is a project should be shared with everyone on the remote machine, we must allow people to get to the repository and make it readable and writable by everyone.
chmod a+x ~/ ~/repo git init --bare --shared=0666
Shared with Group.
Usually a public repository isn’t the greatest idea because anyone on the machine can mess with your code.
If you have the luxury of having a group containing all members, we can restrict access to the group.
Let it be defined as
chmod a+x ~/ ~/repo chgrp $group . chmod g+rwxs . git --bare init --shared=group
This section describes the minimal amount of knowledge you need to use git.
Note that some commands (
git pull and
git push) assume some default values which were set by
Back on your own machine, get a copy of the repository using
mkdir -p ~/code cd ~/code git clone $remote_url cd $proj
After this initial clone, it is simple to pull changes other people have made.
To add a new file to version control:
echo "# $proj has begun!" > README.md git add README.md
To see what files have been added, modified, or are not tracked by git, use the status command.
To commit all of your changes:
git commit -a
This will open an editor so you can explain your changes in a commit message.
The editor is determined by the
$EDITOR environment variable, which is probably
nano by default… pretty easy to use.
If you only have a short message and don’t want to work in an editor, the message may be specified directly.
git commit -a -m 'Add README'
One can also change the most recent commit or its message (ONLY DO THIS IF THE COMMIT HAS NOT BEEN PUSHED).
git commit -a --amend
Finally, push your changes to the repository, otherwise nobody will see them!
When it’s the first commit, you generally need to specify a push location and branch like
git push origin master.
I tend to prefer a
trunk branch instead of the default
master one since it matches Subversion terminology.
Setting that up is a couple of extra commands but is pretty hassle free afterwards:
git branch -M trunk git push -u origin trunk git push origin trunk
For all pushes after the first one,
trunk are implied.
If you still need the
trunk arguments, you can set the defaults in an editor with
git config -e or directly like:
git config branch.trunk.merge refs/heads/trunk git config branch.trunk.remote origin
To see other options:
git config -l
Add file, remove file, move file, or discard changes.
git add new-file.c git rm unwanted-file.c git mv old-file.c new-file.c git checkout HEAD file-with-changes.c
If you previously added a file and want to remove it, you must be rather forceful.
git rm -f --cached unwanted-file.c
See previous commit messages.
git log git log --follow file-that-has-moved.c
The above instructions are fine for working by yourself, but what about when others are making changes concurrently?
git push complains about your copy not being up to date, you’ll need to do a
However, there could be conflicts!
(WARNING: I don’t have much experience here, so perhaps look elsewhere for good advice.)
If you have uncommitted changes and wish to pull new changes from a teammate, first stash your changes, then have them automatically merged. (Merges don’t always go cleanly though, so copy your changes elsewhere just in case.)
git stash save git pull git stash pop
Most commits do warrant some description. Imagine if your changes broke something, and someone else (or “future you”) is tasked with fixing it. Without a meaningful commit message to read, that person doesn’t know your intent in making those original changes, and their change may break something else! (Side note: Use tests to protect your code from others.)
A commit message should be formatted with the first line being a short description (cut off at 50 characters), followed by an empty line, and then more detailed explanation. I tend to prefer small code changes these days, with most documentation in examples and tests, leaving the commit messages to explain why code is being changed how it is.
My old style noted what changed where. It served me well for a long time, so here’s an example:
Add normal mapping to raytracer 1. In the raytraced version, one can now specify a normal map in object coordinates to give the illusion of a more complex surface. a. material.c/h map_normal_texture() a. wavefront-file.c readin_wavefront() a. raytrace.c fill_pixel() - This function is getting too complicated... 2. When determining the normal of the track's surface, be sure the damn thing is normalized! This only affects tracks without vertex normals. b. motion.c apply_track_gravity() 3. Clean up some parse code with the addition of a new macro. a. util.h AccepTok() c. wavefront-file.c + readin_wavefront() + readin_materials() c. dynamic-setup.c readin_Track()
Changes are described in order of priority and hierarchically by: intent (number prefix), file (letter prefix), function or class (
+' prefix, or on same line if there's room), and extra description (-‘ prefix).
The letter prefixes signify the type of change:
c means change code,
b means bug fix,
a means add code (new functionality),
r means remove code, and
d means comment/documentation changes (if the file also contains code).
The letters may be a bit pedantic (former colleagues used a `*’ prefix instead).