The git pull command is probably one of the most used. But how does it really work?

git pull [options] [<repository> [<refspec>...]]

As we can read in the git pull documentation, what this command does is running a git fetch with the given parameters and then a git merge to incorporate the retrieved heads into the current branch.

We now need to understand what fetch does, what are the parameters used for, and what merge does.


This is the command to use to get up to date refs__ from a given repository. _Refs is the git term used to group branches and tags.

The optional refspec parameter specifies which refs to and which local refs to update.

The format of a parameter is an optional plus `+`, followed by the source ref , followed by a colon `:`, followed by the destination ref . The colon can be omitted when is empty.

It’s nice to have the power to map a source to a differently named destination, but in my opinion keeping everything aligned with the remote makes things simpler.


The merge command is certainly another famous one. What it does is incorporating changes from the named commits, since the time their histories diverged from the current branch, into the current branch.

Using the same example used in the documentation, given this tree:

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

Running git merge topic from the master branch will replay the changes made on topic since it diverged from master on top of it, and make a new commit with the result.

This means that the changes from E introduced by A, B, and C will all end up all together into a single new commit.

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

To recap, git pull origin under the hood calls git fetch origin, which gets all the changes made in the remote repository named origin. Then git merge is called, which creates a new commit in the current branch to add all the changes fetched.

Food for thoughts:

  • What are the most interesting options for pull, fetch and merge?
  • Usage examples of the refspec syntax of fetch
  • How are the default values picked for these commands?