Before continuing the GIT series, it is worthwhile to tangent a bit and write about using git rebase
versus git pull
. Using git pull
will fetch any changes from the remote branch and merge them on to your local branch, creating a new merge commit. Using git rebase
will remove each of your commits temporarily (stored in .git/rebase), update your local branch to match the remote branch, then apply each of your local changes again in the order they were originally applied. Both processes will lead to occasion merge conflicts, but the later will produce a cleaner history, without extraneous merge commits.
My personal experience is that git rebase
is only more tedious when there are merges, but because it adjusts the git history, it is easier to track commits in a collaborative repository. Especially, when trying to figure out where a code change was originally introduced. Our team exclusively uses git rebase
at Votizen.
Getting ready
For the examples today, assume you are working on your local branch master
and a remote branch origin/master
. The origin/master
branch is collaborative and frequently committed to by multiple team members. You updated master
from origin/master
a few hours ago, made severals commits, and when you try to push, you see the following:
To [email protected]:votizen/common.git ! [rejected] master -> master (non-fast-forward) error: failed to push some refs to '[email protected]:{YOUR_REMOTE_REPO}.git' 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.
The Git commit history looks something like:
- C1 - C2 - C3 - C4 - C5 - C6 - C7 (master) \ C5' - C6' - C7' (origin/master)
How do it…
If you follow the instructions in the Git message and pull:
git pull origin master
Git actually does the following two commands:
git fetch origin master git merge origin/master
And the following happens to the commit tree:
- C1 - C2 - C3 - C4 - C5 - C6 - C7 (master) \ \ C5' - C6' - C7' - C8 (origin/master)
On the other hand, if you are to rebase:
git fetch origin master git rebase origin
The following happens to the commit tree:
- C1 - C2 - C3 - C4 - C5' - C6' - C7' - C5 - C6 - C7 (master) | (origin/master)
How it works…
In the first example, the remote changes are fetched and then merged together with your local into a new commit. In some circumstances this will cause the merging committer to be attributed with changes that they never made. In the latter example the remote changes are applied before your changes, and then your changes are applied afterwards. Any merges will be resolved when your changes begin to be applied.
There’s more…
For more information, there is another great article about rebasing on the online Git Book.