With the issue you're talking about, that's why we have staging environments. If you're going to release A and then B, you should be staging A, and then staging A+B. It's true that if they had ZERO idea on what the other were doing, they could step on each other's toes. But it will get caught before release. And hopefully there's enough communication to at least have a vague idea of who's working on the same parts of the code as you. If you're designing things that span large parts of the codebase without consulting or warning teammates, you have bigger problems.
Without distinct feature branches, you end up in abysmal horror situations where you push something, realize you have a bug in production, but can't roll it back without rolling N other features back. Then you start hacking in code to turn the feature off temporarily, etc, which rapidly turns into a mess.
I'm thinking about the scenario where you create a branch to do some dev work. It takes a week or so, during which, other commits are happening on master. Probably at multiple points during your week of dev work, you are going to want to pull in updates from master to make sure you don't hit conflicts or run into issues that weren't found until the day you try to merge your final work.
It sounds like you are saying that every time you want to update, you'd create a new integration branch of your work + master and then switch to that for further work until you are finally ready to commit to master? That feels a bit unwieldy..
Yes, you can catch the problem in staging, but you might have caught it before that if you had merged earlier.
> Without distinct feature branches, you end up in abysmal horror situations where you push something, realize you have a bug in production, but can't roll it back without rolling N other features back.
I don't think having a dev branch in an unshippable state is an abysmal horror situation. And even if you use feature branches for everything, that does not mean you can necessarily roll back the commits easily.
Do the developers of feature A and B push their respective feature branches to a repo in the staging environment where they are merged in some local integration branch there? Logistically, who does the merging? Is it this integration branch that is then merged into mainline?
And in an open-source community, as you rightly point out, nobody wants to do the dirty work. And merging is as dirty as it gets.
Surely this is a little overly pedantic? The point is that you want developers A and B to work on code bases that are as close to each other as possible, so that any problem in the interaction between these developers' work is caught early. Your project doesn't need to be completed in a day or two, you just need to accept that you have a dev branch which isn't always in a shippable state (which I think is usually unproblematic).
Instead, A and B should be on separate branches. Maintain integration environments where the feature branches are regularly merged together when each gets to the level of doneness that environment represents. The final step is to get promoted to master-candidate, where you are going to launch tomorrow unless we find a problem. If things break there, blow that away and recreate it from master, and fix your problems one integration environment lower.
In those cases, you have to fix the code base, and git wont help you. In my experience, it is much less common to have code that needs to be removed than to have bugs that were introduced because the code bases were synced too late. How much of a problem this is depends on how flexible your release cycle is.