Alex headshot

AlBlue’s Blog

Macs, Modularity and More

Git Tip of the Week: Pulling and Rebasing

2011, git, gtotw, tip

This week's Git Tip of the Week is about configuring what happens when you pull. You can subscribe to the feed if you want to receive new instalments automatically.


Pulling

Back in March, I wrote about pushing and pulling as an introduction to getting data from a remote Git server. Now that we've talked about rebasing (twice), we can talk about the different pull strategies.

Recall that git fetch merely makes the changes available in your local repository; it doesn't affect the branch(es) that you are on. On the other hand, git pull does affect the branches that you are on as it tries to include changes from upstream.

By default, Git will attempt to do a merge whenever you pull changes. Here's what it looks like when you do a merge:


$ git log --oneline master
e1c1744 Third
36c3a20 Second
c66b73b First
# Take a branch from a previous point in history
$ git checkout -b feature-merge 36c3a20
Switched to a new branch 'feature-merge'
# Set it up so I can pull from master
$ git branch --set-upstream feature-merge master
Branch feature-merge set up to track local branch master.
$ git log --oneline feature-merge
36c3a20 Second
c66b73b First
# Add another file so we diverge
$ touch feature-merge.txt
$ git add feature-merge.txt
$ git commit -m "Feature-Merge"
[feature-merge a16a3db] Feature-Merge
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 feature-merge.txt
# Now, let's see what happens when we pull
$ git pull
From .
 * branch            master     -> FETCH_HEAD
Merge made by recursive.
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 c
$ git log --oneline --graph
*   23b50a0 Merge branch 'master' into feature-merge
|\  
| * e1c1744 Third
* | a16a3db Feature-Merge
|/  
* 36c3a20 Second
* c66b73b First

Here, we've invoked the default operation which is to do a merge. When we're behind master with local changes, and we do a pull, it automatically sets up a merge node, as shown by the graph above. (Normally the branch would be a remote one; however, I'm showing a tracked local branch for convenience.)

However, this is configurable to do a rebase instead. This configuration is done on a branch-by-branch basis. Let's create a new branch to experiment with this feature:


$ git checkout -b feature-rebase 36c3a20
Switched to a new branch 'feature-rebase'
$ git branch --set-upstream feature-rebase master
Branch feature-rebase set up to track local branch master.
$ git log --oneline feature-rebase
36c3a20 Second
c66b73b First
# Add another file so we diverge
$ touch feature-rebase.txt
$ git add feature-rebase.txt
$ git commit -m "Feature-Rebase"
[feature-rebase 62855ee] Feature-Rebase
 0 files changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 feature-rebase.txt
$ git log --oneline
62855ee Feature-Rebase
36c3a20 Second
c66b73b First
# Configure the branch for rebase operations
$ git config branch.feature-rebase.rebase true
# Now, let's see what happens when we pull
$ git pull
From .
 * branch            master     -> FETCH_HEAD
First, rewinding head to replay your work on top of it...
Applying: Feature-Rebase
$ git log --oneline
* ff0ecc2 Feature-Rebase
* e1c1744 Third
* 36c3a20 Second
* c66b73b First

What's happened here is that instead of creating a merge node, the pull operation resulted in a rebase of the underlying branch against the current master. This is dangerous (in the sense that a rebase is dangerous and changes history) but provided that you're doing this on local branches (those not pushed to the repository yet) then you may find this acceptable.

This configuration has to be done on a branch-by-branch basis. If your preferred way of working is to always enable this option, then there is a configuration item which can help:


$ git config branch.autosetuprebase always

If this is configured (either in a repository or globally with the --global setting) then whenever you create a new branch, it will automatically add branch.name.rebase=true for you.


Come back next week for another instalment in the Git Tip of the Week series.