# The Three Types of Pull Request Merge in GitHub

When you go to merge a pull request on GitHub, you would see three choices:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1726970585142/6c4cfc29-84df-4512-bb23-926699b629ca.png align="center")

The behaviour of each of the merge methods is as follows (assuming for the sake of this post that the target branch of the pull request is `main`, i.e. you are merging into `main`):

**Merge commits** keep all of the commits in the pull request’s source branch and simply add a single new merge commit that points back both to the last commit in the source banch and to the last commit in `main`.

In the commit graph shown below, the tip of `main` is the merge commit.

The commit message of the merge commit defaults to the combined pull request and description (topmost comment in the pull request) if this is what you have selected under **Allow merge commits** in Settings:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1726938037341/f4a8cf7b-20e9-4610-bcf5-44aa571be3d4.png align="center")

**Squash merging** does not carry over source branch’s commits into `main`. Instead it squashes all changes in the source branch commits and creates a single commit from these and places it in front of the last commit in `main`.

In the commit graph below, the tip of `main` is the squash commit. As you can see, unlike a merge commit, it doesn’t point back to the branch `add-hello-world` that was merged. Instead it squashes the two commits on that branch ahead of `main` into a single commit. This becomes the new tip of `main`.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1726961169930/69cd017f-a9c2-4676-8abe-938b1855b51a.png align="center")

Again, the message of this commit is the combined pull request title and description if this is what you have selected under Pull Requests in Settings:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1726939494453/97d3a7da-5b9e-4624-8fe7-8262e86a62e8.png align="center")

**Rebase merging** rebases the source branch onto main (without altering the source branch) and places the new rebased commits in front of `main`. Hence there is one new commit on `main` for every commit in the source branch that is ahead of the original tip of `main`. The last rebased commit becomes the new tip of `main`.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1726967177618/de48001e-2869-43d7-9aff-c8320312f2a8.png align="center")

Each rebased commit retains the commit message of the original commit. Therefore the pull request title or description do not get used in any commit message and there is also no option to use them under **Allow rebase merging** in **Settings**.

## My personal preference: Squash Merge

I personally prefer the Squash merge method and disallow the other two because:

* I prefer to keep my `main` linear as it’s much easier to understand (e.g. to `git bisect`) than the sort of non-linearhistory yo uget when you have merge commits. Therefore I select option **Require Linear History** in **Branch protection rule** for `main` (see step XX above).  
    This precludes the use of merge commits: the merge commit options would not be available on a pull request if you have the require Linear History option checked in the branch protection rule for the target branch (`main` in this case).
    
* Of the remaining two available merge methods - Squash merge and Rebase merge - I prefer squashing. I like to merge smaller pull request frequently rather than attempt to merge several days or weeks of work on the feature branch into `main`. For smaller merges, I find that having a single meaningful squash commit on `main` works a lot better than having lot of tiny commits on `main` that were obtained by rebasing lots commits on feature branch onto `main`.
    

Thus with squash merging, I get a linear `main` on which individual commits are chunky and meaning rather than a `main` that is littered with lots of tiny commits.
