User Tools

Site Tools


git_merge

Overview

Both basic and advanced merging operations.

SYNOPSIS

git merge [-n] [--stat] [--no-commit] [--squash]
     [--[no-]edit]
     [-s <strategy>] [-X <strategy-option>] [-S[<keyid>]]
     [--[no-]allow-unrelated-histories]
     [--[no-]rerere-autoupdate] [-m <msg>]
     [-F <file>] [<commit>...]
git merge --abort
git merge --continue

Simple merging

Basic merge

If you have this situation:

              A---B---C topic
             /
        D---E---F---G master

followed by:

$ git checkout master
$ git merge topic

the end result is a new merge commit H:

              A---B---C topic
             /         \
        D---E---F---G---H master

Fast-forward merge

If you have this:

              A---B---C topic
             /
        D---E master

followed by:

$ git checkout master
$ git merge topic

the default fast-forward merge will produce:

              A---B---C topic
             /          master
        D---E

or, depicted another way:

        D---E---A---B---C master
                          topic

Query containedness and mergeness

From man git-branch:

With --contains, shows only the branches that contain the named
commit (in other words, the branches whose tip commits are
descendants of the named commit), --no-contains inverts it.
With --merged, only branches merged into the named commit (i.e.
the branches whose tip commits are reachable from the named
commit) will be listed. With --no-merged only branches not
merged into the named commit will be listed. If the <commit>
argument is missing it defaults to HEAD (i.e. the tip of the
current branch).

Examples:

$ git branch --merged master
$ git branch --no-merged
$ git branch --contains v4.19
$ git branch --no-contains v4.19

Dealing with simple merge conflicts

Imagine this change on the master branch:

$ git show master
commit 4a93eab592cf790838314b3799eb7a4faa213538 (HEAD -> master)
Author: Robert P. J. Day <rpjday@crashcourse.ca>
Date:   Fri Mar 1 08:17:50 2019 -0500

    Change to third edition

diff --git a/README.asc b/README.asc
index fa40bad..9fefbd5 100644
--- a/README.asc
+++ b/README.asc
@@ -1,4 +1,4 @@
-= Pro Git, Second Edition
+= Pro Git, Third Edition
 
 Welcome to the second edition of the Pro Git book.
 
$

And imagine this clearly-conflicting change on the branch 4th:

$ git show 4th
commit 9e679bc1c27d5d708d571ea1b47564f3a99df944 (4th)
Author: Robert P. J. Day <rpjday@crashcourse.ca>
Date:   Fri Mar 1 08:19:35 2019 -0500

    Fourth edition

diff --git a/README.asc b/README.asc
index fa40bad..1f0879f 100644
--- a/README.asc
+++ b/README.asc
@@ -1,4 +1,4 @@
-= Pro Git, Second Edition
+= Pro Git, Fourth Edition
 
 Welcome to the second edition of the Pro Git book.
 
$

Trying to merge will generate a merge conflict:

$ git checkout master
$ git merge 4th
Auto-merging README.asc
CONFLICT (content): Merge conflict in README.asc
Automatic merge failed; fix conflicts and then commit the result.
$

git status will tell you that you have a merge conflict;

$ git status
... snip ...
You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)

	both modified:   README.asc

no changes added to commit (use "git add" and/or "git commit -a")

The merge conflict is identified in the README.asc file:

$ less README.asc
<<<<<<< HEAD
= Pro Git, Third Edition
=======
= Pro Git, Fourth Edition
>>>>>>> 4th

Welcome to the second edition of the Pro Git book.

... etc etc ...

So edit the file and resolve the conflict any way you want, such as:

$ less README.asc
= Pro Git, Fifth Edition
... snip ...

Stage the resolved file:

$ git add README.asc

You can tell the conflicts are now resolved:

$ git status
On branch master

All conflicts fixed but you are still merging.
  (use "git commit" to conclude merge)

Changes to be committed:

	modified:   README.asc

$

And commit:

$ git commit -m "Bumped merge up to fifth edition"

The final version of README.asc:

= Pro Git, Fifth Edition

Welcome to the second edition of the Pro Git book.
... etc ...

Advanced merging

Fast-forwarding

Recall a fast-forward merge:

              A---B---C topic
             /          master
        D---E

You may or may not want that:

--ff
    When the merge resolves as a fast-forward, only update the
    branch pointer, without creating a merge commit. This is
    the default behavior.

--no-ff
    Create a merge commit even when the merge resolves as a
    fast-forward. This is the default behaviour when merging an
    annotated (and possibly signed) tag that is not stored in
    its natural place in refs/tags/ hierarchy.

--ff-only
    Refuse to merge and exit with a non-zero status unless the
    current HEAD is already up to date or the merge can be
    resolved as a fast-forward.

Committing

--commit, --no-commit
    Perform the merge and commit the result. This option can be
    used to override --no-commit.

    With --no-commit perform the merge but pretend the merge
    failed and do not autocommit, to give the user a chance to
    inspect and further tweak the merge result before
    committing.

Editing

--edit, -e, --no-edit
    Invoke an editor before committing successful mechanical
    merge to further edit the auto-generated merge message, so
    that the user can explain and justify the merge. The
    --no-edit option can be used to accept the auto-generated
    message (this is generally discouraged). The --edit (or -e)
    option is still useful if you are giving a draft message
    with the -m option from the command line and want to edit
    it in the editor.

Squashing

--squash, --no-squash
    Produce the working tree and index state as if a real merge
    happened (except for the merge information), but do not
    actually make a commit, move the HEAD, or record
    $GIT_DIR/MERGE_HEAD (to cause the next git commit command
    to create a merge commit). This allows you to create a
    single commit on top of the current branch whose effect is
    the same as merging another branch (or more in case of an
    octopus).

    With --no-squash perform the merge and commit the result.
    This option can be used to override --squash.

As in:

$ git checkout master
$ git merge --squash <branch with many commits>
$ git commit

Setting merge options

Per-branch merge options

From man git-config, you can set (either locally or globally) per-branch merge options:

branch.<name>.mergeOptions
    Sets default options for merging into branch <name>. The
    syntax and supported options are the same as those of git-
    merge(1), but option values containing whitespace
    characters are currently not supported.

For example, if you wanted to prevent any fast-forward merges to any master branch across all of your repositories, you could:

$ git config --global branch.master.mergeOptions "--no-ff"

Global merge.ff option

For merging, there is at least one repo-wide merge option you can set (see man git-merge):

merge.ff
    By default, Git does not create an extra merge commit when
    merging a commit that is a descendant of the current
    commit. Instead, the tip of the current branch is
    fast-forwarded. When set to false, this variable tells Git
    to create an extra merge commit in such a case (equivalent
    to giving the --no-ff option from the command line). When
    set to only, only such fast-forward merges are allowed
    (equivalent to giving the --ff-only option from the command
    line).

So for widespread fast-forward merge configuration:

$ git config --global merge.ff "true"

This setting is superseded by any per-branch fast-forward merge setting.

Merge strategies

ours

Technically record a merge while totally ignoring its content – for record-keeping.

Example:

$ git checkout master
$ git merge --strategy=ours <obsolete branch>

How to make master look exactly like develop:

$ git checkout topic
$ git merge -s ours master
$ git checkout master
$ git merge --ff-only topic

To do this for an arbitrary commit, create a temporary branch:

$ git checkout -b tempbranch <commit ID>
$ git merge -s ours master
$ git checkout master
$ git merge --ff-only tempbranch
git_merge.txt · Last modified: 2019/03/13 13:09 by rpjday