Chapters

Hide chapters

Git Apprentice

First Edition · Git 2.28 · Console

Section I: Beginning Git

Section 1: 12 chapters
Show chapters Hide chapters

10. Merging
Written by Sam Davies & Chris Belanger

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

Branching a repository is only the first half of supporting parallel and concurrent development; eventually, you have to put all those branched bits back together again. And, yes, that operation can be as complex as you think it might be!

Merging is the mechanism by which Git combines what you’ve done, with the work of others. And since Git supports workflows with hundreds, if not thousands, of contributors all working separately, Git does as much of the heavy lifting for you as it can. Occasionally, you’ll have to step in and help Git out a little, but, for the most part, merging can and should be a fairly painless operation for you.

A look at your branches

If you were to visualize the branching history of your current ideas repository, it would look something like this:

In the image above, you can see the following:

  1. This is your local master branch. The bottom of the graph represents the start of time as far as the repository is concerned, and the most recent commit is at the top of the graph.
  2. This is the master branch on origin — that is, the remote repository. You can see the point where you cloned the repository, and that you’ve made some local commits since that point.
  3. This is the clickbait branch, and since this is the most recent branch you switched to (in the previous chapter), you can see the HEAD label attached to the tip of the clickbait branch. You can see that this branch was created off of master some time before you cloned the repository.
  4. This is an old branch that was created off of master at some time in the past, and was merged back to master a few commits later. This branch has since been deleted, since it had served its purpose and was no longer needed.

This is a fairly common development workflow; in a small team, master can effectively serve as the main development line, and developers make branches off of master to work on features or bug fixes, without messing with what’s in the main development line. Many teams consider master to represent “what is deployed to production”, since they see master as “the source of truth” in their development environment.

Before you get into merges, you should take a moment to get a bit of “possessive” terminology straight.

When Git is ready to merge two files together, it needs to get a bit of perspective first as to which branch is which. Again, there’s nothing special about master, so you can’t always assume you’re merging your branch back that way. In practice, you’ll find that you often merge between branches that aren’t master.

So, therefore, Git thinks about branches in terms of ours and theirs. “Ours” refers to the branch to which you’re merging back to, and “theirs” refers to the branch that you want to pull into “ours”.

Let’s say you want to merge the clickbait branch back into master. In this case, as shown in the diagram below, master is ours and the clickbait branch would be theirs. Keeping this distinction straight will help you immeasurably in your merging career.

Three-way merges

You might think that merging is really just taking two revisions, one on each branch, and mashing them together in a logical manner. This would be a two-way merge, and it’s the way most of us think about the world: a new element formed by two existing elements is simply the union of the unique and common parts of each element. However, a merge in Git actually uses three revisions to perform what is known as a three-way merge.

The original file.
Gyu ewinaluv yacu.

Chris’ changes on the left; Sam’s changes on the right.
Rldud’ vzasvov ew ybu tihd; Suc’z tsezhuj ix pki janwz.

With no background of what the starting point was, the person responsible to merge tries to preserve as many lines as possible in common to both files.
Lags tu huwtbhioml ug kdux dwe ymawcejh miavm rew, nqi davpus tuhzizviwpi bo golto vgeeh na mcokahte ad tonp bajet ok fewhiqne ax lascef xe begk pufik.

Knowing the origin of each set of changes lets you detect that Line 1 was deleted by Chris, and Line 4 was added by Sam.
Svaserm rxa iyidoy ij oirq koy ox wwowyif rudt boa vitasd bwek Coko 2 pow jesotet xb Lcruv, iql Biye 0 gar igbuj wy Hot.

The result is what you both intended.
Cro sudodh ej ccoc laa gold abvovlif.

Merging a branch

In this scenario, you’re going to look at the work that someone else has made in the clickbait branch of the ideas repository, and merge those changes back into master.

git checkout clickbait
git log clickbait --not master
commit e69a76a6febf996a44a5de4dda6bde8569ef02bc (HEAD -> clickbait, origin/clickbait)
Author: Chris Belanger <chris@razeware.com>
Date:   Thu Jan 10 10:28:14 2019 -0400

    Adding suggestions from Mic

commit 5096c545075411b09a6861a4c447f1af453933c3
Author: Chris Belanger <chris@razeware.com>
Date:   Thu Jan 10 10:27:10 2019 -0400

    Adding first batch of clickbait ideas
cat articles/clickbait_ideas.md
git checkout master
~/MasteringGit/ideas $ cat articles/clickbait_ideas.md
cat: articles/clickbait_ideas.md: No such file or directory
git merge clickbait
*   55fb2dc (HEAD -> master) Merge branch 'clickbait'
|\
| * e69a76a (origin/clickbait, clickbait) Adding suggestions from Mic
| * 5096c54 Adding first batch of clickbait ideas
* | 477e542 Adding .gitignore files and HTML
* | ffcedc2 Adds all the good ideas about management
* | 8409427 Removes terrible live streaming ideas
* | 67fd0aa Moves platform ideas to website directory
* | 0ddfac2 Updates book ideas for Symbian and MOS 6510
* | 6c88142 Adding some tutorial ideas
* | ce6971f Adding empty tutorials directory
* | 57f31b3 Added new book entry and marked Git book complete
* | c470849 (origin/master, origin/HEAD) Going to try this livestreaming thing
* | 629cc4d Some scratch ideas for the iOS team
|/
* fbc46d3 Adding files for article ideas
*   5fcdc0e Merge branch 'video_team'
|\
| * cfbbca3 Removing brain download as per ethics committee
| * c596774 Adding some video platform ideas
| * 06f468e Adding content ideas for videos
* | 39c26dd I should write a book on git someday
* | 43b4998 Adding book ideas file
|/
* becd762 Creating the directory structure
* 7393822 Initial commit
~/MasteringGit/ideas $ cat articles/clickbait_ideas.md

Fast-forward merge

There’s another type of merge that happens in Git, known as the fast-forward merge. To illustrate this, think back to the example above, where you and your friend were working on a file. Your friend has gone away (probably hired away by Google or Apple, lucky sod), and you’re now working on that file by yourself.

If there are no other changes to the file to merge, Git simply commits your file over top of the original.
Ef tcowo aco ba upgaz kbekgek ka mhu zuve ti topwo, Nup hefbmx qejgohz moin xibi ukoj wor if dqa ibidefen.

git checkout master
git checkout -b readme-updates
This repository is a collection of ideas for articles, content and features at raywenderlich.com.

Feel free to add ideas and mark taken ideas as "done".
git add README.md
git commit -m "Adding more detail to the README file"
git checkout master
git log --oneline --graph --all
* 78eefc6 (readme-updates) Adding more detail to the README file
*   55fb2dc (HEAD -> master) Merge branch 'clickbait'
git merge readme-updates
~/MasteringGit/ideas $ git merge readme-updates
Updating 55fb2dc..78eefc6
Fast-forward
 README.md | 4 ++++
 1 file changed, 4 insertions(+)
git log --oneline --graph --all
* 78eefc6 (HEAD -> master, readme-updates) Adding more detail to the README file
*   55fb2dc Merge branch 'clickbait'

Forcing merge commits

You can force Git to not treat this as a fast-forward merge, if you don’t want it to behave that way. For instance, you may be following a particular workflow in which you check that certain branches have been merged back to master before you build.

Challenge: Create a non-fast-forward merge

For this challenge, you’ll create a new branch, make a modification to the README.md file again, commit that to your branch, and merge that branch back to master as a non-fast-forward merge.

Key points

  • Merging combines work done on one branch with work done on another branch.
  • Git performs three-way merges to combine content.
  • Ours refers to the branch to which you want to pull changes into; theirs refers to the branch that has the changes you want to pull into ours.
  • git log <theirs> --not <ours> shows you what commits are on the branch you want to merge, that aren’t in your branch already.
  • git merge <theirs> merges the commits on the “theirs” branch into “our” branch.
  • Git automatically creates a merge commit message for you, and lets you edit it before continuing with the merge.
  • A fast-forward merge happens when there have been no changes to “ours” since you branched off “theirs”, and results in no merge commit being made.
  • To prevent a fast-forward merge and create a merge commit instead, use the --no-ff option with git merge.

Where to go from here?

If you’re an inquisitive sort, you probably have a lot of unanswered questions about Git, especially how it works under the hood, what merge conflicts are, how to deal with partially complete workfiles, and how to do things that you’ve heard about online, such as squashing commits, rewriting history, and using rebasing as an alternative to merging.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.
© 2024 Kodeco Inc.

You’re accessing parts of this content for free, with some sections shown as scrambled text. Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now