Custom Git Workflow with different environments?

Viewed 642

My question is a theoretical/procedural one. I am trying to figure out/build a custom Git Workflow (not to be confused with Git Flow) that works well for our organization.

We're using GitLab (but this is not that important) and have the following 3 long-living branches:

  • development (latest stable codebase)
  • staging (auto deploys to staging server)
  • master (auto deploys to production server)

The development, staging and master branches are protected, meaning that the developers can only merge to them, but can't push. Also, during the merging, rebase (only FF) and squash-merge are enforced for a cleaner Git log.

For every feature/bugfix, a new feature-branch gets created, based on development and merged back to the respective branches when ready.

But here is the problem, we want to have good control of what gets merged into the 3 long-living branches. For example, just because some functionality is developed and merged with development, doesn't mean we want it in master, which turns out to be hard to achieve, at least from my perspective.

Here is an example scenario:

  • A developer creates a feature/store branch, based on development, and completes it over time
  • They rebase it to development and merge it to development and staging
  • After that a new feature development starts named feature/add-footer-menu. This branch is based on development too and once completed, they merge it to development, staging and master, because it needs to go live immediately

The tricky part is that this way the changes from feature/store go live too, and we don't want that. The only workaround to this is to work exclusively with cherry-picks and cherry-pick only the commits we want to merge with staging and master. This probably will work, but is an overkill in my opinion. Is there an easier flow to achieve this?

The main goal is to have good control over what goes live. Usually development and staging will have the same commits, but only specific features need to go to master.

Also, one more thing. If we do the above, this means that if we want to have a feature branch merged into the 3 long living branches, this means we need to have the respective feature branches, so we could rebase and merge them. 3 long-living branches = 3 short-lived feature branches, just for the merging. Without being a Git expert, this just doesn't look right.

Please share your thoughts and suggestions. Thank you!

1 Answers

I would recommend you consider the workflow that the maintainers of Git use, which is called gitworkflows. (Sometimes it's also called gitworkflow; singular without the 's'.) Additional reading here.

I'm basing this recommendation on the requirement:

Usually development and staging will have the same commits, but only specific features need to go to master.

Essentially you have two levels of integration branches before you decide to complete your feature branch PRs into master.

Possible tweaks to your workflow:

  1. Treat your development branch (or actually rename it) as either pu (proposed updates) or seen (which is what they are calling it now). This is the first level of integration testing.
  2. Treat your staging branch (or actually rename it) as next. This is your hardened integration branch for deployment to your staging system.
  3. Developers should branch off of master instead of development (or seen).
  4. Start thinking of your development and staging branches as throwaway branches that will be reset to master periodically. If you don't do this, you'll eventually end up with a lot of unmerged code polluting your test environments. At my company we reset the next branch every Sunday, and sometimes more often than that, particularly when we're considering reverting a reverted PR.

Considerations:

  1. What do you actually do with your development branch? If the answer was nothing (it's not deployed anywhere) and was previously only used for a branching point for developers to use, maybe you can just delete it. Then branch off of master and test by merging into staging.
  2. Regarding your question of rebasing and merging feature branches onto each of the target branches, you no longer need to do that for development and staging. The reason is a clean history isn't necessary for throwaway branches. You would still want to rebase onto the latest master though, and your final test in staging would either already have the latest master if it was recently reset, or your PR into staging could include those new commits from master so you can test your integration with them.

Final thought:

Branching strategies are rarely a one size fits all. Inevitably you may want to use parts of different workflows that make sense for your repo and your team. As an example, some of the teams at my company use a slightly modified Git Flow in conjunction with gitworkflows. We have a next branch that is the pre-cursor to our develop branch so we can do some integration testing before code gets into develop. The reason is that in Git Flow, all code that lands in develop eventually works its way into master and goes to production, so it gives us that extra sanity check. Some people think Git Flow is too complex and we've made it arguably even more complex, but it works great for us.

Related