In a previous post, we have seen what Git is and its main characteristics. Now, we’ll go more into detail about its functionality and we’ll see what a usual day working with Git looks like.

But before, some initial concepts:

  • Repository: A working tree of files and directories which can be versioned, keeping track of every single modification made over the working tree, been able to move forward and backward in its history.
  • Branch: it is an alternative image of the repository, keeping track of its own history of modifications. A repository has a main branch called master, and it can have an undefined number of branches, some of them may be copies of remote branches and the default name for the upstream repository is origin. The current branch of the working copy can be always referenced as HEAD.
  • Commit: it is a concrete state of a branch, containing the modifications made to the entire working tree since the previous commit in the history, as well as author information and timestamps. It can be identified by its SHA hash, but a name or tag can be associated to it in order to make thing easier.
  • Merge: it is the process of integrating changes or commits of two different branches. This integration is automatically carried by Git, if there are no conflicts between commits.
  • Push: the changes committed in a local branch into a remote branch.

These are the basic concepts we are going to use in the rest of this post. Now let’s start with the fun!

Setting up the repository: initialize and importing

First step is to create or to obtain a repository. In order to create a fresh new repository, this is the instructions we need to execute:

mkdir hello_world
cd hello_world
git init

Alternatively, we can grab an already initialized remote repository with these instructions:

git clone git://url.to/hello_world
cd hello_world

A Git repository is a normal directory that contains a .git directory inside, where all the necessary information to track changes will be stored.

Modifications: status, adding, committing and reverting

Once we have our repository ready to work (we can check that its clean by using the command status):

$ git status
# On branch master
#
# Initial commit
#
nothing to commit (create/copy files and use "git add" to track)

we can start to work in the current directory, creating, modifying and deleting files and directories as we need to. For example, I will create a Hello World! in java (but a more complex one than the usual, to prove how to work with several files). First of all, I’m going to create two separate folders: one for sources and other for classes. Then I will create an empty Greetings.java and a HelloWorld.java and then I will make a commit with the initial structure:

mkdir src bin
touch src/Greetings.java
touch src/HelloWorld.java
git add –A

Now we can check the status of the current working tree and see that there are changes pending to be committed:

$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
# (use "git rm --cached ..." to unstage)
#
# new file: src/Greetings.java
# new file: src/HelloWorld.java
#

So let’s commit these modifications. Every commit needs a commit message that identifies the contents of this commit:

$ git commit –m "Initial commit: project structure and source files created"
[master (root-commit) 8738922] Initial commit: project structure and source files created
0 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 src/Greetings.java
create mode 100644 src/HelloWorld.java

Ok, we have our prune project ready to be coded. Now it is time to type the necessary code to get the result expected, so open Greetings.java and HelloWorld.java with your preferred editor and paste the following code:

Greetings.java

public class Greetings {

	public int sayHello() {
		System.out.println("Hello World!");
	}
}

HelloWorld.java

public class HelloWorld {

	public static void main(String[] args) {
		Greetings g = new Greetings();
		g.sayHello();
	}
}

Now if we check the status of the working tree, we can see that these two files have modifications pending to be committed:

$ git status
# On branch master
# Changes not staged for commit:
# (use "git add ..." to update what will be committed)
# (use "git checkout -- ..." to discard changes in working directory)
#
# modified: src/Greetings.java
# modified: src/HelloWorld.java
#
no changes added to commit (use "git add" and/or "git commit -a")

Let’s commit it, it is a Hello World, what could it be wrong, huh?

$ git commit –a –m "Java code for Greetings and HelloWorld classes"
[master 18e6ec5] Java code for Greetings and HelloWorld classes
 2 files changed, 13 insertions(+), 0 deletions(-)

Now we can see that our repository history has two commits:

$ git log
commit 18e6ec54628a5f01f6beda8b30c64f61ab23585a
Author: Daniel Pecos Martinez
Date:   Sun Aug 28 22:42:45 2011 +0200

    Java code for Greetings and HelloWorld classes

commit 8738922a6193fbbeb4bcb67e663b0403a8fbdace
Author: Daniel Pecos Martinez
Date:   Sun Aug 28 19:33:36 2011 +0200

    Initial commit: project structure and source files created

And if we want to see a diff output of the current HEAD revision with its previous commit we can do like this:

$ git diff HEAD^1
diff --git a/src/Greetings.java b/src/Greetings.java
index e69de29..aeff26c 100644
--- a/src/Greetings.java
+++ b/src/Greetings.java
@@ -0,0 +1,6 @@
+public class Greetings {
+
+       public void sayHello() {
+               System.out.println("Hello World!");
+       }
+}
\ No newline at end of file
diff --git a/src/HelloWorld.java b/src/HelloWorld.java
index e69de29..cbc10da 100644
--- a/src/HelloWorld.java
+++ b/src/HelloWorld.java
@@ -0,0 +1,7 @@
+public class HelloWorld {
+
+       public static int main(String[] args) {
+               Greetings g = new Greetings();
+               g.sayHello();
+       }
+}
\ No newline at end of file

Time to test it! Compilation is the first step (as you know for sure ;-)):

$ javac src/Greetings.java -d bin/

$ javac src/HelloWorld.java -d bin/ -cp bin/
src\HelloWorld.java:6: missing return statement
        }
        ^
1 error

Ups! There was an error :-S Well, that one is easy to fix: let’s change return type of main method to void:

$ javac src/HelloWorld.java -d bin/ -cp bin/
$ java -cp bin/ HelloWorld
Hello World!

So now everything seems fine, but our working tree is not clean, we have our last modifications pending to commit. But, if I commit them and I publish the repository, everyone could see what a fool I am because of that silly mistake, what should I do? Well, I ’ll try to hide my failure so I will amend last commit and include modifications made later:

$ git commit -a --amend
[master a612cb0] Java code for Greetings and HelloWorld classes
 2 files changed, 13 insertions(+), 0 deletions(-)

$ git log
commit a612cb025664304586609700b9874eab19aab8b1
Author: Daniel Pecos Martinez
Date:   Sun Aug 28 22:42:45 2011 +0200

    Java code for Greetings and HelloWorld classes

commit 8738922a6193fbbeb4bcb67e663b0403a8fbdace
Author: Daniel Pecos Martinez
Date:   Sun Aug 28 19:33:36 2011 +0200

    Initial commit: project structure and source files created

Perfect! I have included the necessary fix for my bug and nobody will notice it, great! But wait… my current working tree is not clean:

$ git status
# On branch master
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#       bin/
nothing added to commit but untracked files present (use "git add" to track)

Well, these are the files resulting from compilation, so they can be deleted (in fact, is not correct to commit them), but this will happen again and again, any time I compile my project and don’t delete the resulting classes. The way to avoid this is to tell Git to ignore certain files that match a defined pattern, defined in a special file .gitignore:

$ cat > .gitignore
bin/*

$ git status
# On branch master
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#       .gitignore
nothing added to commit but untracked files present (use "git add" to track)

Done! now the only thing left is to commit the just created file (I let this to you, so you can practice a little bit with git)

That’s all folks! (for now ;-)). In following posts I will try to explain how to work with branches (remote and local) and how to resolve conflicts, as well as some nice tools provided by git.