Compartilhar via


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 o targetRef 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 com topic at B, deixando G,I em topic e não em main.
  • release/2024-September cruza com topic at A deixando B,G,I em topic e não em release/2024-September.
  • feature/targets cruza com topic at G, deixando I em topic e não em feature/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 e git merge . Comandos como git reset --hard ou git 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.

Próximas etapas