Skip to content

Git pull.rebase vs pull.ff: Differences and Best Practices

Problem Statement

When working with Git, many users encounter confusion between the pull.rebase and pull.ff configuration options. Both settings affect how git pull integrates upstream changes into your local branch:

bash
# Configurations in question
git config pull.rebase false   # Merge (default)
git config pull.ff true        # Allow fast-forward merges

At first glance, these settings appear similar since both can result in fast-forward merges when possible. However, they control fundamentally different aspects of Git's behavior. Using them incorrectly can lead to unexpected merge commits, history pollution, or failed operations.

Understanding the Configuration Options

pull.rebase: Choose Strategy (Merge vs. Rebase)

Controls whether git pull uses a merge or rebase strategy:

bash
# Possible values
false       # Default - performs merge
true        # Rebase local commits on top of fetched changes
merges      # Rebase while preserving merge commits
interactive # Interactive rebase
  • Setting to true will rebase your local commits on top of upstream changes
  • Setting to false enables default merge behavior

pull.ff: Control Merge Behavior

Only applies when pull.rebase=false and specifies how merge commits are created:

bash
# Possible values
true      # Fast-forward when possible, create merge otherwise (default)
false     # Always create merge commit (--no-ff)
only      # Allow only fast-forwards, abort otherwise
  • Acts as the configuration equivalent for --ff, --no-ff, and --ff-only CLI flags
  • If you set pull.rebase, this setting is ignored - no merge occurs

Key Interaction

pull.ff has no effect when pull.rebase is enabled since rebasing rewrites history rather than creating a merge commit. These settings operate on different workflow stages!

Practical Recommendations

bash
# Set default pull behavior to rebase
git config --global pull.rebase true

# For branches where you want to enforce fast-forwardability
git config --global pull.ff only

Workflow Comparison Table

CommandWhen Fast-Forward PossibleWhen Not Fast-Forwardable
pull.rebase=false + pull.ff=trueFast-forwardsCreates merge commit
pull.rebase=false + pull.ff=onlyFast-forwardsAborts operation
pull.rebase=trueRebases local commitsRebases local commits

Anti-Pattern

Avoid mixing strategies without understanding the implications:

bash
# This combination is contradictory and confusing
git config pull.rebase true
git config pull.ff false   # Ignored since rebase is enabled!

Expert Best Practices

When to Use Each Configuration

  1. pull.rebase=true (Recommended)

    • Preferred for feature branches and solo development
    • Keeps history linear and clean
    • Avoids superfluous merge commits
    • Ideal for: Developers working on shared repositories and CI/CD pipelines
  2. pull.ff=only (Specific use cases)

    • Enforces branch compatibility before integration
    • Prevents unintended merge commits
    • Suitable for: Release branches, hotfix branches, and production environments

Advanced Alternative: Manual Fetch Workflow

git-diff
# Instead of git pull, use:
$ git fetch
$ git log --graph --oneline origin/main your-branch
$ git rebase origin/main    # OR
$ git merge origin/main

When to Use Manual Workflow

  • Complex integrations: View changes before integrating
  • History cleanup: Drop/edit commits before rebasing
  • Multiple upstreams: Handle special merge scenarios
  • Troubleshooting: Diagnose integration conflicts

Key Takeaways

  1. pull.rebase defines whether to rebase or merge
  2. pull.ff controls how merges happen (but only if merging)
  3. For clean history: git config --global pull.rebase true
  4. For strict branch control: pull.ff=only
  5. Always consider separating git fetch and git merge/git rebase

Understanding these configuration options helps maintain cleaner Git histories and prevents workflow disruptions. Choose the strategy that aligns with your team's collaboration model and quality standards.