DEV Community

Cover image for Fast-Forward-Only Merges in GitHub Actions: A Safer Way to Sync Branches
Riddhi Jathar
Riddhi Jathar

Posted on

Fast-Forward-Only Merges in GitHub Actions: A Safer Way to Sync Branches

The problem

We maintain a repo with two long-lived branches, master and main, that need to stay in sync. The manual routine was: checkout locally, pull both, merge, hope nothing conflicts, push. Every time. Repetitive, and one distracted moment away from a messy merge commit or a conflict resolution you didn't mean to make.
A co-maintainer on this repo set up a GitHub Action to handle it instead. I just liked it enough to write about it.

The workflow

name: Manual Fast-Forward Master to Main
on:
  workflow_dispatch:
jobs:
  merge-branches:
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - name: Checkout Code
        uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Configure Git Identity
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
      - name: Attempt Fast-Forward Merge
        id: git_merge
        run: |
          git fetch origin main
          git fetch origin master

          git checkout main

          if ! git merge origin/master --ff-only; then
            echo "::error::Cannot fast-forward! Histories have diverged or conflicts exist. Aborting."
            exit 1
          fi
      - name: Push Changes
        run: |
          git push origin main
Enter fullscreen mode Exit fullscreen mode

workflow_dispatch means this only runs when someone manually clicks "Run workflow" in the Actions tab, no accidental triggers on push or schedule. Click it, and the job:

Checks out the full history (fetch-depth: 0 needed so the merge actually has both branches' history to compare)
Checks out main
Tries git merge origin/master --ff-only
Pushes if it worked

Why --ff-only is the part worth understanding
A regular git merge will happily create a merge commit, or ask you to resolve conflicts, or in some configs auto-resolve things in ways you didn't explicitly review. --ff-only refuses all of that. It only allows the merge if main hasn't diverged from master at all, meaning main can just "fast-forward" its pointer forward to match, with no new commit and no ambiguity about what changed.
If the branches have diverged, the flag makes git fail instead of guessing. That's the whole safety net. The workflow catches that failure explicitly (if ! git merge ... ; then echo "::error::..."; exit 1; fi) so it shows up loud and clear in the Actions log instead of silently pushing something wrong.
That's the actual lesson here: automating a merge is easy. Automating it so that it fails safely instead of doing something unintended, that's the part worth copying into your own workflows.

Is this novel?

No, and worth being upfront about that. workflow_dispatch has existed since GitHub introduced it in 2020, and fast-forward-only merges are just core git behavior. This isn't a new invention, it's a small, well-known pattern for anyone who's automated branch syncing or release promotion with Actions.
But it's a good example of a broader habit worth building: find the repetitive manual git step you don't fully trust yourself to do carefully every single time, and hand it to a machine that does the exact same safe thing, consistently, with a paper trail.

Top comments (0)