Chef code version control

At the moment my team and I just use a simple knife cookbook upload command from our workstation to push updated cookbooks to our chef infra server. We do too much back and forth with each other to ensure we don't step on each others toes and overwrite our code. Its possible we could be working on the same cookbook and we're constantly pushing to our chef infra server to test new automated pipelines. There has to be a better way.
Gitlab of course has version control where you can push to git and if there is a newer version of the code it prompts you first. Or you can check out code so no-one else can overwrite what you have accomplished.
We're looking for a way to properly merge chef cookbooks and recipes, check-in and check-out code, versioning, etc. When its time to push to master it somehow updates the chef infra server with the new cookbook version.
I have seen how developers use gitlab for their cookbook development and that would work perfect but I am not seeing where or how gitlab then update the chef infra server with the new policy cookbooks.
Any help would be great.

Test with chef-zero and a git repo. After the git repo passes testing, only then push the updated recipe to the server.

This injects another manual process and we have thought about this. If this is the only option, we'll have to manage. I was just hoping Chef had a more robust built-in version control system between developers.

You can of course make your own to handle the cookbook code on any version control system you like and with any CI tool you like. That's a matter of having a job in your CI pipeline to upload the cookbook to the chef server and is a recomended way to do it.

I'd say that's no more the chef-server role to handle conflicts than it is artifactory or nexus role to handle code conflicts when you upload an artifact. However to avoid overwritting a cookbook version knife can be configured to freeze the cookbook version (or you can use --freeze option in the upload command).