Git merge, merge-squash and rebase simplified
Tags: git
Published: 2019-08-09 10:17:46

# Git merge, merge-squash and rebase simplified

## Starting the repository with basic files

Lets create an empty repository and commit a file to the master branch:

~~~sh
$ git init 
$ touch m1
$ git add m1
$ git commit -m "m1"
~~~

Now we switch to a new branch named feature:

~~~sh
$ git checkout -b feature
~~~

Is time to create a file in the feature branch and commit it:

~~~sh
$ touch f1 
$ git add f1 
$ git commit -m "f1"
~~~

Now let's go back to the master and create another file :

~~~sh
$ git checkout master
$ touch m2 
$ git add m2
$ git commit -m "m2"
~~~

If we type `$ git log` we will see this : 

~~~
* 60c3a2b - (1 second ago) m2 - Hector (HEAD -> master)
| * 7832858 - (87 seconds ago) f1 - Hector (feature)
|/  
* 0a950f5 - (5 minutes ago) m1 - Hector
~~~

## Integrating changes from master to feature branch

Up to now we have one simple feature branch with a commit and two commits in the master branch, it is a common practice to integrate the commits from the master branch to our feature in order to avoid losing track of master changes, but there are a few ways to do it : 

* **Git merge**

~~~sh
$ git checkout feature 
$ git merge master
~~~

This is a non-destructive way, branches keep preserved its history and only a merge commit appears :

~~~
*   fad9250 - (11 seconds ago) Merge branch 'master' into feature - Hector (HEAD -> feature)
|\  
| * 60c3a2b - (5 minutes ago) m2 - Hector (master)
* | 7832858 - (7 minutes ago) f1 - Hector
|/  
* 0a950f5 - (11 minutes ago) m1 - Hector
~~~

* **Git merge --squash**

~~~sh
$ git checkout feature 
$ git merge --squash master
$ git commit -m "Squash"
~~~

This is a non-destructive way as well, branches keep preserved its history but now no merge commit appears, all the changes in master are grouped into 1 commit named Squash in my case and appears as as a single commit in the feature branch, as you can see : 

~~~
* dc4e5b7 - (10 seconds ago) Squash - Hector (HEAD -> feature)
* 7832858 - (19 minutes ago) f1 - Hector
| * 60c3a2b - (18 minutes ago) m2 - Hector (master)
|/  
* 0a950f5 - (23 minutes ago) m1 - Hector
~~~

* **Git rebase**

~~~sh
$ git checkout feature 
$ git rebase master
~~~

With rebase instead, the history will be simpler, what it does in high-level words is to search for the last common commit and add master commits upon it but below our branch commits.

As you can see m2 commit is **upon** m1 (last common commit in both branches) and **below** f1 (our feature branch commit)

~~~
* 6074794 - (11 minutes ago) f1 - Hector (HEAD -> feature)
* 60c3a2b - (10 minutes ago) m2 - Hector (master)
* 0a950f5 - (15 minutes ago) m1 - Hector
~~~

## Integrating changes from feature branch to master 

Let's suppose we integrate master changes to feature branch with merge and we add some few changes to both branches, m3 and f2 resulting to this log :

~~~
* 83c98e1 - (1 second ago) m3 - Hector (HEAD -> master)
| * 0a3663c - (2 minutes ago) f2 - Hector (feature)
| *   edfda02 - (2 minutes ago) Merge branch 'master' into feature - Hector
| |\  
| |/  
|/|   
* | 60c3a2b - (29 minutes ago) m2 - Hector
| * 490a167 - (3 minutes ago) f1 - Hector
|/  
* 0a950f5 - (35 minutes ago) m1 - Hector
~~~

As before, we have the same 3 options :

* **Git merge**

If we do a `$ git merge feature` it will result as it follows :

~~~
*   d6b643b - (4 seconds ago) Merge branch 'feature' - Hector (HEAD -> master)
|\  
| * 0a3663c - (4 minutes ago) f2 - Hector (feature)
| *   edfda02 - (4 minutes ago) Merge branch 'master' into feature - Hector
| |\  
| * | 490a167 - (4 minutes ago) f1 - Hector
* | | 83c98e1 - (2 minutes ago) m3 - Hector
| |/  
|/|   
* | 60c3a2b - (31 minutes ago) m2 - Hector
|/  
* 0a950f5 - (36 minutes ago) m1 - Hector
~~~

* **Git merge --squash**

If we do a squash :

~~~sh
$ git merge --squash feature
$ git commit -m "Squash"
~~~

With the behaviour expected, not a merge commit and non-destructive history we get :

~~~
* 63f7387 - (10 seconds ago) Squash - Hector (HEAD -> master)
* 83c98e1 - (3 minutes ago) m3 - Hector
| * 0a3663c - (5 minutes ago) f2 - Hector (feature)
| *   edfda02 - (5 minutes ago) Merge branch 'master' into feature - Hector
| |\  
| |/  
|/|   
* | 60c3a2b - (32 minutes ago) m2 - Hector
| * 490a167 - (5 minutes ago) f1 - Hector
|/  
* 0a950f5 - (37 minutes ago) m1 - Hector
~~~

* **Git rebase**

Finally, let's test what would happen with `$ git rebase feature` we obtain the following log :

~~~
* 6c6ba0e - (5 minutes ago) m3 - Hector (HEAD -> master)
* 0a3663c - (7 minutes ago) f2 - Hector (feature)
*   edfda02 - (7 minutes ago) Merge branch 'master' into feature - Hector
|\  
| * 60c3a2b - (35 minutes ago) m2 - Hector
* | 490a167 - (8 minutes ago) f1 - Hector
|/  
* 0a950f5 - (40 minutes ago) m1 - Hector
~~~

Rebase takes the last common commit, which is the merge commit and add places the f2 commit upon it, but below the m3 commit from master.