Merging Changes

Merging

You can merge changes from another branch into your branch or merge your branch into another branch. You can even merge just a few files or changes to files. The branch you merge changes into is called the target branch.

Merging doesn’t necessarily end a branch, but a merge is usually your last action before closing and deleting a branch.

Before you make any merges, you need a clean working directory. A working directory is considered clean if git status shows no “Changes not staged for commit” or “Changes to be committed”. You can force a merge without a clean working directory, but Git might corrupt your files.

git merge <the_other_branch>

This is the simplest form of the command; it applies the changes from the other branch into this branch and commit. Even in this simple form, there are two types of merges: fast-forward merges and true merges.

Fast-Forward Merge

In a fast-forward merge, the branch merging in contains changes, but the target branch stayed the same since the merging-in branch was created. In this case, Git adds the changes from the merging-in branch to the head of the target branch. That’s a little confusing but is easier to explain with a diagram:

Work branch Main branch A B C D
A main and work branch with commits only on the branch. This merge will be a fast-forward merge.

Here, the branch “work branch” is made from the tip of the “main” branch in spot “A”. Commits named “B”, “C”, and “D” are made on the work branch. But no changes get made to the “main” branch between the time the work branch is created and when it’s time to merge it back in.

Main Work branch A B C D
Diagram showing the Git history after a fast-forward merge. The work branch history is fully integrated into the main branch history, as if it never existed.

Because there were no changes to the main branch, Git puts the work branch on the end of the main branch and fast forwards the main branch’s head. After the merge, you can still switch to the work branch or the main one, but they’re the same, pointing to the same commit. Additionally, all the commits made on the work branch will become part of the history of the main one.

True Merge

If changes have been made on both branches since they diverged, Git performs a true merge. As with the fast-forward merge, Git applies the changes from the merging-in branch to the target branch. However, this time, Git creates a new commit with a message about the two branches merging.

E Work branch Main branch A B C D
Diagram of a main branch and work branch, each with commits.

As with the fast-forward example, the work branch diverges from the main one at point “A”. Then, commits named “B”, “C”, and “D” are made to the work branch. Also, during that time, a commit “E” is made to the main branch.

E F Work branch Main branch A B C D
Diagram showing a merge commit and that the two histories can be separately navigated when needed.

After the merge, Git creates a new commit, “F”. Unlike the fast-forward merge, Git leaves the tip of the work branch on the last commit in that branch. You could git switch to the branch, and your project would be in the before-merge state.

Deleting After Merge

Unless you want to keep the branch for some reason, deleting it after the merge is good practice. The git branch command has a -d option for this.

git branch -d work-branch

Git warns you if you try to delete a branch that hasn’t been merged. If you want to delete the branch, you can force Git to do it:

git branch -D work-branch

Conflicts

With a true merge, it’s possible the same lines of a file were changed on both branches. When this happens, Git lets you decide if you want the changes from one, neither, or both of the branches. Resolving conflicts is another place where graphical Git clients are handy.

When changes have been made to different lines of the same file on two branches, Git usually can merge them. But when the same line is changed in two branches, Git won’t do the merge. Git marks the files in the working directory that have conflicts. To complete the merge, you need to resolve the conflicts and then make a commit.

For example, if you had a text file containing:

This is some text
and this is some more
and here is some more.

Next, you make a branch — work-branch — and in that branch, you change and commit the second line to read:

and this is really some more

Then, back on main, you change and commit the second line:

and this is not much more

Now, when you are on main and you git merge work-branch, Git gives you an error and modifies the text file. You’ll need to open the file and decide what to do. The conflicted file looks like this:

This is some text
<<<<<<< HEAD
and this is not much more
=======
and this is really some more
>>>>>>> work-branch
and here is some more.

You can change the file however you want. The changed text between “<<<<<<< HEAD” and “=======” is the change from main. The change between “=======” and “>>>>>>> work-branch” is the change from work-branch. You can complete the commit after you fix the conflict and save the file.

If you decide you don’t want to try to resolve the conflict, you can undo the merge with:

git merge --abort

This command is valid only when you’re in the middle of a merge, working with conflicts. If you complete the merge but then realize you want to try again, you can discard the commit that joined the two branches. When you’re on main, you can:

git reset --hard HEAD^

This command tells Git to forcefully make the parent commit and become the tip of the branch, and to throw away any commits after. Remember from the first lesson that the “^” means the parent commit.

Instead of HEAD^, you can use the hash of any commit in the history and reset to that. Beware: All the commits after the one you reset to will be lost forever.

In the next section, you’ll see a demo of merging and how a graphical client handles conflicts.

See forum comments
Download course materials from Github
Previous: Git Commands Demo Next: Merging Demo