---
title: "Handling \"git pull\" Automatic Merges"
url: "/articles/handling-git-pull-automatic-merges"
type: article
date: 2011-08-03
updated: 2014-05-15
---

# Handling "git pull" Automatic Merges

#  Handling "git pull" Automatic Merges 

 "Only YOU can prevent useless merges"

 By

 [  Andrew Berry   ](/about/andrew-berry) 

 August 3, 2011

  

If you're just starting out with Git, you'll inevitably run into commits into your feature branches like the following:

> Merge branch 'test' of git.lullabot.com:lbcom into test

What are these commits, and how did they get created? Usually, it's the result of adding a commit to your local copy of a branch, and then pulling upstream changes into that branch. Since your local commit isn't on the remote repository yet, when `git pull` runs `git merge origin/[branch] [branch]`, it will automatically do a "recursive" merge and create a commit with the remote changes. Then, when you push your changes up, you end up with both a merge from the remote integration branch into your local branch, and a merge from your feature branch into the integration branch.

Let's take a look at an example of how this situation can happen, and a way to resolve it cleanly. First, let's create two temporary git repositories: "upstream", to represent the remote repository, and "downstream", to represent your local clone of the repository.

`~/ $ cd /tmp<br></br>tmp/ $ git init upstream<br></br>Initialized empty Git repository in /private/tmp/upstream/.git/<br></br>tmp/ $ cd upstream<br></br>upstream/ $ git config --local receive.denyCurrentBranch ignore # This allows us to push into upstream even when it has a branch checked out<br></br>upstream/ $ echo 'Demo for how to handle upstream commits after you have merged into the upstream branch.' > README.txt<br></br>upstream/ $ git add README.txt<br></br>upstream/ $ git commit -m 'Adding a README file.'<br></br>[master (root-commit) b8b6630] Adding a README file.<br></br> 1 files changed, 1 insertions(+), 0 deletions(-)<br></br> create mode 100644 README.txt<br></br>upstream/ $ cd /tmp<br></br>tmp/ $ git clone upstream downstream<br></br>Cloning into downstream...<br></br>done.  `

Now that we have our upstream repository with one commit on master, and a downstream clone of it, let's add another commit to the upstream repository:

`tmp/ $ cd upstream<br></br>upstream/ $ echo 'Adding another upstream commit.' >> README.txt<br></br>upstream/ $ git add README.txt<br></br>upstream/ $ git commit -m 'Adding an upstream commit.'<br></br>[master 9e625ab] Adding an upstream commit.<br></br> 1 files changed, 1 insertions(+), 0 deletions(-)  `

The next step is to add a feature branch and merge commit to the downstream clone. This simulates parallel development between two different developers:

`upstream/ $ cd /tmp/downstream<br></br>downstream/ $ git checkout -b 1234/awesome-feature-branch<br></br>Switched to a new branch '1234/awesome-feature-branch'<br></br>downstream/ $ echo 'Adding a downstream commit before pulling into my local master branch.' >> README.txt<br></br>downstream/ $ git add README.txt<br></br>downstream/ $ git commit -m 'Adding a downstream commit.'<br></br>[1234/awesome-feature-branch dff13db] Adding a downstream commit.<br></br> 1 files changed, 1 insertions(+), 0 deletions(-)<br></br>downstream/ $ git checkout master<br></br>Switched to branch 'master'<br></br>downstream/ $ git merge --no-ff 1234/awesome-feature-branch<br></br>Merge made by recursive.<br></br> README.txt |    1 +<br></br> 1 files changed, 1 insertions(+), 0 deletions(-)<br></br>  `

We've completed our feature branch, and have merged it to our local copy of master. Time to push up our merge and share it with the world!

`downstream/ $ git push<br></br>To /tmp/upstream<br></br> ! [rejected]        master -> master (non-fast-forward)<br></br>error: failed to push some refs to '/tmp/upstream'<br></br>To prevent you from losing history, non-fast-forward updates were rejected<br></br>Merge the remote changes (e.g. 'git pull') before pushing again.  See the<br></br>'Note about fast-forwards' section of 'git push --help' for details.<br></br>downstream/ $ git pull<br></br>remote: Counting objects: 5, done.<br></br>remote: Compressing objects: 100% (2/2), done.<br></br>remote: Total 3 (delta 1), reused 0 (delta 0)<br></br>Unpacking objects: 100% (3/3), done.<br></br>From /tmp/upstream<br></br>   b8b6630..9e625ab  master     -> origin/master<br></br>Auto-merging README.txt<br></br>CONFLICT (content): Merge conflict in README.txt<br></br>Automatic merge failed; fix conflicts and then commit the result.<br></br>downstream/ $ vim README.txt<br></br>downstream/ $ git add README.txt<br></br>downstream/ $ git commit<br></br>[master 46208d7] Merge branch 'master' of /tmp/upstream<br></br>downstream/ $ git push<br></br>Counting objects: 11, done.<br></br>Delta compression using up to 2 threads.<br></br>Compressing objects: 100% (5/5), done.<br></br>Writing objects: 100% (7/7), 779 bytes, done.<br></br>Total 7 (delta 2), reused 0 (delta 0)<br></br>Unpacking objects: 100% (7/7), done.<br></br>To /tmp/upstream<br></br>   9e625ab..46208d7  master -> master<br></br>  `

What does our history graph look like now?

  ```

downstream/ $ git lg
*   46208d7 - (HEAD, origin/master, origin/HEAD, master) Merge branch 'master' of /tmp/upstream (2011-07-29 14:49:38 -0400) <Andrew Ber
|\  
| * 9e625ab - Adding an upstream commit. (2011-07-29 14:33:55 -0400) <Andrew Berry>
* |   1bffd57 - Merge branch '1234/awesome-feature-branch' (2011-07-29 14:37:17 -0400) <Andrew Berry>
|\ \  
| |/  
|/|   
| * dff13db - (1234/awesome-feature-branch) Adding a downstream commit. (2011-07-29 14:35:01 -0400) <Andrew Berry>
|/  
* b8b6630 - Adding a README file. (2011-07-29 14:32:11 -0400) <Andrew Berry>
  
```

That's pretty confusing. How could we have done this better? Instead of using `git pull`, let's use `git pull --ff-only`. Better yet, let's alias that command to `git pl` by running `git config --global alias.pl 'pull --ff-only'`. The following was done after I undid the above merges in both repositories using `git reset`. *Never do `git reset` on a real public branch!*

`downstream/ $ git pl<br></br>From /tmp/upstream<br></br>   b8b6630..9e625ab  master     -> origin/master<br></br>fatal: Not possible to fast-forward, aborting.<br></br>downstream/ $ git lg<br></br>*   9de839b - (HEAD, master) Merge branch '1234/awesome-feature-branch' (2011-07-29 14:52:21 -0400) <Andrew Berry><br></br>|\<br></br>| * dff13db - (1234/awesome-feature-branch) Adding a downstream commit. (2011-07-29 14:35:01 -0400) <Andrew Berry><br></br>|/<br></br>| * 9e625ab - (origin/master, origin/HEAD) Adding an upstream commit. (2011-07-29 14:33:55 -0400) <Andrew Berry><br></br>|/<br></br>* b8b6630 - Adding a README file. (2011-07-29 14:32:11 -0400) <Andrew Berry><br></br>downstream/ $ git reset --hard origin/master<br></br>HEAD is now at 9e625ab Adding an upstream commit.<br></br>downstream/ $ git merge --no-ff 1234/awesome-feature-branch<br></br>Auto-merging README.txt<br></br>CONFLICT (content): Merge conflict in README.txt<br></br>Resolved 'README.txt' using previous resolution.<br></br>Automatic merge failed; fix conflicts and then commit the result.<br></br>downstream/ $ vim README.txt<br></br>downstream/ $ git add README.txt<br></br>downstream/ $ git commit<br></br>[master b8d200d] Merge branch '1234/awesome-feature-branch'<br></br>downstream/ $ git push<br></br>Counting objects: 10, done.<br></br>Delta compression using up to 2 threads.<br></br>Compressing objects: 100% (4/4), done.<br></br>Writing objects: 100% (6/6), 674 bytes, done.<br></br>Total 6 (delta 1), reused 0 (delta 0)<br></br>Unpacking objects: 100% (6/6), done.<br></br>To /tmp/upstream<br></br>   9e625ab..b8d200d  master -> master  `

What does our repository look like now?

`downstream/ $ git lg<br></br>*   cf13636 - (HEAD, origin/master, origin/HEAD, master) Merge branch '1234/awesome-feature-branch' (2011-08-01 20:44:09 -0400) <Andrew<br></br>|\<br></br>| * dff13db - (1234/awesome-feature-branch) Adding a downstream commit. (2011-07-29 14:35:01 -0400) <Andrew Berry><br></br>* | 9e625ab - Adding an upstream commit. (2011-07-29 14:33:55 -0400) <Andrew Berry><br></br>|/<br></br>* 9568144 - Adding a README file. (2011-08-01 20:41:38 -0400) <Andrew Berry>  `

## The Takeaway

- Try to prevent extra merge commits when they don't show anything useful about the development of a feature branch.
- Don't use `git pull` by default, and if you do, be prepared to undo local merge commits with `git reset --hard HEAD^`. Use the `git pl` alias above to simplify this.
- If you do run into a situation where someone else has pushed a commit to the integration branch before you, use `git reset --hard origin/[branchname]` on your local copy of the integration branch to remove your merge and create a new one at the tip of the branch.

## Footnote

For the command-line-addicted, my alias for `git lg` in ~/.gitconfig is:  
`[alias]<br></br>  lg = log --all --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%ci) %C(bold blue)<%an>%Creset' --abbrev-commit`

 

   You must have JavaScript enabled to use this form.

## Get in touch with us

### Tell us about your project. We'd love to hear from you!

 First Name  

 Last Name  

 Your email address  

 Your organization  

 How you heard about us  

 Tell us more 

     Leave this field blank