loading...
Cover image for Git and GitHub: Merge

Git and GitHub: Merge

lofiandcode profile image Joseph Trettevik ・6 min read

Song of the Week

Introduction

Last week I briefly covered git merge as part of a general overview of common git commands. This week I wanted to go into more depth on merge since it can be a little tricky. Hopefully I can help you avoid some of the confusion I've experienced in the past.

Topics Covered:

  • Preparing for the Merge
  • Fast-Forward
  • 3-way Merge
  • Merge Conflicts
  • Deleting Branches

Preparing for the Merge

Before you execute a merge it's important to take a few steps to prepare.

  • Step 1: Make sure your on the branch you want to merge into. If you're not sure which branch you're on, run git status. If you're on the wrong branch, run git checkout <branch-name> to switch to the correct branch.
  • Step 2: Make sure the branches you're merging are up-to-date with the latest remote commits. To do this, run git pull once you're on the branch you want to update. This is especially important if you're merging into a branch that you share with other developers.

Fast-Forward

There are two types of merges that Git will execute depending on the situation. The simplest is called “fast-forward.” A fast-forward is when Git just moves the tip of the receiving branch to point to the same commit as the tip of the merging branch. This happens when the tip of the branch you're merging into is a direct ancestor of the branch you're merging in. Let’s look at an example!

Alt Text
Diagram 1: Commit history before the fast-forward.

Let’s say we’re working with a simply git history like the one in the diagram above. In this example you have a master branch, and a feature branch that branched off at commit #3. We can see that even thought we’ve made two commits on our feature branch, no new commits have been made to the master branch. This means that the tip of the master branch is a direct ancestor of our feature branch. So, when we run git merge feature, the commit history will look like this:

Alt Text
Diagram 2: Commit history after the fast-forward.

Notice that the tip of the master branch now points to the same commit as the feature branch. The fast-forward just moved the tip of the master branch up the linear commit history to point to the most recent commit.

3-way Merge

Often the commit history is not simple enough for Git to do a fast-forward. This is especially true when you are work on the same code base with multiple developers.

This is where the 3-way merge comes into play. Git performs a 3-way merge when the tip of the branch you’re merging into is not a direct ancestor of the branch you’re merging in. A 3-way merge is when Git creates a new snapshot of the code using the commits that the two branch tips point to and the common ancestor commit, and then creates a merge commit with the result. Again let’s look at an example to better understand what’s happening.

Alt Text
Diagram 3: Commit history before the 3-way merge.

In this example, the feature branch also branches off at commit #3, but this time the master branch tip is not pointing to a commit that is a direct ancestor of the feature branch. This can happen if you or someone else merged a commit into master after your feature branch was created.

To merge these branches we should have already switched to the master branch in the prepare step, so we can just run git merge feature. Notice that is the same Git command, but this time a 3-way merge will result. Git will automatically perform a fast-forward or a 3-way merge depending on the state of the commit history.

After the 3-way merge the commit history will look like this:

Alt Text
Diagram 4: Commit history after the 3-way merge.

Take note of the fact that unlike a fast-forward, the master and feature branch tips do not point to the same commit after a 3-way merge. Master is now pointing to a merge commit that is a combination of the two branch tips and the common ancestor.

One last thing that should be said if it wasn’t clear. Merges don’t always have to go from a feature branch into the master branch. You can merge any branch into another other branch. So you could merge master into your feature branch, or feature_1 branch into feature_2. branch.

Merge Conflicts

Usually Git will automatically merge the files from both branches together. However, if the same part of a file has been changed in different ways on the two branches being merged, Git won't be able to merge them. In this case, Git will label the trouble spot as a conflict and will wait for you to resolve it. To see which files have conflicts you can run git status. Then open those files in VS Code or whichever text editor you prefer. In the files you will see something like this:

<<<<<<<<HEAD:app.js
if (a < 0) {
  b = 5;
}
==============
if (a < 0) {
  c = 5;
}
>>>>>>>>feature:app.js

Above I created a hypothetical conflict that may have come up in the 3-way merge example we looked at before. The less than signs (<<<<<<<<) mean that everything between them and the equal signs (=========) is the code from the current branch (aka the branch you're merging into). On the bottom, the greater than signs (>>>>>>>>) mean that the code between them and the equal signs (========) is from the branch that you're merging in.

Once you decide which version to keep, or create a mix of the two, save the file. Once all the conflicts are resolved and saved, run git add <file-name> on each file with a conflict. Or you can run git add ., which will git add all the modified files at once. Then just run git commit -m <type a message here> with your commit message and your merge is done.

Deleting Branches

Now that your feature branch is merged into master you can delete it since it's changes have been incorporated into master. To delete a branch run git branch -d <branch-name>.

So in the case of our examples, after the merge we would run git branch -d feature.

Takeaways

  • Prepare for the Merge
    • Make sure you're on the branch you want to merge into by running git status and running git checkout <branch-name> if you need to switch to the correct branch.
    • Make sure the branches you're merging are up-to-date with the latest remote commits. To do this, run git pull.
  • Two Types of Merges can result from git merge <branch-name>
    • Fast-Forward: When Git just moves the tip of the receiving branch forward to point to the tip of the merging branch. This happens when the the tip of receiving branch is a direct ancestor of the merging branch.
    • 3-way Merge: When the tip of the receiving branch is not a direct ancestor of the merging branch Git creates a new snapshot of the code using the commits that the two branch tips point to, and the common ancestor commit, and then creates a merge commit with the result.
  • Merge Conflicts
    • If the same part of a file has been changed in different ways on the two branches being merged, Git won't be able to merge them and will label them as a conflict.
    • <<<<<<<<: Everything between these less than signs and the equal signs (=========) is the code from the current branch (aka the branch you're merging into)
    • =========: Separates the code from the receiving and the merging branches that is in conflict.
    • >>>>>>>>: Everything between these greater than signs and the equal signs (========) is the code from the branch that you're merging in.
    • Once the conflicts are resolved in a text editor, run git add . and git commit -m <type a message here>.
  • Delete Branch
    • To delete a branch run git branch -d <branch-name>.

References

Basic Branching and Merging - Git Docs
Git Merge - Git Docs
Git Merge - Atlassian Git Tutorial
Git Pull - Atlassian Git Tutorial
Git Branch - Git Docs

Posted on Jun 14 by:

lofiandcode profile

Joseph Trettevik

@lofiandcode

Full Stack Software Engineer who loves puzzles. Experience in React, JavaScript, and Ruby on Rails, and strong skills in problem solving and writing algorithms.

Discussion

markdown guide