Skip to main content
What is common between Google, Facebook, Microsoft, Twitter and Linked in? If you are looking for the answer its Git the Distributed Version Control System (DVCS) that has simplified software revision control. Its major features are speed and performance combined with ease of use provided you know the basic git concepts.

If you are new to git you should read some getting started tutorials or if you have used SVN you should read migrating to git. For the audience of this post, I assume that you are already using git for some time and are familiar with concepts like commit, push a branch, pull changes from remote repository, merging a branch to "master" and similar daily things that git users normally do.

Git is a lot more popular than SVN or Mercurial. If you take check Google trends in the past 5 years (July 2009 - July 2014) in Internet and Telecom category, git it twice or move as popular as the other two:

More on Git

I started using git in early 2009, then I had a little experience with SubVersion (SVN) and git was a refreshing change to slow and difficult SVN. At that time, we did not do much branching or follow the git flow branching model.

I rediscover the power of Git in 2012 when I joined Namshi where we were a bigger team than I used to work with and Git made total sense. We were also using a revised git flow with lots of branching, merging, rebasing and tagging for releases.

Recently I watched a video "Git happens" by @Jessitron and I refreshed the git concepts. This video is great not only that she is talking about git, also because it's not a presentation she uses a whiteboard, markers and some sticky notes to make all the most important git concepts very clear to you. If you are using git I really recommend watching this:



And remember when using Git, its about telling the story of your project, how you and your team decide it will help maintain and informative history of your project. 

The Tips

Some Git tips beyond the basics (commit, pull, push) are as follows:

Diff (what changed?)

So you are working on a new feature on your branch my-feature, before you commit, you do a git status to list your files, then you need to know what changed in the files you should do git diff on your working directory. It will see all the changes you have made.

ᐅ git diff 

diff --git a/Dockerfile b/Dockerfile
index 392e7c0..a0a7c9f 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -48,6 +48,13 @@ ADD build/sites-enabled/dashboard /etc/nginx/sites-enabled/dashboard
ADD build/sites-enabled/test.local /etc/nginx/sites-available/test.local
ADD build/sites-enabled/test.local /etc/nginx/sites-enabled/test.local

+ADD build/sites-enabled/drupal7.local /etc/nginx/sites-available/drupal7.local
+ADD build/sites-enabled/drupal7.local /etc/nginx/sites-enabled/drupal7.local
+
+ADD build/sites-enabled/drupal8.local /etc/nginx/sites-available/drupal8.local
+ADD build/sites-enabled/drupal8.local /etc/nginx/sites-enabled/drupal8.local
+
+#phpmyadmin
ADD build/sites-enabled/phpmyadmin /etc/nginx/sites-available/phpmyadmin
ADD build/sites-enabled/phpmyadmin /etc/nginx/sites-enabled/phpmyadmin

diff --git a/readme.md b/readme.md
index 7ddea6c..4188d66 100644
--- a/readme.md
+++ b/readme.md
@@ -1,6 +1,6 @@
# Docker: Ubuntu, Nginx and PHP Stack

-This is the basis for LEMP stack (minus MySQL). This is based on [phusion/baseimage-docker](https://github.com/phusion/baseimage-docker) base Ubuntu image, which takes care of system issues which Docker's base Ubuntu image does not take care of, such as watching processes, logrotate, ssh server, cron and syslog-ng.
+This is the basis for LEMP stack (without MySQL). This is based on [phusion/baseimage-docker](https://github.com/phusion/baseimage-docker) base Ubuntu image, which takes care of system issues which Docker's base Ubuntu image does not take care of, such as watching processes, logrotate, ssh server, cron and syslog-ng.

You can also use git diff if you have already added the files to the staging area with git add, you will need to use git diff --cached. Diff can be used to compare branches and commits for example:

✹✭ ᐅ 
git diff master...my-feature

diff --git a/Dockerfile b/Dockerfile
index 9f9cd77..392e7c0 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -6,34 +6,115 @@ RUN /etc/my_init.d/00_regen_ssh_host_keys.sh

CMD ["/sbin/my_init"]

+# install certificates
+ADD build/certificates/server.crt /etc/nginx/certificates/
+ADD build/certificates/server.key /etc/nginx/certificates/
+
# Nginx-PHP Installation
RUN apt-get update
RUN apt-get install -y vim curl wget build-essential python-software-properties
RUN add-apt-repository -y ppa:ondrej/php5
RUN add-apt-repository -y ppa:nginx/stable
+
RUN apt-get update
+RUN apt-get install -y python-software-properties python python-setuptools ruby rubygems

It can be used on github as well, with a URL like: https://github.com/geshan/angular-presentation/compare/master...more-intro - so this is comparing master with the more-info branch. The same can be done with commit hashes.

Global Git Ignore

If you use an IDE and it creates folders like .settings or .idea and you want to ignore it globally on all git repositories you can do it with global git ignore rather than adding it to each .gitignore file in each repository. You can create a file say global_gitignore on your home directory and list the folders and files you want to be ignored in all git repositories like:
#global git ignore
.idea
.settings

/test.txt

Then run the following command you will have the above git ignore rules applied to all the git repositories:
git config --global core.excludesfile ~/.gitignore_global

There are a lot of other git configurations you can try and tune git to meet your needs, if you want to look at the current configs applied to your git globally do cat .gitconfig on your home directory.

Stash your work

You are working on feature-a, an urgent bug say bug-x is discovered and you need to leave what you were doing for feature-a and fix bug-x. What do you do with the changed files in branch feature-a that you were working on, you don't wan't to commit or push it as its a work in progress. Here comes git stash to your rescue, you can just stash what you were doing on branch feature-a and finish work of bug-x then come back to feature-a branch and pop or apply your stash. How?

✹ ᐅ cd my-project
✹ ᐅ git checkout -b feature-a

# working on feature-a, some files changed say 3 of them
# bug-x discovered, need to fix it urgently so let's stash changes
# (save them for later)
✹ ᐅ git stash save feature-a

# lets go to master and create a new branch to fix bug-x
✹ ᐅ git checkout master
✹ ᐅ git checkout -b bug-x

# work to fix bug x for 1 hr, its fixed now.
✹ ᐅ git add .
✹ ᐅ git commit -m 'bug-x fixed with change in config files'
✹ ᐅ git push origin bug-x

# then open a pull request on github for bug-x,
# and come back to working on feature-a

✹ ᐅ git checkout feature-a
✹ ᐅ git stash pop
# all your changed files are back and you are at the stage
# where you left it before fixing bug-x

Stash pop will remove the last stash, you can do  git stash list to check all your stashes, stashes can be saved without name and can be applied with the hash. Check the stashing docs for more information, generally I follow the above flow for staging and prefer not having any stashes in the list.

Squash your commits

You did this big feature taking 4 days work and as a good git user you did commits when the code was stable. So now you have 10 commits in total for the feature-b you worked in for 4 days. Do you really want to send a Pull Request with 10 commits, may be along the way you wrote some commits messages that are not so relevant now. So how do you get the 4 commits to become 1, its easy you squash your commits using git reabse -i, how?

Now you have 4 commits (shown using gitk ) on top of master:


you need to execute the following command:

✹ ᐅ git rebase -i HEAD~4 #the last number, here 4 is the no. of commits you want to squash.

# you will get a screen like this :

pick 8dd81e6 feature-b changes to the config files
pick 7ea892d Feature-a fixed class A b and C
pick a465749 Feature-b fixed tests
pick cd6f406 Feature-b fixed tests


# change all picks except of the first one to s.
# s is short for squash like below:
pick 8dd81e6 feature-b changes to the config files
s 7ea892d Feature-a fixed class A b and C
s a465749 Feature-b fixed tests
s cd6f406 Feature-b fixed tests

# now exit your editor, if you are using vim :wq
# then as you are squashing commits you can select which commit messages to pick
# from a screen like:
# This is a combination of 4 commits.
# The first commit's message is:
feature-b changes to the config files

# This is the 2nd commit message:

Feature-a fixed class A b and C

- [x] Works for A and B

# This is the 3rd commit message:

Feature-b fixed tests

* fixed most test

# This is the 4th commit message:

Feature-b fixed tests

- [x] fixed all tests


# Pick the ones that you need or delete, for this example I will not delete anything
# and quit the editor

# 4 of your commits are squashed into 1.

If your commit squash was successful, you will see only 1 commit in place of the 4 on gitk with all commit messages intact, like:

Conclusion

This is just scratching the surface of git there are lots of other things that can be done with git, like cherry pick commits, list git branches sorted by created date, bisect for debugging, you have to know how to fix conflicts with tools like meld etc.

Then you have git hooks which open up a new world of its own like having pre-commit hooks to do checks of code and run tests. Git has also been used to version control text related projects like books not only code. So the possibilities are endless and if you are not using Git you are missing on a lot of things.

Comments