Sunday, 27 December 2015

Git - Working with Branches

A Branch in git is an independent line of development. They are used for a developing a new feature or for doing some experiment. If the feature is developed or the experiment comes out green, then the branch is merged with master (default branch). If experiment fails then the branch can be deleted without impacting the primary line of development.

Use branches often because -
  • They are cheap.
  • They do not take processor power.
  • They do not consume storage space.
  • They are easy to create, delete and work with.
  • They allow you to try new ideas.
  • Switching between branches is very fast.

When you create a branch, a pointer is created which points to the commit from where the branch is created. HEAD always points to the tip of the branch (unless you make it point to some other commit). 

Branch Basics

View Branches
To view list of branches,
$ git branch
  add_content
* master
  seo_title

asterisk(*) tells the current branch you are on.

To view corresponding pointer files,
$ ls -l .git/refs/heads/
total 3
-rw-r--r-- 1 USER 197121 41 Dec 27 17:20 add_content
-rw-r--r-- 1 USER 197121 41 Dec 27 17:24 master
-rw-r--r-- 1 USER 197121 41 Dec 27 17:19 seo_title

If you view content of any of these files, they will point to a commit.
$ cat .git/refs/heads/master
f80d0b2367f10062e07321ff11fb85266d1ebc59

$ git log --oneline -1
f80d0b2 Merge branch 'add_content'

Create/Checkout a Branch
To create a branch,
$ git branch insert_place

You can see that  a pointer file is created,
$ ls -l .git/refs/heads/
total 4
-rw-r--r-- 1 USER 197121 41 Dec 27 17:20 add_content
-rw-r--r-- 1 USER 197121 41 Dec 27 17:40 insert_place
-rw-r--r-- 1 USER 197121 41 Dec 27 17:24 master
-rw-r--r-- 1 USER 197121 41 Dec 27 17:19 seo_title

It has not still switched the branch. You can do this by,
$ git checkout insert_place
Switched to branch 'insert_place'

The two steps of creating and switching branch can be done by using a single command as,
$ git checkout -b insert_place

Also note that working directory should be clean or you should stash your changes before switching branch otherwise git will abort the switching operation.

Rename a Branch
To rename a branch,
$ git branch --move insert_place insert_tourist_places

$ git branch
  add_content
* insert_tourist_places
  master
  seo_title

Delete a Branch
You can not chop the branch you are on. Hence first you have to switch to a different branch before deleting the branch you are on. To delete a branch you can use -d or -D (force delete) flag. 

$ git branch -d <branch_name>

Git will not allow to delete a branch having commits not merged with any other branch. Still if you wish to delete then use -D.

Comparing Branches
To compare changes on two branches,
$ git diff master..insert_tourist_places
diff --git a/home.html b/home.html
index f417b9e..28c2713 100644
--- a/home.html
+++ b/home.html
@@ -2,5 +2,9 @@
        <body>
                India is the best place for tourists on earth.
                People from Mars also visit here frequently.
+               <ul>
+                       <li>India Gate</li>
+                       <li>Red Fort</li>
+               </ul>
        </body>
 </html>

To view all other branches from where the commits have already been merged, 
$ git branch --merged
  add_content
* master
  seo_title

Note that it is not showing insert_tourist_places branch as it is having extra commits which are not on master branch.

Merging Branches & Resolving Conflicts (if any)

Once a feature development completes or an experiment turns out successful, you would like to merge the changes to the master branch. First you need to checkout master branch & then execute

$ git merge <feature_branch>

There are two types of merges that can happen. (Click Here for Details)
  1. Fast Forward Merge
  2. 3-Way Merge
Fast-Forward Merge
This happens when the HEAD pointer of master branch can be taken to the tip of feature_branch in a linear fashion. Following digram illustrates this.


This will not make any new commits in the history & in future you won't be able to identify that a feature branch has been merged. To stop fast forward and make it a verbose commit, even if fast forward is possible,

$ git merge --no-ff <feature_branch>

To tell git do the merge only if you can do it in fast forward fashion,

$ git merge --ff-only <feature_branch>

3-Way Merge
This happens when a fast-forward is not possible. When a 3-way merge occurs, an explicit commit is made which merges the 2 commits of merging branches. Following diagram illustrates 3-way merge.



Resolving Conflicts

Conflict occurs when there are two different version of changes on same lines or on same set of lines. If changes are on different lines then git will merge both the changes and create one composite document.

There are three approaches to resolve merge conflict.

  1. Abort Merge $ git merge --abort
  2. Resolve manually
  3. User a merge tool

The best way to avoid conflicts is merge often.
Consider the following structure of branches.

Description - I am having a master branch. From that I have created website branch. And from website I have created  seo_title, hotfix_correct_title and visiting_places branch. Now let's do merging and resolve conflicts if it occurs.

$ git log --oneline website
d821d77 Adds header to website
9bffbda Adds home page
9f76373 Adds Index file
3a86518 Initial Checkin

Merging hotfix_correct_title to website -
This is going to be a fast forward merge. But I want to have a verbose commit, therefore

$ git merge --no-ff hotfix_correct_title
Merge made by the 'recursive' strategy.
 header.html | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

$ git branch -d hotfix_correct_title

Merging visiting_places to website -
This will be a 3 way merge as the master branch has already moved. Following diagram illustrates the current branch state.


$ git merge visiting_places
Merge made by the 'recursive' strategy.
 home.html | 5 +++++
 1 file changed, 5 insertions(+)

$ git branch -d visiting_places

And the branch structure is as follows.

Merging seo_title to website -
This merge will create conflict because header.html file has already been changed at the time of hotfix and merged with master.

$ git merge seo_title
Auto-merging header.html
CONFLICT (content): Merge conflict in header.html
Automatic merge failed; fix conflicts and then commit the result.

Now you are not really on website branch; rather you are on - (website|MERGING)

$  git status
On branch website
You have unmerged paths.
  (fix conflicts and run "git commit")

Unmerged paths:
  (use "git add <file>..." to mark resolution)

        both modified:   header.html

Here if there are many conflicts or you are not sure how to resolve,
$ git merge --abort

But if you want to continue then you have to resolve the conflict manually, add and commit it. 

When you open header.html it will be as follows.

<html>
        <body>
<<<<<<< HEAD
                <h1>Incredible India - Heaven on Mars</h1>
                India offers a different aspect of her personality – exotic, extravagant, elegant, eclectic -- to each traveller to the country.
=======
                <h1>India - Heaven on planet Earth</h1>
>>>>>>> seo_title
        </body>
</html>

It is showing the changes in current branch from <<< HEAD to === and changes in seo_title branch from === to >>> seo_title.

Ok so I see that I have changed Mars to Earth. This change I wish to retain from seo_title. Other changes are good on website branch. Manually do the changes to look your file as follows.

<html>
        <body>
                <h1>Incredible India - Heaven on Earth</h1>
                India offers a different aspect of her personality – exotic, extravagant, elegant, eclectic -- to each traveller to the country.
        </body>
</html>

Save & quit. Then

$ git add header.html

$ git commit
[website 4b0deff] Merge branch 'seo_title' into website

$ git branch -d seo_title
Deleted branch seo_title (was 185c63d)


OR you can view the same branch structure via command line.

If I merge website with master now, it will be a fast forward merge.
$ git merge website
Updating 3a86518..4b0deff
Fast-forward
 header.html |  6 ++++++
 home.html   | 14 ++++++++++++++
 index.html  |  6 ++++++
 3 files changed, 26 insertions(+)
 create mode 100644 header.html
 create mode 100644 home.html
 create mode 100644 index.html

No comments:

Post a Comment

Your comments are very much valuable for us. Thanks for giving your precious time.