Articles/Git/GitHub Flow: Keep Your Main Branch Deployable

GitHub Flow: Keep Your Main Branch Deployable

GitHub Flow is the lightweight branching workflow built on a single rule: anything in main is deployable. Here is the whole loop, branch, pull request, review, merge and deploy, with the git and gh commands and an honest look at where it fits.

June 14, 2026·7 min read

If Git Flow is the structured, ceremony-heavy end of the branching spectrum, GitHub Flow is the opposite. It throws out the long-lived branches and release windows and runs on one rule: anything in main is deployable. Everything else follows from that. If you want the head to head, I wrote a Git Flow vs GitHub Flow comparison; this post is the hands-on deep dive into GitHub Flow itself.

The one rule that drives everything

GitHub Flow has exactly one promise: whatever is on main right now could be deployed to production this second without a second thought. That single constraint is what makes the rest of the workflow so light. There is no develop branch collecting work, no release branch to harden, no version window to wait for. There is main, and there are short-lived branches that become main once they pass review.

The trade you are making is honest and worth saying out loud. You get speed and simplicity, and you give up the ability to maintain several released versions at once. For a web app or a service, where the only version that matters is whatever is live, that is a great deal. For shrink-wrapped software that has to support v1 and v2 in the field, it is not, and that is where Git Flow earns its structure instead.

The loop, step by step

GitHub's own docs describe GitHub Flow as a lightweight, branch-based workflow, and lay it out in six steps:

  1. Create a branch off main with a short, descriptive name.
  2. Make changes as small, complete commits, pushing as you go.
  3. Open a pull request describing what changed and why.
  4. Address review feedback by pushing more commits to the same branch.
  5. Merge the pull request once it is approved and checks pass.
  6. Delete the branch, since its work now lives in main.

You will notice "deploy" is not its own numbered step in the modern docs. That is because deployability is baked into the philosophy rather than bolted on at the end. Scott Chacon's original 2011 description of GitHub Flow was more explicit about it: once something is merged into main, you can and should deploy it immediately. Either way, the mental model is the same: branches are temporary, main is always ready, and shipping is the easy part.

The command walkthrough

Here is one full trip around the loop in the terminal. I will use the GitHub CLI (gh) for the pull request bits, but you can do all of it from the web UI too.

BASH
# Start from an up-to-date main
git checkout main
git pull origin main

# Create a descriptively named branch for the change
git switch -c increase-test-timeout

# Make an isolated, complete change and commit it
git add .
git commit -m "Increase CI timeout so flaky integration tests stop failing"

# Push the branch and set it to track the remote
git push -u origin increase-test-timeout

# Open a pull request
gh pr create --title "Increase test timeout" \
  --body "Bumps the CI timeout so flaky integration tests stop failing. Closes #123"

After review, merge and clean up in one command.

BASH
gh pr merge --squash --delete-branch

That is the entire workflow. Branch, commit, push, PR, merge, delete. Because main is shippable the moment that PR lands, you deploy right after.

Branch names and commits that do not make you wince

Two small habits keep GitHub Flow pleasant. First, name branches for what they do. increase-test-timeout and add-code-of-conduct tell your teammates what is in flight at a glance; fix and wip do not. Second, keep each commit to a single, complete change with a message that says what it does. Small commits are easy to review and trivial to revert when something slips through. You are not writing a novel, you are leaving a trail the next person (often future you) can follow.

Pull requests are the checkpoint

The pull request is the heart of GitHub Flow, and it is more than a merge button. It is where the change gets explained, reviewed, and discussed. A good PR description says what changed and what problem it solves, links the issue it closes with a keyword like Closes #123 so the issue closes automatically on merge, and pulls in the right reviewers with an @mention or a review request.

This is also where your automation does its job. Branch protection rules can require a passing CI run and at least one approval before the merge button lights up, which is what lets you trust the "main is always deployable" promise in the first place. The PR is your quality gate; treat it like one.

Keeping your branch fresh

Because branches are short-lived, they rarely drift far from main. When one does, you bring main into it before merging.

BASH
git fetch origin
git merge origin/main      # safe on shared branches
# or, on a branch only you have touched:
git rebase origin/main     # cleaner, linear history

Merge is the safe choice on anything someone else might have pulled. Rebase gives you tidy history but rewrites commits, so save it for branches that are yours alone. Resolve any conflicts here, on your branch, not on main.

Deploy on merge, or deploy before merge?

There is one honest debate worth knowing about. Chacon's original flow says merge into main, then deploy immediately. Plenty of modern teams flip that: they deploy the branch to a staging or preview environment and validate it live before merging, so main only ever receives code that has already proven itself in production-like conditions. GitHub's own branch-deploy style works this way.

Neither is wrong. Deploy-on-merge is simpler and keeps the loop tight. Deploy-before-merge gives you a real safety net at the cost of more tooling. Pick based on how much you trust your tests and how expensive a bad deploy is for you.

Hotfixes are just normal branches

Here is the payoff of all this simplicity. In Git Flow, an emergency fix means a dedicated hotfix/* branch off main, merged back into two places and tagged. In GitHub Flow, a hotfix is just a normal short branch off main that jumps to the front of the review queue.

BASH
git switch -c hotfix-login-null-check main
git commit -am "Add null check on the login handler"
git push -u origin hotfix-login-null-check
gh pr create --fill && gh pr merge --squash --delete-branch

Same loop, same main, just faster. There is nothing special to learn because there is nothing special about it.

Where it fits, and where it strains

GitHub Flow is a great fit for web apps, services, and SaaS, anywhere there is really only one live version and you deploy often. It is friendly to continuous integration because you are constantly merging small changes instead of nursing a giant branch toward a release.

Two places it strains. It has no clean home for maintaining multiple released versions at once, so if customers stay on old releases you will want Git Flow's release branches instead. And "main is always deployable" is only true if your tests and pipeline actually enforce it; without solid CI, that promise is wishful thinking.

It is worth knowing GitHub Flow's close relative, trunk-based development, which goes one step further: everyone integrates into main constantly, branches live for hours, and anything unfinished hides behind a feature flag. You can think of GitHub Flow as the comfortable middle ground, trunk-based development with pull requests and short feature branches still giving you a natural review checkpoint.

Wrapping up

GitHub Flow really does come down to that one rule: keep main deployable, and let short branches and pull requests carry everything else. If you ship a web app and deploy continuously, start here. If you ship versioned software with multiple releases to support, read the Git Flow deep dive instead, and if you are still deciding between them, my comparison article lays out exactly how to choose.