Introduction

I am preparing this document as a guide for a group of people I will be working with. We will be developing some web application and we decided to manage our job with Git. Some of the people in the group are new to git. So this article is intended to be a guide for them.

What is git

In short: Git is a version control utility, it keeps track of the changes you made to documents, so you can review those changes, and go back to any stage you want at any time. In other words is like a time machine for your project.

Git is actually a lot more than that, and it is very powerful, but for the sake of simplicity we will leave the definition there for now.

First steps

You can start with git mainly in two possible ways.

You are starting the project

When you are the one starting the project, the first thing you need to do is initialize the git repository.

Let's create the folder where we will be working.

mkdir ~/my-project
cd ~/my-project

Now we need to start git.

git init

That will create a new folder ~/my-project/.git this folder, contains all the info git needs to keep track of your changes. You never have to edit or change anything in this folder by hand, and if you delete it, you will lose your project history.

Now you have your git project started, you need to start your work.

Let's say you create two documents inside:

emacs main-app.c
emacs sub-routines.c

Once you are done with that, you have add the information to git.

If you now check the status of the project, you will see that there are files not tracked by git. Let's do it:

git status

You will get this:

# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
main-app.c
sub-routines.c
nothing added to commit but untracked files present (use "git add" to track)##

What git is saying is that there are two documents which are new in the folder it is monitoring, but none of them have been explicitly added for tracking. So we need to add them.

git add main-app.c
git add sub-routines.c

Now they are added, if there too much files and you want to add all of them with one step.

git add -A

Let's check the status again:

git status

The output is:

# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
new file:   main-app.c
new file:   sub-routines.c
###

Now the files are added but not yet committed, you now have the chance to un-track or un-stage a file. If you want to, you can use git rm [somefile]. We do not like, so, let's go with our first commit.

git commit -m 'My first commit. I am adding here main-app.c which is the main code of the app, and it will call some sub routines from the sub-routin.c file. This last file is still emply'

We now have the files committed, if we check the status once again, we will see this:

git status

The output is:

# On branch master
nothing to commit (working directory clean)

The project already exists somewhere, you are cloning it

What is great about git, is that there is no central authority, you clone a project and you can work with it on your PC, with no need to be connected to the cloned repository, unless you want to share your changes.

Let's clone a project.

cd ~/
git clone git://server.com/my-project.git

You can also clone from your own disk, or a network disk: git clone /shared/network/project.git

Now that you have the project you can work on it, and submit your changes to the "central" repository.

vim README.txt

You have added a readme file, let's check the status:

git status

You will see this:

# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
README.txt
nothing added to commit but untracked files present (use "git add" to track)

We now need to add the file we just created. We will proceed from here as above.

git add README.txt
git commit -m 'added a README file with description of the app, and instruction for installation'

That is it. You have started with git.

Summary

You now know how to:

  • Create a git repository
  • Add untracked files to the project
  • Commit changes
  • Clone repositories and work on them

Working with remote repositories

In the section above, I have created a git repository at ~/my-project/, and then I have cloned it in this other path ~/second-project/, so the second working folder is: ~/second-project/my-project.

So, we will call the first one origin as that is the way git name the cloned repository by default. Let's go to first one.

cd ~/my-project/

And check the logs:

git log

The output is:

commit a6787b87ee36050f58014caa916bf85801771d34
Author: Guillermo Garron - Mac- <ggarron@localhost>
Date:   Mon May 13 15:28:37 2013 -0400

    My first commit. I am adding here main-app.c which is the main code of the app, and it will call some sub routines from the sub-routine.c file. This last file is still empty

If we now go to the second folder.

cd ../second-project/my-project/

And check the log:

git log

The output is:

commit b355a28868f5ac19b6ee949e110d0575dd5ed2dc
Author: Guillermo Garron - Mac- <ggarron@localhost>
Date:   Mon May 13 15:45:07 2013 -0400

    added a README file with description of the app, and instruction for installation

commit a6787b87ee36050f58014caa916bf85801771d34
Author: Guillermo Garron - Mac- <ggarron@localhost>
Date:   Mon May 13 15:28:37 2013 -0400

    My first commit. I am adding here main-app.c which is the main code of the app, and it will call some sub routines from the sub-routine.c file. This last file is still empty

As you can see the second is ahead by one commit. If we want to share the changes introduced in the second one, we can push them. But first take a look at bare repositories:

Bare repositories

In order to share the work, this two virtual workers, one working on ~/my-project/ and the other on ~/second-project/my-project/ need a bare repository. A bare repository one without a working tree, that is it is composed only by the .git folder.

In the two repositories we have, there is a .git folder inside the working folders, the bare repository will only be the .git folder with no working folder. Let's create that bare repository.

mkdir -p ~/tmp/my-project.git
cd ~/tmp/my-project.git
git init --bare

We now have a bare repository. Now let's go to the second project we have.

cd ~/second-project/my-project/
git remote rm origin
git remote add origin ~/tmp/my-project.git

We had to remove the origin before in order to add a new origin, it had an origin because it was cloned, basically you may have leave that there, and just add a new remote, but I prefer to name the "central" repository origin. Let's check the remote now:

git remote -v

The output will be something like this:

/Users/ggarron/tmp/my-project.git (fetch)
/Users/ggarron/tmp/my-project.git (push)originorigin

We can now push our changes there:

git push origin master

Here is the output:

Counting objects: 7, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (7/7), 739 bytes, done.
Total 7 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (7/7), done.
To /Users/ggarron/tmp/my-project.git
 * [new branch]      master -> master

Let's say now our first virtual developer wants to get our changes in his folder.

cd ~/my-project/

We need to add the origin here in order to pull the changes.

git remote add origin ~/tmp/my-project.git

There was no need to remove anything here, because this was not a cloned repo, it has no origin defined.

Let's now pull changes.

git pull origin master

The output is:

 From /Users/ggarron/tmp/my-project
  * branch            master     -> FETCH_HEAD
  Updating a6787b8..b355a28
  Fast-forward
   README.txt |    2 ++
   1 file changed, 2 insertions(+)
   create mode 100644 README.txt

As you can see, the file README.txt has been created with 2 insertions (was a small file). Now both folders are in sync with the "central" repository.

Summary

We now know how to:

  • Create bare repositories
  • Remove and add remotes
  • Push commited changes to the remote repo
  • Pull contents from a remote repo

Working with branches

One of the most powerful features of Git is working with branches. A branch is like a second set of folders to work at, that way you do not mess with the actual project. Is something like when you work with a configuration file, let's say http.conf. You want to do some changes, but if something goes wrong you want to be able to go back quickly. You usually create a copy of the file cp http.conf http.conf.original and now your are backed up. Git uses branches for that, so to say.

By default you are working on branch master, and you can create as many branches as you want to test locally before messing with the master branch.

In our example, let's suppose the first developer (Chief) creates a branch named testing and share it with the other developer via the "central" repo.

cd ~/my-project/
git checkout -b testing

The output is:

Switched to a new branch 'testing'

So git, created the new branch and switched to it. Let's now test a new sub-routing in our app.

vim sub-routines.c

After he made some changes

git status

The output is:

# On branch testing
# 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:   sub-routines.c
#
no changes added to commit (use "git add" and/or "git commit -a")

Now, let's add and commit those changes.

git add -A
git commit -m 'changes in main sub-routine, just for testing purposes. Debugging is hardly recommended before send it to production'

Now we can see the state of both branches.

git branch -v

The output is:

  master  b355a28 added a README file with description of the app, and instruction for installation
  * testing bf211b2 changes in main sub-routine, just for testing purposes. Debugging is hardly recommended before send it to production

As you can see, we are working on testing see the asterisk, and you can also see, that testing is ahead. Now the chief, wants to share his change with the other developer for him to debug.

git push origin testing

Here we are pushing the branch testing to origin (which is our central repository). The output you will see is:

Counting objects: 5, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 429 bytes, done.
Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To /Users/ggarron/tmp/my-project.git
 * [new branch]      testing -> testing

Now the second developer will pull those changes and work with them:

cd ~/second-project/my-project/
git checkout -b testing
git pull origin testing

The output is:

 From /Users/ggarron/tmp/my-project
  * branch            testing    -> FETCH_HEAD
 Updating b355a28..bf211b2
 Fast-forward
  sub-routines.c |    8 ++++++++
  1 file changed, 8 insertions(+)

Let's check the status:

git branch -v

The output is:

  master  b355a28 added a README file with description of the app, and instruction for installation
  * testing bf211b2 changes in main sub-routine, just for testing purposes. Debugging is hardly recommended before send it to production

The second developer can now work on the changes.

emacs sub-routines.c
git add sub-routines.c
git commit -m 'all tested, and corrected, ready for production'
git push origin testing

On the other side, the chief of developers will grab his copy and do the final tests, and then merge it with the master (production) branch.

cd ~/my-project/
git checkout testing
bit pull origin testing

After all test are done, it is time to merge.

Merging branches on Git

The chief of developers will now merge the testing branch into the master one.

Let's see the status of branches:

git branch -v

The output shows:

master  b355a28 added a README file with description of the app, and instruction for installation
* testing 0b38a32 all tested, and corrected, ready for production

Master is way behind testing. Switch to master

git checkout master

And merge both of them

git merge testing

The output is:

Updating b355a28..0b38a32
Fast-forward
 sub-routines.c |    4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

Extra notes

You can create as many branches as you want on your local PC, and work and test with them, you do not have to share all or any of them.

To delete a branch from origin the command is:

git push origin :testing

testing is just in our case, you have to use there the name of the branch you intend to delete. Consider that other may be working on it before deleting it.

Summary

Now you know how to:

  • Create branches
  • Switch between branches
  • Push and pull branches
  • Merge branches

Conclusion

Git is a lot more than just this, but this commands should be enough for simple projects, and for projects with few people working on them.

If you have any comment or question, please feel free to contact me

  • Last edited on May 13, 2013