Tuesday, March 5, 2013

Git Course (Part I)

Ok, so you have problems with git, right? Welcome to the crash course that will explain to you the fundamentals and the way we use this thing.

Repositories

Git is a VCS, a Version Control System. VCS are trackers of the evolution of something, typically code.

VCS normally have a repository, and git is no different. A repository contains the history of changes made to the state of your code, in an internal format that is recognisable only by the VCS tool.

By using the repository, the VCS tool should able to take you to any state of the code in time, and track who did what at what point.




The firsts VCS had a centralised repository. This means that to sync work, the user would have to push his stuff to a central repository, and another user would have to fetch the things the user did from that repository, eventually pushing his things to the repository as well.

The users had no direct interaction between themselves. So, for example, if a developer wanted to share something with another, he would have to make it available to everybody else.

Git is different. Every code copy in git has its own repository. There's no central repository.  You maybe are asking yourself now "Wait a minute, what is github then?". The fact is, even if you setup a central repository, it's just the same repository with the same things everyone has in their own repository (except that it's probably a bare repository, but you don't need to know that). The fact that it's central is just a convention.

So, if a developer wants to send code directly to another, he may do so. He should also be able later to share it with everybody else. And they both should be able to send code to a third developer should they so wish, who should also sync his code with the "central" repository, without having any problems.

How git is able to perform this magic will be explained in the following section.

 How to create a git repository? Simple!!! Just go to any folder where you want to track stuff and execute

git init .

You will notice that in this folder was created a .git subdirectory. This .git is where, among other things, git will store your own repository.

Working Tree, Index, Commits

The Working Tree is the contents of your folder under version control except for the .git subfolder. It contains a state of the code as it is now.

Let's practice a little. Create a folder called git_tutorial. Inside this folder run git init . as set before.

Now execute:

echo "This is a cool file!!!" > a.txt

weasley:git_tutorial rafael$ git init .
Initialized empty Git repository in /Users/rafael/dev/git_tutorial/.git/
weasley:git_tutorial rafael$ echo "This is a cool file" > a.txt
weasley:git_tutorial rafael$ cat a.txt
This is a cool file
weasley:git_tutorial rafael$ ls
a.txt
weasley:git_tutorial rafael$ ls -lah
total 8
drwxr-xr-x 4 rafael staff 136B Mar 5 00:56 .
drwxr-xr-x 8 rafael staff 272B Mar 5 00:55 ..
drwxr-xr-x 10 rafael staff 340B Mar 5 00:56 .git
-rw-r--r-- 1 rafael staff 20B Mar 5 00:57 a.txt

If you notice, you know have a file a.txt and the .git subfolder. Now, run git status, and you should see the following:

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

What git status is telling you is that you have a untracked file called a.txt. Untracked means git won't care about this file and won't put these alterarations on the repository unless you tell git to track it. The way to do this is to add the changes you made to the index.

The index contains alterations on your working tree that are ready to go to the repository. To add some alteration to the index, you use the command git add (unless it's a file deletion, in which case you would have to use git rm, but I won't cover it in this tutorial because there's a shortcut that takes care of that). git add is recursive, so you could do a git add . to include all your alterations in the index.

Now execute git add a.txt and run a git status. You should now see this:

weasley:git_tutorial rafael$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
# (use "git rm --cached ..." to unstage)
#
# new file: a.txt

Now a.txt is not untracked anymore and ready to go to the repository. The way to put a set of alterations in a repository is by creating a commit with said alterations.

A commit is a bunch of alterations, a reference to the commits parent (the commit on witch this commit was based) and a SHA-1 code that identifies the commit.

The SHA-1 identifies the commit, and git will assume that two commits are the same if their SHA-1 code are the same. This is how git can know that commits in different repositories are actually the same commit.

Every commit, except the first one, has a parent. If you change the parent of a commit you change the SHA-1, so it becomes a different commits. This notion will be of extreme importance when we're talking about syncing your code with other people, so be sure to remember it.

To create a commit in our repository, just type git commit. Your favourite editor will appear (you can configure what it is by defining a shell variable called GIT_EDITOR) where you can type a message. After you type a message and close your editor, you just created a commit:

weasley:git_tutorial rafael$ git commit
[master 7113d77] Hello commit world!!!!
 1 file changed, 1 insertion(+)
 create mode 100644 a.txt

If you run git status now:

weasley:git_tutorial rafael$ git status
# On branch master
nothing to commit (working directory clean)

It shows there is nothing to commit.  You can use git log to show the history of commits, and git log -p to see the history and a diff containing the changes.

Now let's learn a very useful shortcut. Put further stuff on a.txt

weasley:git_tutorial rafael$ echo "More content" >> a.txt
weasley:git_tutorial rafael$ 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: a.txt
#
no changes added to commit (use "git add" and/or "git commit -a")



See that a.txt was modified, but the changes are not in the index yet, so if you generate a commit, these changes won't be on it.

You could add the changes by using git add, but that's boring.

If git already tracked previous changes on a file, you can add all changes on files that git already knows about by passing the -a flag to git commit.

So by executing git commit -a you add changes on files that were already in git to the index before creating the commit.

Be careful because this won't affect new files.

weasley:git_tutorial rafael$ git commit -a
[master ca93f24] Another commit.
 1 file changed, 1 insertion(+)

Also, take a look at git commit --amend. If you don't like a commit and wants to edit it, git commit --amend let's you remake that commit.

Next Steps

That's all for today. In the next part of this tutorial, I will tell you about the stash and I will tell you how you can change your commit history,

Till next time!

No comments:

Post a Comment