Configurar branches de destino para solicitações de pull
Azure DevOps Services
Por padrão, o Azure DevOps sugere a criação de novas solicitações de pull no branch padrão. Em um repositório com várias ramificações usadas para solicitações de pull, os proprietários do repositório podem configurar a lista de ramificações de destino da solicitação de pull para que essas sugestões selecionem a ramificação de destino adequada.
Para habilitar esse recurso, crie um arquivo com nome .azuredevops/pull_request_targets.yml
no branch padrão do repositório.
Esse arquivo YAML deve conter uma única lista, intitulada pull_request_targets
, contendo os nomes ou prefixos de ramificação que correspondem às ramificações candidatas.
Por exemplo, considere estes conteúdos:
pull_request_targets:
- main
- release/*
- feature/*
Essa lista de destinos potenciais especifica main
como o branch de destino a ser selecionado primeiro, mas se um branch começando com release/
ou feature/
for uma opção melhor, esse branch será escolhido.
Para obter mais diretrizes de solicitação de pull e considerações de gerenciamento, consulte Sobre solicitações de pull.
Quando essa configuração é usada?
Há vários pontos de entrada para usar uma ramificação de destino dinâmica.
Sugestões de solicitação de pull. Quando um usuário envia um branch por push para Azure DevOps, sua próxima visita à página Repos pode sugerir a criação de uma solicitação de pull desse branch. Este botão "Criar nova solicitação de pull" escolhe o branch de destino dinamicamente.
URL da solicitação de pull. Quando um usuário navega diretamente para a página de criação de solicitação de pull usando um
sourceRef
parâmetro, mas omitindo otargetRef
parâmetro, o Azure DevOps seleciona um branch de destino com base nessa escolha dinâmica.
Há uma capacidade para as ferramentas de cliente criarem solicitações de pull usando essa opção dinâmica, mas esses clientes precisam adicionar um sinal opcional de que o usuário não especificou um branch de destino. Verifique a ferramenta do cliente de sua escolha para ver se a opção está ativada.
Quais são os bons candidatos para alvos de filiais?
Recomendamos que a lista configurada de branches candidatos inclua apenas branches protegidos por políticas de solicitação de pull. Essas ramificações provavelmente só são alteradas com a conclusão de solicitações de pull, o que garante que a posição anterior da ramificação esteja no histórico do primeiro pai da confirmação de dica. Se uma estratégia de mesclagem for usada, o segundo pai representará os commits que estão sendo introduzidos no branch de destino concluindo uma solicitação de pull e o primeiro pai será a dica anterior.
Como o Azure DevOps escolhe um branch?
O Git não rastreia metadados em torno da criação de uma ramificação. Não há uma maneira exata de determinar qual ramificação foi usada ao criar uma ramificação de tópico. Em vez disso, o Azure DevOps usa uma heurística com base no histórico do primeiro pai das ramificações.
Entre os possíveis branches de destino, o Azure DevOps seleciona o branch cujo histórico do primeiro pai faz a maior interseção com o histórico do primeiro pai do branch de origem.
Exemplo: sem confirmações de mesclagem
Considere a seguinte estrutura de ramificação, que é simplificada mais do que o normal, pois não há confirmações de mesclagem. Neste exemplo, todo o histórico é representado pelo histórico do primeiro pai.
,-E---F <-- release/2024-September
/
A---B---C---D <--- main
\
`-G---H <--- feature/targets
\
`-I <--- topic
Com esse histórico e a lista de exemplos pull_request_targets
usada anteriormente, temos três ramificações de destino candidatas, em ordem de prioridade:
main
release/2024-September
feature/targets
O ramo de origem, topic
, é então comparado a esses ramos.
main
cruza comtopic
atB
, deixandoG,I
emtopic
e não emmain
.release/2024-September
cruza comtopic
atA
deixandoB,G,I
emtopic
e não emrelease/2024-September
.feature/targets
cruza comtopic
atG
, deixandoI
emtopic
e não emfeature/targets
.
Portanto, neste exemplo, o feature/targets
branch é escolhido como o branch de destino para uma solicitação de pull com topic
o branch de origem.
Exemplo: mesclar confirmações
Em um exemplo mais complicado, onde o branch foi mesclado feature/targets
main
e mesclado main
em si mesmo, o histórico de commits tem mais casos a serem considerados:
,-E---F <-- release/2024-September
/
A---B---C---D---J---K <--- main
\ _/ \
\ / \
`G---H---L--\--M <--- feature/targets
\ \/
\
`I <--- topic
Aqui, o commit D
em main
representa um momento em que feature/targets
foi mesclado em main
. Commit M
representa um momento em que main
foi mesclado em feature/targets
. A ligação entre commits M
e J
é desenhada de forma a enfatizar que J
é o segundo pai de M
while L
é o primeiro pai.
Nesse caso, quando você considera o histórico main
de confirmação completo e feature/targets
ambos cruzam o histórico de topic
at G
. No entanto, o primeiro histórico pai ainda demonstra uma preferência por feature/targets
.
Rompendo laços
Se duas ramificações tiverem a mesma interseção de histórico do primeiro pai, o Azure DevOps selecionará a ramificação que aparece anteriormente na pull_request_targets
lista. Se várias ramificações ainda estiverem empatadas com base na lista devido a uma correspondência de prefixo pull_request_targets
, a mais antiga em ordem alfabética vencerá.
Esses tipos de vínculos estão presentes com mais frequência quando novas ramificações candidatas são criadas, como o início de uma nova ramificação de recursos ou a bifurcação de uma ramificação de lançamento.
,-E---F <-- release/2024-October
/
A---B---C---D <--- main
\
\
`G <--- topic
Neste exemplo, a ramificação release/2024-October
foi criada a partir da ramificação main
depois topic
de ter sido ramificada a partir de main
. Embora isso seja intuitivo para um leitor humano, a main
ordem das categorias e release/*
na pull_request_targets
lista indica a ordem preferencial para Azure DevOps.
E se o Azure DevOps escolher o branch de destino errado?
A página de criação de solicitação de pull tem um seletor para ajustar o branch de destino se a opção dinâmica não corresponder às expectativas. O branch de destino também pode ser ajustado após a criação da solicitação de pull.
Mais importante, pode ser valioso entender por que a heurística pode estar selecionando o ramo-alvo "errado".
Essa heurística se baseia em algumas suposições sobre como as ramificações de destino e a ramificação de origem foram criadas. Aqui estão algumas razões potenciais pelas quais a heurística não funciona:
Os branches de destino não são protegidos por políticas de solicitação de pull. Se as ramificações de destino puderem ser enviadas arbitrariamente, o histórico do primeiro pai não será um indicador confiável do local anterior dessa ramificação.
O branch de origem foi criado a partir de uma ponta anterior de um branch candidato. Se o branch de origem escolheu um commit arbitrário no histórico, não há garantia sobre o primeiro histórico pai do qual ele dependia.
O branch de origem foi avançado usando
git commit
comandos egit merge
. Comandos comogit reset --hard
ougit rebase
podem alterar o histórico da ramificação de maneiras imprevisíveis.
Se você discordar do branch de destino escolhido por essa heurística, considere atualizar a opção usando git rebase --onto <new-target> <old-target> <source>
. O git rebase
comando reescreve o histórico do primeiro pai para fazer com que a heurística escolha o novo destino.
Um erro comum que os usuários cometem ao perceber que estão baseados no ramo errado é usar git merge
para trazer o ramo certo para seu histórico.
A mesclagem não altera o histórico do primeiro pai e, portanto, não altera a escolha do branch de destino.
Como posso testar essa decisão localmente?
A heurística usada pelo Azure DevOps foi contribuída para o cliente Git principal e está disponível nas versões 2.47.0 e posteriores do Git.
Para testar essa lógica em seu próprio repositório, primeiro execute git fetch origin
para garantir que você tenha a versão mais recente dos branches de destino. Em seguida, execute o seguinte git for-each-ref
comando, ajustado para corresponder à sua lista de ramificações candidatas:
$ git for-each-ref --format="%(is-base:HEAD) %(refname)" \
refs/remotes/origin/main \
"refs/remotes/origin/release/*" \
"refs/remotes/origin/feature/*"
refs/remotes/origin/main
refs/remotes/origin/release/2024-September
(HEAD) refs/remotes/origin/feature/targets
Nesse comando, o HEAD
commit é usado como a origem e compara o histórico do primeiro pai das ramificações de destino da mesma maneira. Embora cada branch candidato esteja listado na saída, a cadeia de caracteres (HEAD)
indica qual dos branches deve ser usado como branch de destino.