Is GitLab flow (or GitHub flow, etc) anti build-once deploy-everywhere? Historically, especially in the Java world, build-once, deploy everywhere has been a very big thing for deployments.  Artifacts should be built exactly one time when a release is made and stored somewhere like Nexus or Artifactory where they are immutable and can be deployed to all environments, repeatedly and safely.

GitLab flow, on the other hand, seems to recommend having a branch per environment and deploying to that environment as an event upon doing a merge request to the branch.  E.g. a master -> staging merge runs CI/CD on the staging branch, resulting in a deployment there.  Merging the staging to the production branch does the same in production (with the possibility of forcing a manual agreement to the run).

So, GitLab flow causes us to rebuild our artifacts for every environment rather than build once deploy everywhere.

Does this mean we should totally ditch build-once deploy-everywhere when moving to modern tools like GitLab/GitHub?  Is that a good thing?

I guess we can augment GitLab flow by:


Build artifacts on merge into DEV branch and store in a maven/etc repo.
Do deployment using those artifacts. 
Have merges to staging/prod skip build/test and only do deploy using the same artifacts.


This seems like forcing GitLab/etc to do something against their model though, so I'm thinking its not a good idea.



Note: I also am wondering how building/testing/deploying in every environment separately is possible in some large projects.  E.g. Facebook's presto has like an hour of tests in a maven build (or more)... I wouldn't want my production release taking hours; that's the opposite of modern.

Any thoughts here?
One possible answer could come from the reason for using multiple branches as basis for environments in the first place.

In some organisations (typically for large scale projects and often for historical reasons) it is desired to allow for cherry-picking hot fixes in each environment to limit the amount of changes (thus the risk) picked up in each iteration on that environment. I'd argue that such approach is not really aligned with continuous integration/delivery at the project level (it may be at each of the branch levels). 

In this context the branches will diverge, so build-once, deploy everywhere principle is similarly applicable only at the branch/environment level, it cannot be applied at the project level. The GitHub/GitLab flow could work well in such case.

If, however, there is no cherry-picking between branches and strictly straight/fast-forward merges from upstream branch refpoints are used to propagate changes to the downstream branches/environments then the reason for using multiple branches is IMHO questionable. A single/master branch can be used instead, the environments being implemented simply as different steps/stages in the CI/CD processing pipeline.

The pipeline would be triggered on the branch tags/refpoints from which the original change propagation would be initiated in the multi-branch scenario (ideally for each and every commit).

The build-once, deploy everywhere principle can easily be enforced in this approach, which aligns very well with continuous integration/delivery/deployment at the entire project level. You just need to consider each build as potential release candidate from the very beginning of your pipeline processing.

Note that nothing in this scenario conflicts with using GitLab/GitHub (or any other modern version control system) itself, you just don't have to use all the features they offer ;)