Quick Links

Key Takeaways

To merge a development branch into the current branch, use "git merge dev-branch-name". If you get conflict warnings about a merge, use "git merge --abort" to back out of it, or edit the affected files and then commit them.

Git uses branches to isolate development streams, to prevent the stable release branch from becoming polluted. Bringing work in a branch into the main stream means merging branches. Here's how you do it.

What Is a Merge in Git?

Git was designed to make branching simple and fast. In contrast to other version control systems, branching on Git is a trivial matter. On multi-developer projects especially, branching is one of Git's core organizational tools.

Branches sandbox new development efforts so that code can be modified or added without affecting the code in other branches, especially the main or master branch. This usually contains the stable version of your code base.

Isolating these changes from your stable code version makes perfect sense. But sooner or later the new code will be tested, reviewed, and rubber-stamped to be rolled into the master branch. At that point, you need to merge your branch into the master branch.

Actually, branches can have sub-branches so you might be merging your branch into some other branch instead of the master branch. Just remember that merges always take one branch and merge it into a target branch, whatever that branch may be. If you want to merge your master branch into another branch, you can even do that too.

Like most actions in Git, you perform merges in your local repository and push them to your remote repository.

Preparing to Merge a Branch in Git

We've got a small development project with a local Git repository and a remote Git repository. We created a branch called "bugfix14" from the "master" branch and worked on a solution to a bug.

That work is completed, and we've tested our code. It all works as expected. We want to roll those changes into the master branch so that our fix is part of the next release of the software.

There's a little preparation to be done before we perform the merge. We need to make sure the target branch---in this case the "master" branch---and the branch we're going to merge into it are both up to date.

To do this we'll use the

        git status
    

command.

git status

Using git status to see the state of a branch
  • On branch bugfix14: This is our current branch.
  • Your branch is up to date with 'origin/bugfix': The branch in our local repository has the same commit history as the branch in the remote repository. That means they're identical.
  • nothing to commit There are no changes in the staging area that haven't been committed.
  • working tree clean: There are no unstaged changes in the working directory.

All of those indicate that the branch is up to date, and we're clear to proceed. If any of these indicated that changes existed, we'd need to stage them, commit them, and push them to the remote. If someone else had worked on these files, we may need to pull their changes from the remote repository.

Checking out the branch we're going to merge into simplifies the merging process. It also allows us to verify it is up to date. Let's have a look at the master branch.

git checkout master

git status

Checking out the master branch and using git status to see its state

We get the same confirmations that the "master" branch is up to date.

Performing a Merge

Before we merge, our commits look like this.

The commit history before the merge of a branch

The "bugfix14" branch was branched from the "master" branch. There has been a commit to the "master" branch after the "bugfix14" branch was created. There have been a couple of commits to the "bugfix14" branch.

We've made sure our two branches are up to date, and we've checked out the "master" branch. We can issue the command to merge the "bugfix14" branch into the "master" branch.

git merge bugfix14

merging a branch with the git merge command

The merge takes place. The "bugfix14" branch still exists, but now the changes that were made in that branch have been merged into the "master" branch.

The commit history after the merge of a branch

In this instance the merge command performs a three-way merge. There are only two branches, but there are three commits involved. They are the head of either branch, and a third commit that represents the merge action itself.

To update our remote repository, we can use the git push command.

git push

Pushing changes to a remote repository

Some people prefer to delete side branches once they've merged them. Others take care to preserve them as a record of the true development history of the project.

If you want to delete the branch, you can do so using the git branch command with the -d (delete) option.

git branch -d bugfix14

Deleting a branch in the local repository

To delete the branch in the remote repository use this command:

git push origin --delete bugfix14

Deleting a branch in the remote repository

You'll have a linear commit history, but it won't be the true history.

Performing a Fast-Forward Merge in Git

If you haven't made any commits to the "master" branch, your history will look like this. It will also look this if you've rebased your development branch so that it's attached to the end of the "master" branch.

The commit history before a fast-forward merge

Because there are no commits in the "master" branch, to merge the "bugfix15" branch, all Git has to do is point the "master" head pointer to the last commit of the "bugfix15" branch.

We can use the usual git merge command:

git merge bugfix15

That gives us this result.

One way to view the result of a fast-forward merge

Which is the same as this:

One way to view the result of a fast-forward merge

Which is just the same as this:

One way to view the result of a fast-forward merge

Git will perform a fast-forward merge whenever it can. If commits to the "master" branch mean a fast-forward merge isn't possible, Git will use a three-way merge.

You can't force a fast-forward merge---it might not possible, after all---but you can declare it's going to be fast-forward merge or nothing. There is an option that instructs Git to use a fast-forward merge if it can, but not to do a three-way merge if it can't. The option is --ff-only (fast-forward merge only).

This merges the "bugfix15" branch into the "master" branch, but only if a fast-forward merge is possible.

git merge --ff-only bugfix15

Using the --ff-only option to prevent a three-way merge from being used if a fast-forward merge is not possible

Git will complain and exit if it isn't possible.

git merge --ff-only bugfix16

Git not performing any merge because a fast-forward merge is not possible and the --ff-only option has been used

In this case, there have been commits to the "master" branch, so a fast-forward merge isn't possible.

How to Resolve Merge Conflicts in Git

If the same portions of the same file have been changed in the both branches, the branches cannot be merged. Human interaction is required to resolve the conflicting edits.

Here, we've got made changes to a file called "rot.c" in a branch called called "bugfix17" that we want to merge to the "master" branch. But "rot.c" has been changed in the "master" branch too.

git merge bugfix17

Get reporting conflicts and halting a merge

When we try to merge it, we get a warning that there are conflicts. Git lists the conflicting files, and tells us the merge failed. We could back out completely using the --abort option:

git merge --abort

But resolving merges isn't as scary as it sounds. Git has done some work to help us. If we edit one of the conflicting files---in our case, we only have one---we'll find the conflicting code sections highlighted for us.

Using git status to see the state of a branch

Each conflict is bounded by seven less-than characters "<<<<<<<" and seven greater-than characters ">>>>>>>", with seven equals signs "=======" between them.

  • The code above the equals signs is from the branch you're merging into.
  • The code below the equals sign is the code from the branch you're trying to merge.

You can easily search for one of the sets of seven characters and move from conflict to conflict through your file. For each conflict, you need to choose which set of edits you're going to keep. You must edit out the code you're rejecting, and the seven-character lines that Git has added.

We're going to keep the code from the "bugfix17" branch. After editing, our file looks like this.

Using git status to see the state of a branch

We can now carry on with the merge. But note, we use the commit command to do so, not the merge command.

We commit the change by staging the file and committing it as usual. We'll check the status before we make the final commit.

git add rot.c

git status

git commit -m "Merged bugfix17"

Using git status to see the state of a branch

The merge is complete. We can now push this to our remote repository.

Everything Merges Eventually

All branches need to be merged, eventually, so that the changes in them don't become orphaned and forgotten about.

Merging branches is easy, but dealing with conflicts can get complicated in busy, larger teams. Resolving conflicts may require input from each developer just to explain what their code does and why they made their changes. You need to understand that, before you can make an informed decision about which edits to keep.

Sadly, Git can't help with that.