Skip to content

Instantly share code, notes, and snippets.

@wware
Last active August 29, 2015 14:17
Show Gist options
  • Save wware/aa30601146f4a6462054 to your computer and use it in GitHub Desktop.
Save wware/aa30601146f4a6462054 to your computer and use it in GitHub Desktop.
Tricks and tips for "git merge"

Git Merge Lore

I'm working at a place where people prefer merges over rebases. In the past I've been influenced by the pro-rebase school of thought, but if there are relatively few pull requests being merged, you can use --no-ff to maintain pretty good clarity, and merge points become the decision point where a pull request has been included or excluded. With that in mind, I want to look at a few relevant use cases.

Before I do that, I want to highly recommend the following addition to your ~/.gitconfig file, which is invoked with the command git lg. It shows all the git tags and branches with nice colors to clarify everything that's going on.

[alias]
        lg = log --graph --abbrev-commit --decorate --date=relative --format=format:'%C(bold blue)%h%C(reset) - %C(bold green)(%ar)%C(reset) %C(white)%s%C(reset) %C(dim white)- %an%C(reset)%C(bold yellow)%d%C(reset)' --all

I also want to provide a few helpful git-related links:

Merging one branch into another using "--no-ff"

Let's set up a couple of branches and then merge one into the other. In both this section and the next section, you can think of branch A as a pull request that we want to merge (either into master or into branch B).

$ git init
$ touch README.md
$ git add README.md
$ git commit -m "Initial commit, empty README.md"

$ vim README.md    # add some text
$ git commit -a -m "beginning readme stuff"

$ git checkout -b A
$ touch a.txt
$ git add a.txt
$ git commit -m "Add a file a.txt"

$ git checkout master
$ git checkout -b B
$ touch b.txt
$ git add b.txt
$ git commit -m "Add a file b.txt"

$ git merge --no-ff A

With the last line, we are on branch B, and we are merging branch A into branch B.

*   cd399d8 - (11 seconds ago) Merge branch 'A' into B - Will Ware (HEAD, B)
|\
| * 823b468 - (54 seconds ago) Add a file a.txt - Will Ware (A)
* | 9be8ef8 - (25 seconds ago) Add a file b.txt - Will Ware
|/
* 28dff88 - (2 minutes ago) beginning readme stuff - Will Ware (master)
* e2bdbd5 - (2 minutes ago) Initial commit, empty README.md - Will Ware

And the result is that we merge branch A into branch B. The --no-ff option prevents a fast-forward merge. For instance if there had been no commit on branch B after the point of divergence, but branch A represents a pull request, we would get this:

* 823b468 - (54 seconds ago) Add a file a.txt - Will Ware (HEAD, A, B)
* 28dff88 - (2 minutes ago) beginning readme stuff - Will Ware (master)
* e2bdbd5 - (2 minutes ago) Initial commit, empty README.md - Will Ware

What's bad here is that branch A (the work in the pull request) is not visually set apart from other work. We want the work in branch A to be visually distinct like this:

*   cd399d8 - (11 seconds ago) Merge branch 'A' into B - Will Ware (HEAD, B)
|\
| * 823b468 - (54 seconds ago) Add a file a.txt - Will Ware (A)
|/
* 28dff88 - (2 minutes ago) beginning readme stuff - Will Ware (master)
* e2bdbd5 - (2 minutes ago) Initial commit, empty README.md - Will Ware

Merging the target branch back into the work branch

This is necessary if a pull request has become unmergeable. Obviously some amount of manual editing will be required to resolve the conflict. Let's look at how that works.

Again taking branch A as a pull request, we'll first create a situation where the pull request has become unmergeable.

$ git checkout A
$ echo "The owls are not what they seem" > a.txt
$ git commit -a -m "Add some content to a.txt"

$ git checkout master
$ echo "Cooper Cooper Cooper" > a.txt
$ git add a.txt
$ git commit -m "Create a different, incompatible a.txt"

At this point, A is not mergeable into master without manual editing. What we're going to do is merge master into A, resolving the conflict. This will make A mergeable.

$ git checkout A
$ git merge --no-ff master
Auto-merging a.txt
CONFLICT (add/add): Merge conflict in a.txt
Automatic merge failed; fix conflicts and then commit the result.
$ vim  a.txt
$ git commit -a -m "Resolve incompatibility"

Now that the pull request (branch A) is mergeable, we can merge it into master, even if we've done a little more work on master -- provided that additional work doesn't make the pull request unmergeable again. If it does, we need another cycle of merging master back into A.

$ git checkout master
$ echo "Humpty dumpty" >> a.txt
$ git commit -a -m "yet more stuff in a.txt"
$ git merge --no-ff A

The end result of all this is the graph below.

*   3b69b66 - (23 seconds ago) Merge branch 'A' - Will Ware (HEAD, master)
|\
| *   149702b - (81 seconds ago) Resolve incompatibility - Will Ware (A)
| |\
| * | 01acdb5 - (4 minutes ago) Add some content to a.txt - Will Ware
| * | 823b468 - (17 minutes ago) Add a file a.txt - Will Ware
* | | 41d9a38 - (34 seconds ago) yet more stuff in a.txt - Will Ware
| |/
|/|
* | 274149f - (3 minutes ago) Create a different, incompatible a.txt - Will Ware
* | 65076bc - (7 minutes ago) More readme - Will Ware
|/
* 28dff88 - (18 minutes ago) beginning readme stuff - Will Ware
* e2bdbd5 - (19 minutes ago) Initial commit, empty README.md - Will Ware
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment