Skip to main content
Version: 1.1.0

Introduction to Merge Modes

After reviewers have reviewed the code changes submitted by developers, they can decide whether to merge these commits into the main branch master.

However, there are multiple merge modes for merging commits between different branches. The image below shows the merge modes supported by GitLink, including Merge Pull Request, Rebase and Merge, Rebase and Merge --no-ff, and Squash and Merge.

Merge Modes

  1. Merge Pull Request

Merge Pull Request is the most commonly used merge mode. Taking the following diagram as an example, the developer created a development branch dev from commit 3 of the main branch master, then made commits A, B, and C, and then merged back to the master branch.

Before fast-forward merge:

Before Fast-forward Merge

After fast-forward merge:

After Fast-forward Merge

Note: As you can see, the merge process simply moves the master pointer to where the dev pointer is. This type of merge is called fast-forward. This occurs because after commit 3, there were no new commits on the master branch, so the merge can be completed by simply fast-forwarding the master pointer. However, if there are new commits on the master branch, a substantive merge will be needed, as shown in the following two images:

Before merging, commit 4 was made on the master branch after commit A but before commit B on the dev branch. In this case, merging the dev branch cannot be done by simple fast-forward movement; instead, the changes on both branches need to be compared and merged.

Before non-fast-forward merge:

Before Non-fast-forward Merge

After merging, commits A, B, and C will be added to master's commit history according to the timeline, and a new commit D will be generated to record the merge event. Additionally, if conflicts occur during the merge (i.e., both branches modified the same file), they need to be resolved manually. This merge method is called non-fast-forward, and it's the default method in Merge Pull Request mode!

After non-fast-forward merge:

After Non-fast-forward Merge

For better understanding, you can view the commit history on the master branch linearly:

Linear Commit History

Summary: In Merge Pull Request mode, non-fast-forward merge is used by default to merge development branches into the master branch, and the non-fast-forward method generates a special commit to record this merge event!

  1. Rebase and Merge

From the commit history on the master branch after Merge Pull Request, we can see that the commit histories of the two branches might interweave, which could cause confusion in subsequent development. Rebase and Merge can solve this problem.

Rebase and Merge includes two operations: rebase and merge. First is rebase: taking the diagram below as an example, the dev branch was created from commit 3, so commit 3 is the base of dev. The rebase operation changes the base of dev to the latest commit on the master branch. Of course, conflicts may occur during rebasing and need to be resolved manually.

Before rebase:

Before Rebase

After rebase, before merge:

After Rebase, Before Merge

After the dev branch is rebased, there are no "newer" commits on the master branch, so performing a merge at this point gives us the following result:

After merge:

After Merge

Summary: In Rebase and Merge mode, the development branch dev can first perform a rebase operation, making its commits appear as if they were made based on the latest commit of the master branch, then merge back to the master branch using fast-forward, thus organizing the commit history!

  1. Rebase and Merge --no-ff

Because Rebase and Merge uses fast-forward mode by default when merging, there won't be a special commit on the master branch to record this merge event. Therefore, you can use the --no-ff (no fast-forward) option to specify using non-fast-forward mode for merging.

Before --no-ff merge:

Before --no-ff Merge

After --no-ff merge:

After --no-ff Merge

Summary: Using the --no-ff option explicitly declares using non-fast-forward mode when merging, which adds a commit to record the merge event in the master branch!

  1. Squash and Merge

In development branches like dev or feature, developers might make multiple commits to complete a requirement. However, these granular commit messages can make the commit history on master cluttered and confusing after merging. Therefore, these commits need to be squashed before merging. As shown in the image, the squash operation is performed on the master branch. Essentially, it applies the changes made on the dev branch to the files maintained by the master branch, then saves these modifications with a new commit 5, and finally commits.

Before squash:

Before Squash

After squash, before commit:

After Squash, Before Commit

After commit:

After Commit

Summary: Squashing the granular commits on the development branch before merging can make the commit history on the master branch more concise. However, note that this merge mode essentially saves the changes from dev to master in one go and creates a new commit to record these changes, so the committer changes!