Yes, fast-forwarding is a way of maintaining linear history without merge commits.
What is the difference between a fast-forwarded git merge
and a git rebase
When git performs a fast-forward, it is the same thing whether you are using git merge
or git rebase
.
However, merging 2 branches using git merge
will not always be a fast-forward. In this case, you use git rebase
to prepare commit history in the merging branch so that you get to achieve a fast-forward merge.
When fast-forward is possible with git merge
Let us have a scenario: You are working on your own project. Somewhere along, you want to add a feature you have thought of. It is somewhat challenging and you need to do it in a separate branch to see if you can build it.
Your project has a main branch called develop
. And to build this feature, you create a branch called feature
and switch to it. You work on this feature and make several commits. After some while of hacking, you have managed to build it.
At this moment, you project history is like this:
Actually, develop
branch has not had a new commit since you shifted to building and committing in the feature
branch. Therefore, there is no divergent work, i.e feature
branch is directly ahead of develop
. When we merge feature
into develop
using:
git checkout develop
git merge feature
We will get a fast-forward merge. Meaning, Git will not generate a merge commit but just point develop
branch to the tip of feature
branch:
Using git rebase
to make Git perform fast-forward merge
In the second scenario: You have more features to build for your project. And you bring in more developers and give them a feature to build in their respective feature/topic branches. Yourself, you are building yet another feature in feature-2
branch.
At some point, you have finished your feature. But at this time, other developers you assigned them features to build, have done so and already merged their work to the develop
branch:
Right now if you merge like:
git checkout develop
git merge feature-2
You won't have a fast-forward merge because develop
has evolved with newer commits since you last branched off. To make a fast-forward merge possible, you have to change the base of feature-2
branch onto the latest commit on develop
branch, like:
git rebase develop feature-2 #checkout feature-2 then rebase
And this is now the history:
Something about git rebase
is that it will change the base of a branch and reapply its commits with new IDs in the order they occured. Hence the commits illustrated as c3'...c5'
in the image.
Once we have rebased feature-2
branch, we can now merge it into develop
:
git checkout develop
git merge feature-2
And the result should be a fast-forward. The commits of feature-2
branch are appended to the top of everything else in develop
branch:
If so, why would one use one over the other?
When we are certain that git will fast forward changes when merging branches, the merge command: git checkout develop; git merge feature
,will yield the same project history as the rebase command: git rebase feature develop
. So there is no reason to use one over the other(If the two branches can be fast-forwaded). Just your preference.