Git- Branching II

In the previous article, we saw what branches are and how they justify all the hype around them.Having seen them theoretically, Here let us look at a more practical view of branching in git.

Moving around

After branch creation , we can shift branches easily. This is one of the greatest advantages of git. Since branches are only references to commits, it is very less time consuming to change branches when comparing with the other version control systems. The command which is used to acheive that is git checkout

Git Checkout

Git checkout is a command which is used to jump/move to references ( commits , branches , tags ). Since branch is a symbolic reference to a commit , git checkout essentially performs only one task , To shift to a commit.

Git$ gl
* ee978d1 (HEAD, masterv2) commit to a tag
| * 807cee1 (master) commit10
|/
* 90b68fc (tag: version_master) added thank
| * 9060af7 (new_branch) added abc
| * 82c5aa6 added xyz
| * 5088a37 commit8
| * 2337e97 commit7
| * cb435f4 commit6
| * cf2aca1 commit5
| | * 1d61006 (new_2) stashed commits
| |/
|/|
* | 871d5ee commit9
|/
* 2b9e414 (tag: grand_parent) Adding gitignore
* dab6699 Adding change2
* f8a10f7 Adding change1
* 00a5cfe Initial commit

Git$ git checkout master
Previous HEAD position was ee978d1... commit to a tag
Switched to branch 'master'
Git$ gl
* ee978d1 (masterv2) commit to a tag
| * 807cee1 (HEAD -> master) commit10
|/
* 90b68fc (tag: version_master) added thank
| * 9060af7 (new_branch) added abc
| * 82c5aa6 added xyz
| * 5088a37 commit8
| * 2337e97 commit7
| * cb435f4 commit6
| * cf2aca1 commit5
| | * 1d61006 (new_2) stashed commits
| |/
|/|
* | 871d5ee commit9
|/
* 2b9e414 (tag: grand_parent) Adding gitignore
* dab6699 Adding change2
* f8a10f7 Adding change1
* 00a5cfe Initial commit


Git$ git checkout cf2aca1
warning: unable to rmdir new_repo: Directory not empty
Note: checking out 'cf2aca1'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

git checkout -b

HEAD is now at cf2aca1... commit5


Git$ gl
* ee978d1 (masterv2) commit to a tag
| * 807cee1 (master) commit10
|/
* 90b68fc (tag: version_master) added thank
| * 9060af7 (new_branch) added abc
| * 82c5aa6 added xyz
| * 5088a37 commit8
| * 2337e97 commit7
| * cb435f4 commit6
| * cf2aca1 (HEAD) commit5
| | * 1d61006 (new_2) stashed commits
| |/
|/|
* | 871d5ee commit9
|/
* 2b9e414 (tag: grand_parent) Adding gitignore
* dab6699 Adding change2
* f8a10f7 Adding change1
* 00a5cfe Initial commit


Git$ git checkout grand_parent
Previous HEAD position was cf2aca1... commit5
HEAD is now at 2b9e414... Adding gitignore


Git$ gl
* ee978d1 (masterv2) commit to a tag
| * 807cee1 (master) commit10
|/
* 90b68fc (tag: version_master) added thank
| * 9060af7 (new_branch) added abc
| * 82c5aa6 added xyz
| * 5088a37 commit8
| * 2337e97 commit7
| * cb435f4 commit6
| * cf2aca1 commit5
| | * 1d61006 (new_2) stashed commits
| |/
|/|
* | 871d5ee commit9
|/
* 2b9e414 (HEAD, tag: grand_parent) Adding gitignore
* dab6699 Adding change2
* f8a10f7 Adding change1
* 00a5cfe Initial commit

In the above example, we saw ‘HEAD‘ move around to different commits , when i used a branch , commit or even a tag name.

Isolation

The biggest advantage of branches is that they provide isolation from other branches. Whatever change that is being made to a particular branch doesnt affect any other branches.

Consider a branch ‘master‘ which has the latest stable contents of the repository . So if a bug arises, to solve the bug, usually the master contents are branched into a seperate branch called ‘bugfix‘. After enough testing of the bugfix branch, it can be included ( merged ) with the parent branch. Until then master will remain untainted with untested code.

Merging

After the bugfix has been tested. It is necessary to bring the changes into the stable ‘master’ branch. The process of incorporating commits from another branch is called merging.

Inorder to acheive this , there is a command called `git merge`.

In this case , 

git checkout master && git merge bugfix

does exactly this.

Git tries its best to keep the tree as clean as possible . It tries to avoid unnecessary commits while merging. So it traces back commits to see if a merge can be acheived without the use of a commit. The process is called ‘fast-forward merge‘. We will see about this later.

If the histories of the branches to be merged are in the same timeline, then git just shifts the merged-branch pointer to the mergable branch.

For example,

Git$ gl
* 721d20f (HEAD -> masterv3) commit12
* 5c29aed commit11
* cfae35a (masterv2) Merge branch 'new_2' into masterv2
|\
| * 1d61006 (new_2) stashed commits
* | ee978d1 commit to a tag
| | * 807cee1 (master) commit10
| |/
|/|
* | 90b68fc (tag: version_master) added thank
|/
* 871d5ee commit9
| * 9060af7 (new_branch) added abc
| * 82c5aa6 added xyz
| * 5088a37 commit8
| * 2337e97 commit7
| * cb435f4 commit6
| * cf2aca1 commit5
|/
* 2b9e414 (tag: grand_parent) Adding gitignore
* dab6699 Adding change2
* f8a10f7 Adding change1
* 00a5cfe Initial commit


Git$ git checkout masterv2
warning: unable to rmdir new_repo: Directory not empty
Switched to branch 'masterv2'


Git$ git merge masterv3
Updating cfae35a..721d20f
Fast-forward
file2 | 0
file3 | 0
new_repo | 1 +
x11 | 0
x12 | 0
5 files changed, 1 insertion(+)
create mode 100644 file2
create mode 100644 file3
create mode 160000 new_repo
create mode 100644 x11
create mode 100644 x12


Git$ gl
* 721d20f (HEAD -> masterv2, masterv3) commit12
* 5c29aed commit11
* cfae35a Merge branch 'new_2' into masterv2
|\
| * 1d61006 (new_2) stashed commits
* | ee978d1 commit to a tag
| | * 807cee1 (master) commit10
| |/
|/|
* | 90b68fc (tag: version_master) added thank
|/
* 871d5ee commit9
| * 9060af7 (new_branch) added abc
| * 82c5aa6 added xyz
| * 5088a37 commit8
| * 2337e97 commit7
| * cb435f4 commit6
| * cf2aca1 commit5
|/
* 2b9e414 (tag: grand_parent) Adding gitignore
* dab6699 Adding change2
* f8a10f7 Adding change1
* 00a5cfe Initial commit

Here we can see that , when trying to merge masterv2 with masterv3 ( i.e. when integrating commits from masterv3 into masterv2 ) , git just shifts the masterv2 pointer to the newest commit instead of using a merge commit. During merge, git mentions that it is doing a fast forward merge. Here the histories of the 2 branches have not diverged.

Here is another example, where the histories are diverged when the merge is attempted..

Git$ gl
* 721d20f (HEAD -> masterv2, masterv3) commit12
* 5c29aed commit11
* cfae35a Merge branch 'new_2' into masterv2
|\
| * 1d61006 (new_2) stashed commits
* | ee978d1 commit to a tag
| | * 807cee1 (master) commit10
| |/
|/|
* | 90b68fc (tag: version_master) added thank
|/
* 871d5ee commit9
| * 9060af7 (new_branch) added abc
| * 82c5aa6 added xyz
| * 5088a37 commit8
| * 2337e97 commit7
| * cb435f4 commit6
| * cf2aca1 commit5
|/
* 2b9e414 (tag: grand_parent) Adding gitignore
* dab6699 Adding change2
* f8a10f7 Adding change1
* 00a5cfe Initial commit


Git$ git merge new_branch masterv3
Merge made by the 'recursive' strategy.
a | 0
abc | 0
b | 0
c | 0
d | 0
xyz | 0
6 files changed, 0 insertions(+), 0 deletions(-)
create mode 100644 a
create mode 100644 abc
create mode 100644 b
create mode 100644 c
create mode 100644 d
create mode 100644 xyz


Git$ gl
* dbee184 (HEAD -> masterv2) Merge branch 'new_branch' into masterv2
|\
| * 9060af7 (new_branch) added abc
| * 82c5aa6 added xyz
| * 5088a37 commit8
| * 2337e97 commit7
| * cb435f4 commit6
| * cf2aca1 commit5
* | 721d20f (masterv3) commit12
* | 5c29aed commit11
* | cfae35a Merge branch 'new_2' into masterv2
|\ \
| * | 1d61006 (new_2) stashed commits
* | | ee978d1 commit to a tag
| | | * 807cee1 (master) commit10
| |_|/
|/| |
* | | 90b68fc (tag: version_master) added thank
|/ /
* | 871d5ee commit9
|/
* 2b9e414 (tag: grand_parent) Adding gitignore
* dab6699 Adding change2
* f8a10f7 Adding change1
* 00a5cfe Initial commit

Here , we can see that new_branch and masterv2 have different histories after the commit “Added gitignore“. This is called as ‘diverged branches‘ . So when attempting to merge branches which have diverged, git includes both the histories and serves us with a new commit which can serve as the meeting point of the both the branches.

A commit is necessary because, git maintains all the histories in terms of commits . Commits only contain information related to the previous commit(s). So when there are 2 different histories, the new merge commit has both the previous commits from the diverged branches as its parent.

index
Branch structure before merge
index2
Branch structure after merge
Git$ git cat-file -p dbee184
tree 78bbeeec9220e3ebff36544d85252b34da636480
parent 721d20f4b66b78ac656ec5b537e2a63a52c62959
parent 9060af7eb68b76d47f9dccf6b2a77e9fa7e6ea0d
author harish1996  1526754679 +0530
committer harish1996  1526754679 +0530

Merge branch 'new_branch' into masterv2

As we can see, the merge commit has 2 parents. When reconstructing, git includes all the changes from both the trees. But for fast forward merge, there is still only 1 parent, because git understands that introducing a new commit for 2 branches which havent diverged as unnecessary.

Next Journey ?

In the future articles, we are going to see about ‘Rebasing : The most powerful yet destructive process’. Dont miss out !! Thank you !

3 thoughts on “Git- Branching II”

  1. Thank you for your guides about Git. I’m a beginner and i find this most helpful and much easier to understand than official book and other guides.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s