Configurar ramificações de destino para solicitações pull
Serviços de DevOps do Azure
Por padrão, o Azure DevOps sugere a criação de novas solicitações pull em relação à ramificação padrão. Em um repositório com várias ramificações usadas para solicitações pull, os proprietários do repositório podem configurar a lista de ramificações de destino de solicitação 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
na ramificação padrão do repositório.
Este arquivo YAML deve conter uma única lista, intitulada pull_request_targets
, contendo os nomes das ramificações ou prefixos que correspondem às ramificações candidatas.
Por exemplo, considere estes conteúdos:
pull_request_targets:
- main
- release/*
- feature/*
Esta lista de destinos potenciais especifica main
como a ramificação de destino a ser selecionada primeiro, mas se uma ramificação começar com release/
ou feature/
for uma escolha melhor, essa ramificação será escolhida.
Para obter mais diretrizes de solicitação pull e considerações de gerenciamento, consulte Sobre solicitações 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 uma ramificação para o Azure DevOps, sua próxima visita à página Repos pode sugerir a criação de uma solicitação pull dessa ramificação. Este botão "Create New Pull Request" escolhe a ramificação de destino dinamicamente.
Pull URL de solicitação. Quando um usuário navega diretamente para a página de criação de solicitação pull usando um
sourceRef
parâmetro, mas omitindo o parâmetro, otargetRef
Azure DevOps seleciona uma ramificação de destino com base nessa escolha dinâmica.
Há um recurso para as ferramentas de cliente criarem solicitações pull usando essa opção dinâmica, mas esses clientes precisam adicionar um sinal opcional de que o usuário não especificou uma ramificação de destino. Verifique a ferramenta de 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 ramificações candidatas inclua apenas ramificações protegidas por políticas de solicitação pull. É provável que essas ramificações só sejam alteradas ao concluir solicitações pull, o que garante que a posição anterior da ramificação esteja no histórico do primeiro pai da confirmação de ponta. Se uma estratégia de mesclagem for usada, o segundo pai representa as confirmações que estão sendo introduzidas na ramificação de destino ao concluir uma solicitação pull e o primeiro pai é a dica anterior.
Como o Azure DevOps escolhe uma ramificação?
O Git não rastreia metadados sobre a criação de uma filial. 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 baseada no histórico do primeiro pai das ramificações.
Entre as ramificações de destino possíveis, o Azure DevOps seleciona a ramificação cujo histórico do primeiro pai se cruza mais com o histórico do primeiro pai da ramificação 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 amostras pull_request_targets
usada anteriormente, temos três ramos-alvo candidatos, em ordem de prioridade:
main
release/2024-September
feature/targets
O ramo de origem, topic
, é então comparado com esses ramos.
main
cruza comtopic
atB
, deixandoG,I
dentrotopic
e não emmain
.release/2024-September
cruza-se comtopic
ao sairA
B,G,I
etopic
não ao entrar.release/2024-September
feature/targets
cruza comtopic
atG
, deixandoI
dentrotopic
e não emfeature/targets
.
Portanto, neste exemplo, a feature/targets
ramificação é escolhida como a ramificação de destino para uma solicitação pull com topic
como ramificação de origem.
Exemplo: Mesclar confirmações
Em um exemplo mais complicado, em que o feature/targets
ramo foi fundido e main
fundido main
em si mesmo, o histórico de commit tem mais casos a considerar:
,-E---F <-- release/2024-September
/
A---B---C---D---J---K <--- main
\ _/ \
\ / \
`G---H---L--\--M <--- feature/targets
\ \/
\
`I <--- topic
Aqui, o commit D
in representa um momento em main
que feature/targets
foi fundido em main
. Commit M
representa um momento em que main
foi mesclado no feature/targets
. A ligação entre commits M
e J
é desenhada de forma a enfatizar que J
é o segundo progenitor de M
enquanto L
é o primeiro progenitor.
Neste caso, quando você considera a história completa do compromisso, main
e feature/targets
ambos cruzam a história de topic
at G
. No entanto, a história do primeiro pai ainda demonstra uma preferência por feature/targets
.
Quebrando laços
Se duas ramificações tiverem a mesma interseção do histórico do primeiro pai, o pull_request_targets
Azure Devops selecionará a ramificação que aparece anteriormente na lista. Se várias ramificações ainda estiverem empatadas com base na pull_request_targets
lista devido a uma correspondência de prefixo, vence a mais antiga em ordem alfabética.
Esses tipos de vínculos estão mais frequentemente presentes quando novas ramificações candidatas são criadas, como o início de uma nova ramificação de recurso ou a bifurcação de uma ramificação de versão.
,-E---F <-- release/2024-October
/
A---B---C---D <--- main
\
\
`G <--- topic
Neste exemplo, a release/2024-October
ramificação foi criada fora da ramificação depois topic
de main
ter sido ramificada de main
. Embora isso seja intuitivo para um leitor humano, a ordem das main
categorias e release/*
na lista indica a ordem preferencial para o pull_request_targets
Azure DevOps.
E se o Azure DevOps escolher a ramificação de destino errada?
A página de criação de solicitação pull tem um seletor para ajustar a ramificação de destino se a escolha dinâmica não corresponder às expectativas. A ramificação de destino também pode ser ajustada depois que a solicitação pull é criada.
Mais importante, pode ser valioso entender por que a heurística pode estar selecionando o ramo alvo "errado".
Esta heurística baseia-se em algumas suposições sobre como as ramificações de destino e as ramificações de origem foram criadas. Aqui estão algumas razões potenciais pelas quais a heurística não funciona:
As ramificações de destino não são protegidas por políticas de solicitação pull. Se as ramificações de destino podem ser empurradas arbitrariamente, então o histórico do primeiro pai não é um indicador confiável da localização anterior dessa ramificação.
A ramificação de origem foi criada a partir de uma dica anterior de uma ramificação candidata. Se a ramificação de origem escolheu uma confirmação arbitrária no histórico, então não há garantia sobre o primeiro histórico pai do qual dependeu.
A ramificação de origem foi avançada usando
git commit
egit merge
comandos. Comandos comogit reset --hard
ougit rebase
podem alterar o histórico do ramo de maneiras imprevisíveis.
Se você discordar da ramificação de destino escolhida por esta heurística, considere atualizar a escolha 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 na ramificação errada é usar git merge
para trazer a ramificação certa para sua história.
A fusão não altera o histórico do primeiro pai e, portanto, não altera a escolha para a ramificação de destino.
Como posso testar esta 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 das ramificações 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
Neste comando, a HEAD
confirmação é usada como origem e compara o histórico do primeiro pai das ramificações de destino da mesma maneira. Enquanto cada ramificação candidata é listada na saída, a cadeia de caracteres (HEAD)
indica qual das ramificações deve ser usada como ramificação de destino.