How to configure fast-forward only pulls`

Greg Foster
Greg Foster
Graphite software engineer


Note

This guide explains this concept in vanilla Git. For Graphite documentation, see our CLI docs.


Fast-forwarding is a type of merge that occurs when the current branch tip is behind its upstream counterpart, meaning there are no divergent commits between the two branches. In such cases, Git simply moves (fast-forwards) the tip of your branch forward to match the upstream branch, as there are no conflicting changes to integrate.

In this guide, we will explore the concept of fast-forward merges and how to configure Git to ensure that pulls are only completed as fast-forwards, using the git config command.

This is the simplest kind of "merge" and does not create a new commit if there is a linear path to the new tip. Fast-forwarding keeps the history linear and easier to follow.

Technically, when you perform a fast-forward merge, Git updates the pointer of your branch to point to the latest commit of the branch you are pulling or merging from. Here’s how it works step-by-step:

  1. Check for new commits: Git checks if there are any new commits on the remote branch that are not in your local branch.
  2. Move the HEAD: If your local branch has no divergent commits, Git moves the HEAD, along with the branch pointer, to point to the latest commit of the remote branch.

This process essentially "fast-forwards" your local branch to catch up with its remote counterpart.

To configure Git to only allow fast-forward merges when performing git pull, use the following command:

Terminal
git config pull.ff only

This command sets the pull strategy for your repository to fast-forward only, avoiding any merge commits during a pull if the pull can only be resolved as a fast-forward.

If you want to apply this configuration only to a specific repository, navigate to your repository directory and use:

Terminal
git config --local pull.ff only

The --local flag applies the configuration only to the current repository.

To apply the fast-forward only configuration globally to all your Git repositories, use:

Terminal
git config --global pull.ff only

This setting ensures that any git pull operation in any of your projects will default to fast-forward only, preventing Git from creating a merge commit.

If you need to disable this setting for a project where merging strategies might require actual merges (creating a new merge commit), you can disable it by setting the configuration to false:

Terminal
git config --local pull.ff false
  • Enforcing no-fast-forward merges: For scenarios where you want to ensure that every merge creates a commit, useful for preserving information about the timing of an integration, use:

    Terminal
    git config --local merge.ff false

Fast-forward merges are especially useful when you want to maintain a clean, linear project history without merge commits. This can be helpful in contexts such as:

  • Multiple feature branches that are frequently updated from a main development branch but need to maintain a straightforward history for review.
  • Individual workflows where a single developer updates their local repository with changes from a central repo without needing the overhead of merge commits.
  1. Loss of historical context: The primary downside of fast-forward merges highlighted in the article is the loss of historical information about the existence of a feature branch. When a fast-forward merge is performed, it can make the project history appear as if changes were made directly to the base branch, obscuring the group of commits that collectively added the feature. This linear history lacks the visual representation of branch points and merges, making it more difficult to understand the flow of changes in the project.

  2. Difficult to revert features: Since fast-forward merges do not create a merge commit, reverting a whole feature (i.e., a group of commits) becomes more complex. If the need arises to remove a feature due to issues found in production, having a merge commit makes it straightforward to revert all related changes. Without a merge commit, you would need to manually identify and revert each commit associated with the feature, which can be error-prone and time-consuming. You can also mitigate these issues by using a squash and merge strategy.

  3. Complicated historical analysis: The absence of merge commits also complicates the process of analyzing history for auditing or debugging purposes. Merge commits provide clear checkpoints in the project history that can be quickly identified and inspected. These checkpoints are beneficial when assessing when certain changes were integrated into the main development or production branches.

  4. Merge conflicts management: In the git-flow model, non-fast-forward merges (using the --no-ff option) create a new commit even if a fast-forward merge is possible. This approach ensures that all changes from the feature branch are grouped together in the history. It can also help in managing merge conflicts more transparently. With fast-forward merges, if conflicts arise frequently, they might be harder to track and resolve since the feature's isolation in the branch is lost.

For more information on the differences between different merging strategies see the official Git documentation.

Graphite
Git stacked on GitHub

Stacked pull requests are easier to read, easier to write, and easier to manage.
Teams that stack ship better software, faster.

Or install our CLI.
Product Screenshot 1
Product Screenshot 2