Git: “git pull” vs “git pull -rebase”, a cleaner way to pull

I have been using GIT for my personal projects for a while and I absolutely “LOVE IT”. One of the many reasons is that, I could simply create a project and just do a “git init” to have a full fledged  version control for my code! I did not have to setup of any servers, nor I had to have a “network” connection to do things. Another one is that I could simply put my project in the Dropbox and could work on the project from different machines without having to worry about setting up anything else and still have my version control.

As I worked on my personal projects, I was the only one committing to the repo and things were simple. I could have a feature branch, do merges etc and history of the project would be clean.
Recently I started using GIT on a project that involved more than 2 developers working and often committed changes to the same branch and the history started looking ‘dirty’.

Here is an example.

I am going to setup a simple project called ‘GitExamples’.

$ mkdir GitExamples
$ cd GitExamples
$ git init
$ git checkout -b test

Now to mimic two different users I am going to create two different clones. Just to make things clear I am going to create two directories UserARepo and UserBRepo and clone the repo.

$ mkdir ~/UserARepo
$ mkdir ~/UserBRepo

Let’s setup UserA’s repo

$ cd ~/UserARepo
$ git clone ~/GitExamples
$ git config 'UserA'

Now. UserB

$ cd ~/UserBRepo
$ git clone ~/GitExamples
$ git config 'UserB'

This sets up my playground.
When I am in UserARepo and do a commit I should see “UserA” and likewise for B.

Let me make a quick change from UserA’s repo

$ cd ~/UserARepo
$ echo 'First Text' > UserA.txt
$ git add UserA.txt
$ git commit -m "User A's First commit"

Here is how my history looks:

I am going to push this change up to the remote master repo

$ git push

Let’s say UserA makes another change

$ echo 'Added Some good stuff' >> UserA.txt
$ git commit -am 'UserA Added some content'
$ git push

Things are simple and clean so far,
Here is my working tree:

Let’s jump to UserB to mix things up a bit.

$ cd ~UserBRepo/GitExamples
$ echo "B's First text">UserB.txt
$ git add UserB.txt
$ git commit -m "User B's Fist commit"

If I just did a simple push at this time, it should error out as the HEAD in remote has moved on by few commit pushed by User A.

$ git push
To /home/manijshrestha/deletethis/GitExamples/
 ! [rejected] master -> master (non-fast-forward)
error: failed to push some refs to '/home/manijshrestha/deletethis/GitExamples/'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes (e.g. 'git pull') before pushing again. See the
'Note about fast-forwards' section of 'git push --help' for details.

Here is a better view of how things are

As you can see the ‘master’ in remote has gone its own way since I pulled from it.

Let’s do a pull and then push our changes.

$ git pull
Merge made by recursive.
 UserA.txt | 2 ++
 1 files changed, 2 insertions(+), 0 deletions(-)

Here is how it looks

Here you see the working tree represents what happened but this looks ‘dirty’ with merges, specially since both users worked on different files, it could look cleaner, follow on.

$ git push

From UserA’s side lets do a pull so both users are at the same base.

Lets run through same scenario this time but we will use “–rebase” while doing a pull and you will see how the tree will look a lot cleaner.

So, I am going to do two commits from UserA’s repo

$ echo 'Some more good stuff' >> UserA.txt
$ git commit -am 'User A added good stuff'
$ echo 'Even more good stuff' >> UserA.txt
$ git commit -am 'User A added more good stuff'
$ git push

Going back to UserB’s repo, we will make some change and commit

$ echo "Some good stuff" >> UserB.txt
$ git commit -am "User B added good stuff"
$ echo "Yet Some good stuff" >> UserB.txt
$ git commit -am "User B added yet more"

Unlike before we will do a pull with –rebase flag.
What it does is that, it will get the changes from remote then “re-apply” the changes the user made locally, so things don’t look deviated.

$ git pull --rebase
First, rewinding head to replay your work on top of it...
Applying: User B added good stuff
Applying: User B added yet more

Git just told us what it did, and here is how the tree looks:

You can see the working tree now looks a lot cleaner.

So we have a one straight branch rather than merges etc.

So If i do a push here is how things look.

Will share some move git love in the future…