Parece que você tem alguns problemas aqui:
1. Identificando recursos para uma liberação específica
Este é um problema de gerenciamento de projetos e um problema de coordenação. Será que este recurso ser liberado antes, ao mesmo tempo que, ou após este outro recurso? Se as liberações quiserem um recurso por vez, identifique-o. Se os recursos forem agrupados em lançamentos, descubra quais são os agrupamentos e aplique-os aos desenvolvedores e aos tomadores de decisão. Use seu sistema de rastreamento ou emissão de tickets para marcar lançamentos. Deixe claro que, se um dos recursos de uma versão específica não for possível, todos eles serão.
2. Estratégias de ramificação
Git-flow é a resposta fácil para questões como essas, e muitas vezes as pessoas usam uma variante do git-flow, mesmo que não saibam o que é. Não vou dizer que é um problema para todos os problemas, mas ajuda muito.
Parece que você está enfrentando um problema com estratégias de lançamento não determinísticas, em que os recursos são aprovados em dispersão e algo que iniciou o desenvolvimento há muito tempo pode ser lançado depois de algo iniciado mais recentemente - recursos de salto em distância.
Ramificações de recursos de longa duração ou ramificações de versão simultânea são provavelmente a melhor resposta para esses tipos de problemas. Mesclar (ou refazer, se você estiver confortável com isso) o mais recente do mestre em seus ramos de longa duração. Cuidado para mesclar apenas os recursos que já estão ativos, caso contrário, você encontrará os problemas que está enfrentando agora (muitos recursos misturados em uma ramificação).
As ramificações "Hotfix" ou "bugfix" são uma parte essencial desse processo; use-os para pequenas correções pontuais que possuem um ciclo curto de controle de qualidade.
Pela sua descrição, talvez seja melhor não manter um ramo de 'desenvolvimento' oficial. Em vez disso, ramifique todos os recursos do mestre e crie ramificações de release mescladas assim que um release for identificado.
3. Ambientes
Não combine as ramificações git com seus ambientes, exceto a produção == master. O ramo 'desenvolvimento' deve ser considerado quebrado. As ramificações de liberação são enviadas para ambientes de teste, seja um ambiente de controle de qualidade ou um ambiente de preparação. Se necessário, envie uma ramificação de recurso específico para um ambiente.
Se você possui mais de uma ramificação de recursos que precisam ser liberadas separadamente, mas estão sendo testadas ao mesmo tempo ..... ¯ \ _ (ツ) _ / ¯ .... gerencie outro servidor? Talvez junte-os em uma ramificação descartável ... confirme correções / alterações nas ramificações originais e junte novamente na ramificação descartável; faça a aprovação final e o UAT em ramificações de liberação individuais.
4. Removendo recursos não aprovados de uma ramificação
É isso que os pensamentos acima estão tentando evitar, porque essa é sem dúvida a coisa mais dolorosa a se fazer. Se você tiver sorte, os recursos foram mesclados em suas ramificações de desenvolvimento ou teste atomicamente usando confirmações de mesclagem. Se você não tiver sorte, os desenvolvedores se comprometeram diretamente com o ramo de desenvolvimento / teste.
De qualquer forma, se você estiver se preparando para uma liberação e tiver alterações não aprovadas, precisará usar o Git para recuperar as confirmações não aprovadas do ramo de liberação; a melhor idéia é fazer isso antes de testar o lançamento.
Boa sorte.