Git Merge Strategies
When the work is complete and ready to be merged into the main line of the development, we should choose our merge strategy.
Git combines two commit pointers into one common base commit between them. Git finds that common base in different ways called “merge strategies". After selecting a merge strategy, Git creates a new merge commit combining the changes of the specified merge commits. If not specified, the git merge command will automatically select a merge strategy based on the provided branches. The -s option can be attached with the name of the specified strategy. Here’s the list of merge strategies:
git merge -s recursive branch1 branch2
Git will select recursive as a default strategy when pulling or merging branches. The recursive strategy can detect and manage merges that involve renames, but it cannot use detected copies.
git merge -s resolve branch1 branch2
The resolve strategy uses a 3-way merge for resolving branches and can resolve only two HEADs using a 3-way merge algorithm. It is safe and fast and detects criss-cross merge ambiguities in detail.
git merge -s octopus branch1 branch2 branch3 branchN
When two or more branches are passed, the octopus strategy is engaged, by default. Octopus refuses if the merge has conflicts that need manual resolution. The basic use of Octopus is to bundle feature branch HEADs that have similarities.
git merge -s ours branch1 branch2 branchN
Our strategy resolves multiple branches, but the result is always that of the current branch HEAD. It ignores all changes from all other branches very effectively. It is intended to be used to replace an old history of side branches.
git merge -s subtree branchA branchB
The subtree strategy is the modified version of the recursive strategy. For example, we merge A and B trees. When corresponding to a subtree of A, B is first modified to reflect the tree structure of A. The modification can be done to the shared ancestor tree of A and B.
Types of git merge strategies
Explicit merges are considered as the default merge type. It is called explicit because it creates a new merge commit changing the history and displaying where the merge was invoked. The merge commit content is also considered as explicit as it displays the parent commits of the merge commit.
Implicit merge via rebase or fast-forward merge
The implicit merges do not create a merge commit. They just take a number of commits from the specified branch HEAD and put them to the top of the target branch. They are triggered by rebase events or fast forward merges.
Squash on merge without explicit merge
Squash is another type of implicit merge. A squash merge takes the commits from the target branch and squashes them into one commit which then is applied to the HEAD of the merge base branch. Squash can be executed during an interactive rebase. The commit history of the target branches becomes a squashed branch commit when squashed and merged.
Recursive git merge strategy options
|ours||Forces conflicted parts to be auto-resolved by favoring 'our' version. The changes from the other tree not conflicting with our side are reflected to the merge output.|
|theirs||Favors the other merging tree in conflict resolution. There is no "theirs" merge strategy unlike "ours".|
|patience||Spends much time to avoid mis-merges that occur because of unimportant matching lines.|
|diff-algorithim||Instructs "merge-recursive" to use a different diff algorithm that helps to avoid mis-merges on unimportant matching lines.|
| ignore-* ||Targets whitespace characters. Whitespace changes mixed with other changes are not ignored.|
|renormalize||Runs a check-out and check-in on all of the file stages when resolving a 3-way merge.|
|no-normalize||Disables the renormalize option.|
|no-renames||Ignores renamed files during merge.|
|find-renames=n||Turns on the rename detection passing a similarity threshold. The n value is 100%.|
|subtree||Works on the path metadata of the tree to make the trees match.|