Wednesday, November 4, 2015

Unleashing the Git - part 1 - Fundamentals

Git is a distributed version control system. It has become extremely popular and replacing other version control systems in the industry very fast. Hence, knowing some day to day uses of git is very essential for all developers. I thought of writing some series of posts to cover some very useful git usages along with an example for you to grasp it easily. This is the first post of that series.

Before we delve into details on using the git, make sure you have git installed. If not, you can find details of git installation in the following location.

https://git-scm.com/book/en/v2/Getting-Started-Installing-Git

Ok. Assuming you have git installed, let's dive into using it. 

Go into a directory where you want to monitor for changes. Let's create an empty directory called 'example' in $HOME. I'll refer the directory as $HOME/example from this point.

Most of the commands and examples are in par with the following two books related to Git. It's really worth the time to read these two books if you are working with git on day to day basis.

Git: Version control for everyone
Pragmatic Guide to Git
$ cd $HOME/example
First, let's find out some initial git commands you might come across when initializing a git repository.
$ git init
Initializes empty Git repository in /home/shazni/example

To configure Git, you can use the following commands:
$ git config --global user.name "your full name"
$ git config --local user.name "your full name"
$ git config --global user.email "your email id"
$ git config --local user.email "your email id"
$ git config -l // lists all the configuration variables
$ git config --global color.ui auto  // Optional
$ git config --global core.editor /path/to/editor  // Optional
$ git config --global merge.tool "gvimdiff"   // Setting the diff tool for git mergetool command
Before we proceed, if you need any help on git, issue the following command.
$ git help
If you need to see the built-in documentation of a particular command, you may issue
$ git help <command name=""></command>     // e.g. git help init  
Now copy a file called abc.doc to the directory. This file is still not being monitored by git. Hence, it is referred to be in unstaged state. To make it into staged state, i.e. to make it available for git to monitor it, we have to issue the following command.
$ git add abc.doc
Issue the following command to see the status of all the files.
$ git status
To add multiple files, we may use the following commands,
$ git add .
$ git add *.docx
Remember these commands would add all the files and all the .docx files to the staged state respectively. This includes all the temporary files of the original files, which is often named after ~ with it's original name to save state of the files for disaster recovery. For example when abc.doc is open there can be another file name ~abc.doc. When we use 'git add' even this file is staged. This is at times troublesome. Git has a workaround for this. We can create a file named .gitignore and specify what files and what types of files we need to ignore from 'git add'. Create a file named .gitignore and type the following.

~*.*

This is a pattern. This says to avoid all temporary files like ~abc.doc

Undoing Uncommitted Changes
git reset abc.doc // To make from staged to unstaged before commiting or more specifically

git reset HEAD -- abc.doc // Here -- says Git that everything follows are file names, not commands
With git reset you are telling Git, “Change the index— the staging area — to the latest version of this file.”. Normally git reset is used when you want to unstage already tracked files

Following is normally used to un-stage new files that you staged but still not in git's control. The file will still be in the local working tree
git rm --cached abc.doc // git rm is usually done to rm files from remote repository. Adding --cached options tells to leave the working tree alone.

git checkout -- abc.doc // Caution : Be careful with this command. This will completely wipe out all your current changes and brings back the old file you committed
Though the files can be staged/unstaged it's still not under version control until we commit the files. Only then Git will look for changes of the current version with the last saved version.
$ git commit -m "Initial commit"
$ git status // There won't be any unstaged or even staged files. All are commited now
Now if you modify a file and issue a 'git status' command. It should show that your file is modified. To include it for next commit, let's add it.
$ git add abc.doc
$ git commit -m "Second commit with changes"
$ git log    // Provides history of the repository. The ouput will be as follows.
commit ca8da1d78daa8453dd478da7610e3c375ae917db
Author: Shazni Nazeer <mshazninazeer gmail.com="">
Date:   Tue Dec 3 12:37:24 2013 +0530

    More changes to Refactor doc

commit 93c1e9296a901bee38806e216d72abd74509a18f
Author: Shazni Nazeer <mshazninazeer gmail.com="">
Date:   Tue Dec 3 12:30:05 2013 +0530

    Initial commit
We need the commit id (the 40 character id in front of the commit word). If we need to checkout the files at the first commit.
$ git checkout 93c1e    // Note only the first 5 character is enough to checkout. 
Now when you checkout, the directory would contain the file before you modified. If you want to checkout a previous commit with latest intact, we need to do branching. Will come back to that shortly. But let's get our latest.
$ git checkout master

Previous HEAD position was 93c1e92... Initial commit
Switched to branch 'master'
If you want to permanently move back to the previous state and throw away the latest changes, you can issue the following command. This will revert all the commits you have done after this commit.
$ git reset --hard 93c1e   // What happens is that you have changed the master branch to previous commit
Moving files in git

If you need to rename or mv a file in git we perform the following.
$ git mv abc.doc xyz.doc
$ git commit -m "Renaming abc.doc to xyz.doc"
Now say we have a directory called docs in the repository.
$ git mv xyz.doc docs/
$ git commit -m "Moving xyz.doc to abc.doc"
If a file completely be removed from the repository, you issue the following command.
$ git rm -- abc.doc
$ git rm -r -- docs/
$ git commit -m "Removing abc.doc and the docs directory from git"
Say you issued a git rm command, but didn't commit yet. You need the removed file or directory; as previously mentioned
$ git reset HEAD -- abc.doc docs/