Enforcing two branches have linear history + the same commits

I have two realms - a “dev” realm and a “prod” realm. I have configured the CI so that pushes to the the “main” branch deploy to “dev”, and pushes to the “prod” branch deploy to “prod”. So far so good.

I’d like the commits on these two branches to stay in sync. For example, if the latest commits on the main branch are A, B, C, D, and E. The production branch should have the same commits, but optionally it might be behind the main branch, so production might have commits C, D, and E.

We get into trouble when people who are not familiar with Git create PR’s to merge main to prod, which rewrites the commits, or create commits with merge bubbles, which then create commits that only exist on the production branch.

I turned on branch protection, which prevents force pushes to either main or prod branches, in the hopes of requiring a linear history, and preventing merge commits from being pushed. But it doesn’t seem to prevent the issues that I’ve been seeing with people on my team.

Right now I am asking folks to just use the command line to do:

git checkout prod
git merge --ff-only main
git push origin prod

to deploy to prod. Are there automated tools or merge strategies I can deploy to help protect/encourage this workflow?

I suppose I could create a bot that handles production deploys, but that seems like a lot of work.

1 Like

You should look at branch protection and disabling merge commits:

There’s also an auto-merge feature.

But, I suspect you’re going to want a merge bot to manage things.

Your requirements are basically that prod <= main, and there should be no merge commits.

It feels like you want to entirely lock prod and just have a workflow that promotes commits from main to prod.

That should be fairly easy to write.

have a workflow that promotes commits from main to prod .

Can you describe what you mean here? Is this something I can do with Actions or some other Github feature, or would I need to do this myself.

Fwiw GitHub actions and workflows are often used synonymously, but technically, this is more of a workflow thing than an action. (Unless you have lots of repositories that need the same behavior, in which case you could package your code into a reusable action.)

I think any of:

on:
  label:
    type: created
  push:
    tags: promote
  workflow_dispatch:

(_syntax not validated, this is to give a rough idea of events you could use, I’d pick one. Personally I’m leaning toward the tags one.)

As long as you can have an event with a repository write token responding only to authorized users, and a way for it to recognize the intended commit for promotion.

You’d just do a bit of checking with git to ensure your linearity requirements are met, and possibly some checks with gh to ensure that checks for the commit are passing (assuming you care, I would), then just git branch main $SHA and git push origin main (no force, you want to fail if it’s divergent from main).

If you go with a promote tag, then upon promoting, you might have the same workflow forcibly delete the tag. You might not, since you want the tag to push forward linearly, maybe keeping it around is just as good.

comment written using swipe on a phone