Basic GIT tutorial: centralised and decentralised model

Git is fast becoming the most popular versioning control system in the market today. It is open sourced and offers a number of significant advantages over svn. SVN will probably still be around for a while because a lot of people and software are still dependent on it or don’t see a need for change. I have been using GIT for a while and really liked it. Where else can I share this information except in my own blog!

For introduction to git, check out the official git user manual. For svn users, the git crash course is useful. I am using git 1.72 btw.

Centralised Model

True enough, svn works well in a centralised repo environment, ie everyone check-in and check-out from one single repository. We can simulate this in git as well.

In a typical dev environment, say we have one team lead and x developers. To simulate the centralised model in git, the team lead creates a personal repo first (I’ll be using dummy data and dir names – the idea is just to document the workflow).

[teamlead@web git]$ git config --global user.name "teamlead"
[teamlead@web git]$ git config --global user.email "teamlead@test.com"
[teamlead@web ~]$ mkdir git
[teamlead@web ~]$ cd git
[teamlead@web git]$ git init
Initialized empty Git repository in /home/teamlead/git/.git/
[teamlead@web git]$ echo "test" > test
[teamlead@web git]$ git add ./
[teamlead@web git]$ git commit -a -m "init"
[master (root-commit) 0cd9b7c] init
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 test

Assuming I am the teamlead, I will now need to create a bare repo somewhere else so that everyone can push to it, say the dir “pub” under my home dir. I don’t want anyone updating my own repo.

[teamlead@web git]$ cd ..
[teamlead@web ~]$ ll
total 4
drwxrwxr-x 3 teamlead teamlead 4096 Sep  1 00:34 git
[teamlead@web ~]$ mkdir pub
[teamlead@web ~]$ cd pub
[teamlead@web pub]$ git init --bare
Initialized empty Git repository in /home/teamlead/pub/

OK the new repo is still empty, as the teamlead, I need to populate it with my data first (noticed I have one default master branch).

[teamlead@web git]$ git remote add origin /home/teamlead/pub
[teamlead@web git]$ git branch -a
* master
[teamlead@web git]$ git push origin master
Counting objects: 3, done.
Unpacking objects: 100% (3/3), done.
Writing objects: 100% (3/3), 207 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
To /home/teamlead/pub
 * [new branch]      master -> master

This is cool, now my master branch is replicated over to pub. I will tell my developer to grab the repo. But before I do that, lets make sure that the pub repo is really publicly editable.

[teamlead@web home]$ ll
total 20
drwx------ 2 devA     devA     4096 Sep  1 00:32 devA
drwx------ 2 devB     devB     4096 Sep  1 00:32 devB
drwx------ 4 teamlead teamlead 4096 Sep  1 00:50 teamlead
[teamlead@web home]$ chmod o+x teamlead
[teamlead@web home]$ cd teamlead/
[teamlead@web ~]$ ll
total 8
drwxrwxr-x 3 teamlead teamlead 4096 Sep  1 00:34 git
drwxrwxr-x 7 teamlead teamlead 4096 Sep  1 00:37 pub
[teamlead@web ~]$ chmod o+w -R pub

Making dir with permission 777 is not a good practice but good enough for this illustration. Well, now devA will try to checkout from the pub repo and pushes a change back.

[devA@web ~]$ git clone /home/teamlead/pub git
Cloning into git...
done.
[devA@web ~]$ ll
total 4
drwxr-xr-x 3 devA devA 4096 Sep  1 00:58 git
[devA@web ~]$ cd git
[devA@web git]$ ll
total 4
-rw-rw-r-- 1 devA devA 5 Sep  1 00:58 test
[devA@web git]$ cd ..
[devA@web ~]$ cd git
[devA@web git]$ echo "devA test" >> test
[devA@web git]$ git commit -a -m "devA input"
[master 0542737] devA input
 1 files changed, 1 insertions(+), 0 deletions(-)
[devA@web git]$ git push origin master
Counting objects: 5, done.
Writing objects: 100% (3/3), 237 bytes, done.
Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
To /home/teamlead/pub
   0cd9b7c..0542737  master -> master

All good. Let’s see if teamlead can get the update.

[teamlead@web git]$ git fetch origin
remote: Counting objects: 5, done.
remote: Total 3 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From /home/teamlead/pub
   0cd9b7c..0542737  master     -> origin/master
[teamlead@web git]$ git merge origin/master master
Fast-forwarding to: origin/master
Already up-to-date with master
Merge made by octopus.
 test |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
[teamlead@web git]$ cat test
test
devA test

Got the changes… yay.

Decentralised Model

The philosophy behind the decentralised repo is to commit, branch and merge often. Imagine everyone in the team has their own sharable repo… and you can share your branches anytime. My experience with the decentralised model is that it works better with a bigger team.

Let us use the same development team as before. 1 x teamlead and x developers. The teamlead will pull the changes from the developers and then update the main repo which happens to be a staging www site.

We start by creating the staging site

[root@web html]# pwd
/var/www/html
[root@web html]# mkdir git
[root@web html]# cd git
[root@web git]# git init
Initialized empty Git repository in /var/www/html/git/.git/
[root@web git]# echo "test" > test
[root@web git]# git add test
[root@web git]# git commit -a -m "init"
[master (root-commit) e604a85] init
 Committer: root 
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.
You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"
    git config --global user.email you@example.com

If the identity used for this commit is wrong, you can fix it with:

    git commit --amend --author='Your Name '

 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 test

All good. Now to do proper development, we need to have revisions. We create ver1.

[root@web git]# git checkout -b ver1
Switched to a new branch 'ver1'

give permission to apache so that we can view it on the web

[root@web git]# cd ..
[root@web html]# chown apache:apache -R git

now developer A make some branches… Branching is a good practice  in git and one should do it often.

[devA@web ~]$ git clone /var/www/html/git
Cloning into git...
done.
[devA@web ~]$ cd git
[devA@web git]$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/ver1
[devA@web git]$ git checkout -b origin/ver1 ver1
[devA@web git]$ git checkout -b ver1 origin/ver1
[devA@web git]$ git checkout -b ver1_dev ver1
Switched to a new branch 'ver1_dev'

Dev A can create any no. of branches he likes and merge them with his copy of ver1 anytime.

[devA@web git]$ git branch -a
  master
  ver1
* ver1_dev
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/ver1
[devA@web git]$ echo "test devA" >> test
[devA@web git]$ git commit -a -m"test again"
[ver1_dev a45566d] test again
 1 files changed, 1 insertions(+), 0 deletions(-)
[devA@web git]$ git checkout ver1
Switched to branch 'ver1'
[devA@web git]$ git merge ver1_dev ver1
Fast-forwarding to: ver1_dev
Already up-to-date with ver1
Merge made by octopus.
 test |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

dev A has finished his development and no longer need his dev branch, so he deletes it.

[devA@web git]$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.
[devA@web git]$ git branch -d ver1_dev
Deleted branch ver1_dev (was a45566d).

dev A has no rights to push the changes because they are now using a different workflow. They no longer push, they only pull. team lead has been informed of devA changes and need  to merge devA changes to his.

[devA@web git]$ mail -s "Hi pal, updated my ver1, pls pull" teamlead@test.com

upon receiving the email, team lead pulls the update from dev A and checks that everything is working

[teamlead@web ~]$ sudo chmod o+x /home/devA
[teamlead@web git]$ git remote add devA /home/devA/git
[teamlead@web git]$ git fetch devA
remote: Counting objects: 9, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 7 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (7/7), done.
From /home/devA/git
 * [new branch]      master     -> devA/master
 * [new branch]      ver1       -> devA/ver1
[teamlead@web git]$ git checkout -b ver1 origin/ver1
Branch ver1 set up to track remote branch ver1 from origin.
Switched to a new branch 'ver1'
[teamlead@web git]$ git merge devA/ver1 ver1
Fast-forwarding to: devA/ver1
Already up-to-date with ver1
Merge made by octopus.
 test |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

All good. now teamlead can update the staging site using his own copy.

[root@web html]# su - apache
-bash-3.1$ cd /var/www/html/git
-bash-3.1$ git branch -a
  master
* ver1
-bash-3.1$ git remote add teamlead /home/teamlead/git
-bash-3.1$ git fetch teamlead
remote: Counting objects: 7, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 5 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (5/5), done.
From /home/teamlead/git
 * [new branch]      master     -> teamlead/master
 * [new branch]      ver1       -> teamlead/ver1
-bash-3.1$ git merge teamlead/ver1 ver1
Fast-forwarding to: teamlead/ver1
Already up-to-date with ver1
Merge made by octopus.
 test |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
-bash-3.1$ cat test
test
test devA

now we can toggle between different versions in staging

-bash-3.1$ git branch
  master
* ver1

Well, after some uat testing, we found ver1 to be stable. let’s merge it back to the trunk.

-bash-3.1$ git checkout master
Switched to branch 'master'
-bash-3.1$ git merge ver1
Updating e604a85..fb7bd4c
Fast-forward
 test |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

In the mean time, devB has started working on version 2

[devB@web git]$ git branch ver2
[devB@web git]$ git branch -a
* master
  ver1
  ver2
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/ver1
[devB@web git]$ git checkout ver2
Switched to branch 'ver2'
[devB@web git]$ ls
test
[devB@web git]$ echo "ver2" >> test
[devB@web git]$ git commit -a -m "ver2"
[ver2 2a091f9] ver2
 1 files changed, 1 insertions(+), 0 deletions(-)

devB is aware that master repo could be updated (someone might have fixed a bug) and he needs to integrate the master changes to his ver2. As a good practice, he tries to do this everyday so that he dont get a “big merge” when he finishes his ver2.

While still in the version2 branch,

[devB@web git]$ git pull origin master
From /var/www/html/git
 * branch            master     -> FETCH_HEAD
Updating 230806d..879e570
Fast-forward
 test |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

[devB@web git]$ git rebase master
First, rewinding head to replay your work on top of it...
Applying: ver2
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
Auto-merging test
CONFLICT (content): Merge conflict in test
Failed to merge in the changes.
Patch failed at 0001 ver2

When you have resolved this problem run "git rebase --continue".
If you would prefer to skip this patch, instead run "git rebase --skip".
To restore the original branch and stop rebasing run "git rebase --abort".

ah, we have a conflict. devB needs to resolve it as early as he can. After editing the file,

[devB@web git]$ git add test
[devB@web git]$ git rebase --continue
Applying: ver2

All good. Now devB can continue his development on version 2…. When done, team lead pull changes from devB and merge into his copy. As usual, he updates the staging site. If for some reason ver2 fails in critical occasion, he can revert back to his ver1 easily by just checking out the ver1 branch – reverting changes in production can never be easier.

Conclusion

I have only covered the basics, there are much more like reverting to past versions, taging….etc. I am sure you will enjoy git as much as I do. I hope that as Git becomes more popular, there will be better GUI and integration with development IDEs/project management software. Yes, there were efforts being made till this point but I still find them buggy when compared to the command line version.

Like it.? Share it:

One Response to Basic GIT tutorial: centralised and decentralised model

  1. Lens Hood

    `:: I am really thankful to this topic because it really gives great information ”`