Understanding git fast forward merges
One common type of merge operation is the "fast forward" merge. This guide will explain what a fast forward merge is, how it works, and when it's applicable, including detailed examples and explanations of relevant Git terminology.
What is a git fast forward?
A fast forward in Git occurs during a merge operation when the base branch that's being merged into has no new commits since the feature branch (the branch being merged) was created or last updated. Instead of creating a new "merge commit," Git simply moves the pointer forward, hence the term "fast forward."
Fast forward merge vs. regular merge
Fast-forward merges
Fast-forward merges occur when there is a linear path from the base branch to the target branch, allowing the head of the base branch to be simply moved forward to point to the target branch. The target branch's pointer is moved forward to the head of the source branch if no divergent work has been done on the target branch. This effectively brings the history of the target branch in line with the source branch.
Pros:
- Simpler history: Fast-forward merges keep the repository history linear and clean, which can simplify the understanding and navigation of the history.
- Less overhead: No extra merge commits are created, which can be preferable in small projects or projects with fewer parallel developments.
Cons:
- Loss of context: The major downside is the loss of context regarding the feature's development process. Without a dedicated merge commit, it's harder to see the boundary between different features or to identify when a feature was merged.
- Complicated reverts: Reverting a specific feature becomes more difficult as there's no single merge commit to revert. You would need to individually revert all commits pertaining to that feature.
Use the Graphite CLI to manage Git fast-forward merges
While Git is an incredibly useful tool, it has many shortcomings, particularly with rebasing, and managing stacked pull requests.
The Graphite CLI simplifies git
, handles rebasing automatically, and allows you to create, submit, and stack pull requests right from the command line.
Under the hood, the CLI runs Git to create branches, commits, and metadata, which means you can still use Git in your scripts, tooling, or whenever you feel like it. Read more about installing the Graphite CLI in our docs.
Non-fast-forward merges (--no-ff
)
Using the --no-ff
flag forces a merge commit even when a fast-forward merge would be possible. This approach is preferred in the git-flow mode introduced by Vincent Driessen, for merging feature, release, and hotfix branches back to develop or main branches.
Pros:
- Preserves history: It keeps a clear record of project changes, including the context of feature development and integration.
- Easier to manage features: Features can be collaboratively developed and then cleanly merged as a unit, which also simplifies potential reverts to a single merge commit.
- Facilitates code review and collaboration: The merge commits provide a natural place for code review and discussions about specific features or fixes.
Cons:
- Complex history: This method introduces additional merge commits that can clutter the project history, potentially making it harder to follow.
- More merge conflicts: There is a slightly increased likelihood of encountering merge conflicts that need to be resolved manually, as changes from the base branch are not automatically incorporated into the feature branch during its development.
Examples of git fast forward
Let's go through some common scenarios and commands to understand this better.
Basic fast forward merge
Assume you have two branches: main
and feature
. The feature
branch was created from main
and has new commits, but main
has not changed since feature
was created.
Check out the
main
branch:Terminalgit checkout mainMerge the
feature
branch:Terminalgit merge feature
If a fast forward is possible, you'll see output like:
Updating 4a5b6c7..9d8e7f8Fast-forwardfile.txt | 2 ++1 file changed, 2 insertions(+)
This output shows that the main
branch pointer has moved to the point of the feature
branch.
Disabling fast forward merge
Sometimes, you might want to preserve the exact history of changes, including the fact that a feature branch was created and merged. For this, you can disable the fast forward merge:
git merge --no-ff feature
This forces Git to create a new merge commit even if a fast forward merge is possible, thus preserving the history of a separate branch and merge.
Fast forwarding when pulling
When you pull changes from a remote repository, you can explicitly ask for a fast forward merge:
git pull --ff-only
This command updates your current branch only if the pull can be resolved as a fast forward.
Fast forwarding a local branch
If you want to fast forward your local branch to catch up with changes in another branch (like main
), you can use:
git checkout featuregit merge main
This will fast forward the feature
branch if no divergent changes have been made on feature
.
Checking if fast forward is possible
Before attempting a fast forward merge, you might want to check if it's possible:
git merge-base --is-ancestor main feature
This command returns 0
(true) if main
can be fast forwarded to feature
, and 1
(false) otherwise.
When to use fast forward
The decision between using fast-forward and non-fast-forward merges largely depends on the project's requirements for history visibility and management. For larger, collaborative projects where tracking the development and integration of features separately is crucial, the non-fast-forward approach recommended by the git-flow model is beneficial. It provides explicit markers in the project history that denote the start and end of feature integrations, facilitating easier troubleshooting and version management.
Conversely, for smaller projects or those with a more streamlined development process, fast-forward merges might be preferred for their simplicity and cleaner history. In any case, it's important to choose a strategy that aligns with the team's workflow and project requirements.
Fore more detail on fast forward merging see the official Git documentation.