Git : How to merge and rebase branch


In Git, there are two main ways to integrate changes from one branch into another: the merge and the rebase

Git Merge 

Git merge is a command used for merging one branch to another. It is used used quite extensively. It takes the contents of a source branch and integrates it with a target branch.

The following command is used to merge one branch to another branch.
git merge [Name_of_branch_You_want_to_Merge]  
Now, while we are merging, we need to remember that we must be on the branch in which we want to merge the other branch. 

For example, if you want to move "feature_A" branch to the "master" branch because you have finished your work for the feature A, then, history of commands should look like this...
  /* create a branch named featureA */

git checkout -b "featureA" 

/*edit code and commit */

git commit -m "feature added"

/*now the branch is ready to merge into master */

/*checkout branch because that's where we want to merge our branch into */
git checkout master
/*merge feature into master */
git merge featureA
Updating f42c576..3a0874c
Fast-forward
index.html | 2 ++
1 file changed, 2 insertions(+)

This simple procedure will create a fast-forward commit message since the branch commit tree is a single line. Usually in a workplace, you have a master/development branch that is constantly updating by team members, so in an ideal situation, you usually have to create a pull request. 
The tree of above ran commits can look like this


                        Master                     FeatureA   
Commit1 <--Commit2           "feature added"(commit name)

Now when you run command to merge featureA into master, Git simply moves the pointer forward. 

                                                     Master/ FeatureA   (both branch points to same commit)
Commit1 <--Commit2 <-- "feature added"(commit name)

In another words, all git has to do is attach a new commit node to the master one to create a tree of commits. Git simplifies things by moving the pointer forward because there is no divergent work to merge together -- this is called a "fast-forward" merge.

Now as I mentioned earlier, in a workplace, master branch is constantly changing, so the Git won't be able to just move one pointer to merge. In this case, it uses recursive strategy to merge.

                                                  Master/ FeatureA   (both branch points to same commit)
Commit1 <--Commit2 <-- "feature added"(commit name)
                            ^
                            |
                            |_______ issue#2 (branch name)

Now imagine, that a branch named issue#2 was created before FeatureA branch, so at that time commit2 was the Head commit of the master, so issue#2  branch was created from that commit. Currently, issue#2 branch doesn't know that there have been an update to Master branch by including featureA. 

So in this case, you can either create a pull request ( for seniors or teammembers to review your code), or merge directly. 

which can be done like this...
$ git checkout master
Switched to branch 'master'
$ git merge issue#2
Merge made by the 'recursive' strategy.
index.html |    1 +
1 file changed, 1 insertion(+)

Now, you can see it said "Merge made by the recursive strategy" it is because development history has changed from some older point. In this case, Git does a simple three-way merge, using the two snapshots pointed to by the branch tips and the common ancestor of the two. So commit tree could look like this... 

                                                  Master/ FeatureA 
Commit1 <--Commit2 <-- "feature added"(commit name) <---Commit6
                            ^                                                                        |
                            |                                                                         |
                            |_______ issue#2(commit name) <--------commit5

In real picture, this should clear a bit more.... you can visualize above format in this picture but picture is showing vertical commit tree.


If you want to know more then you can visit this Git-Merge basics.

Git Rebase

Merging creates two pointer (first and last commit) of a branch, and connects first to a common ancestor of "master" (remote) and then attaches the last commit pointer to the end of remote master to merge which requires an extra commit on top of an additional commits already existed in master, so it looks like this...

 


In this image, when you created a branch named "feature branch", you created from the "common ancestor" commit reference, while you worked on feature branch, some team member could push their code to remote master, so there were additional commit(s), so to resolve that git has to create two pointers and merge like this.

So when it comes to Git rebase, what it does is rather than connecting pointers, it essential rewrites the history of commits on top of additional commits that were updated during your feature branch work.


Let's look at an example of rebase.

First thing you need to do is to pull your code from the remote which will make sure that you have your code up-to-date with current state of the code.
 git pull
/* fetches latest code from your remote branch */

So now as you can see, your remote master, and local branch are in sync with each other. Now you need to work on your feature branch, so you can do the following...
 /* creates a branch off from local master */
git checkout -b my_cool_feature

/* some code changes "commit 1" */
git commit -m "added button for animation"

/*another commit "commit 2" */
git commit -m "added footer"
 
Now your commit history would look like this,


Now, during this time while you are developing your feature, someone in your team has already pushed some hotfix or feature that has been completed. So, your remote master branch would look like this...


Now that your feature branch is ready to push, in order to rebase, first of all you must update your local master. so you need to switch your branch from your feature branch to your local master, you can do like this
 /* switch your branch from my_cool_feature to local master */
git checkout local master

git pull
/* gets latest code from your remote, which is addition commit that were pushed during your feature development */  
so now your tree would look like this,


Now you are ready to rebase your local master since your local master and remote master are in sync with eachother. You can do the following...
 /* switch to your feature branc */
git checkout my_cool_feature

/* rebase your feature onto local master */
git rebase master 
If there's no conflicts between code, then git will rebase and your commit tree would look like this...



Important : during this let's say on a website, index.html file exists, if you have worked on your featurebranch and other developer has also worked on index.html and pushed some changes, then git will notify you of "conflicts" which you need to resolve. As a developer, you will know which code to keep and remove because at this point, git will essential recommit changes you have made on top of the updated remote master. 

The above step will make sure that there's no any conflicts between your feature code and updated remote master, so now you can rebase your master with your feature.
 /* switch to local master branch */
  git checkout master
  /* rebase feature onto master */
  git rebase my_cool_feature  
Now, your local master commit tree would look like this


Now final command is to push your local master to your remote master
 git push
/* currently on local master branch */  
now that will have this clean history of commits like this...


So here you can clearly see the distinction between merge and rebase that how rebase provides a clean linear tree of commits.

Merge vs Rebase, which is better?

Merge keeps commit history which is a record of what actually happened. It is a source of information about what actually transpired. On the other thand, commit history is the story of how your project was made. You don't need to publish mistakes and drafts that never made it to the final version of your project, which is why people choose rebase to tell the story in the way that's best for future readers/developers.

The golden rule of rebase  is that you should never use it on public branches. You must only be the author of that particular branch you want to rebase.  

Benefits of Merge :
  • Simple and familiar
  • Preserves complete history and chronological order
  • Maintains the context of the branch
Benefits of Rebase
  • steamlines a potentially clean but complex history
  • avoids merge extra commits in busy repositories with busy branches.
  • cleans intermediate commits by making them a single commit, can be helpful for devOps
The answer to the question is, depends. Both are equally useful in their own domain, as a developer, you can get the best of both worlds, rebase local changes before pushing to clean up your work, but never rebase anything that you have pushed somewhere.

 I hope this tutorial has given you a solid understanding of rebase and merge.

Post a Comment

0 Comments