A lesson from my first week at flatiron Labs
by David Gabeau
This was originally posted on the Flatiron Labs Blog.
On my first day at Flatiron Labs I was asked to make a minor change to the website and submit my first pull request from my feature branch to the develop branch which we use for staging. I went through the usual process that I had used before working in a real production environment.
Step 1: git add .Step 2: `git commit -m ?first commit?` Step 3: `git pull origin develop`
?That?s not right,? I was told. ?On this team you must use git pull ?rebase origin develop when submitting a pull request.? ?Why?? I asked. I had never used `?rebase` before. ?`Git pull ?rebase` turns your local and remote branches into a single branch.?
Confused? So was I. In this blog post I?ll explain why it is important to run `git pull ?rebase` when working in a production environment with many developers.
We?ll start by breaking `git pull ?rebase` into its smaller parts, explain those parts, and finally come to a conclusion.
`git pull ?rebase` contains four major git actions: Fetch, Merge, Pull, and Rebase. We?ll break down these actions in that order.Fetch Fetching is what you do when you want to see what others have been working on. Fetched content is represented as a remote branch and has no affect on your local development work. Fetching is a good way to review commits before integrating them with your local repository. You can see how the central history has progressed without merging the changes into your repository.To be more specific, `Git fetch` imports changes from a remote repository (like Github) and places them in your local repository?s object database. The resulting commits are stored as remote branches instead of normal local branches. This allows you to review changes before integrating them into your copy of the project.
When you are fetching git tells you where it stores each branch on remote repository it fetches. For example you should see something like:
6977bba..27686e5b master -> origin/master
when fetching. This means that `origin/master` stores where `master` is on `origin` repository. This info is then left for a later merge operation done by `git merge`.Merge `Git merge` joins two or more development histories together. This is explained with the next two diagrams:Before Merge
A?-B?-C feature / D?-E?-F?-G development
A?-B?-C feature / D?-E?-F?-G?-H development
We can see that in the second diagram both development histories are joined. This will be important to remember when explaining `git pull ?rebase` in our final diagram. But now on to the next action:
Pull`git pull` is a combination of `git fetch` and `git merge`. `git pull` runs `git fetch` with given parameters and then calls `git merge` to merge the retrieved branch heads into the current branch.
#Before Pull A?-B?-C feature / D?-E?-F?-G development#After Pull A?-B?-C feature / D?-E?-F?-G?-H development
The diagrams for merge and pull look very similiar because they are. `Git merge` will only work if you give your local branch a branch to merge with; these are typically given by a `fetch` command.
The last and final piece of `git pull ?rebase` is the `rebase`. `Git merge` takes all the changes and merges them in one commit, while `git rebase` makes the point of any local merge the beginning of the master branch.These diagrams should help:
Starting history before `merge` or `rebase` C?-D?-E feature / A?-B?-F?-G development#After Merge C?-D?-E feature / A?-B?-F?-G?-H development#After rebase C??D??E? development / A?-B?-F?-G remote
As you can see, even though both actions join histories, `rebase` does so without creating a seperate commit in history (H) to join at.
Git pull ?Rebase.And now to tie it altogether with `git pull ?rebase`.By now we know that `git pull` is a combination of `git fetch` and `git merge`. We also know that `rebase` brings local commits to the head of the master branch. When you run `git pull ?rebase` you are are telling `git pull` to run `git fetch` and then `git rebase` not `git merge`.
This means that the commits that you pull will always be at the head of the master branch which is important when many people are committing and pulling because it keeps the branches history clean, linear, and very easy to fix with a rollback in case of any mistakes.
In short, `git pull` is fine when you have created a branch for the purpose of developing a single feature, but here at Flatiron Labs we use `git pull ?rebase` before combining a feature branch with the staging (development) branch because it is a consistent way to maintain interim commits on a team with many developers.
For further reading about Git check out the documentation here.