Partilhar via


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 mais diretrizes sobre pull requests e considerações de gestão, consulte Sobre pull requests.

Pré-requisitos

Categoria Requerimentos
Acesso ao projeto Membro de um projeto .
Permissões - Ver código em projetos privados: Acesso pelo menos Básico.
- Clone ou contribua para o código em projetos privados: Membro do grupo de segurança Contributors ou permissões correspondentes no projeto.
- Definir permissões de ramo ou repositório: Gerir permissões para o ramo ou repositório.
- Alterar ramificação padrão: Editar políticas e permissões para o repositório.
- Importar um repositório: Membro do grupo de segurança Administradores de Projeto ou com permissão de Criar repositório ao nível do projeto Git definida como Permitir. Para obter mais informações, consulte Definir permissões do repositório Git.
Serviços Repos ativado.
Ferramentas Opcional. Utilize os comandos az repos: Azure DevOps CLI.

Observação

Em projetos públicos, os usuários com acesso Partes Interessadas têm acesso total aos repositórios do Azure, incluindo visualização, clonagem e contribuição para o código.

Categoria Requerimentos
Acesso ao projeto Membro de um projeto .
Permissões - Visualização de código: Pelo menos acesso básico.
- Clone ou contribua para o código: Membro do grupo de segurança Contributors ou com permissões correspondentes no projeto.
Serviços Repos ativado.

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.

  • URL do Pull Request. Quando um utilizador navega diretamente para a página de criação de solicitação de pull usando um parâmetro sourceRef mas omitindo o parâmetro targetRef, o 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 pull requests, o que garante que a posição anterior da ramificação esteja no histórico de primeiro-parent do commit 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 existe uma forma 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 de ancestrais principais 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á commits de fusão. 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 com topic em B, deixando G,I em topic e não em main.
  • release/2024-September cruza-se com topic em A, deixando B,G,I em topic e não em release/2024-September.
  • feature/targets cruza com topic em G, deixando I em topic e não em feature/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

Num exemplo mais complicado, em que o ramo feature/targets foi fundido em main e main foi fundido 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 em main indica um momento onde 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 se considera o histórico completo de commits, main e feature/targets ambos cruzam o histórico de topic em G. No entanto, a história do primeiro progenitor 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 na lista pull_request_targets devido a uma correspondência de prefixo, vence a que vier primeiro em ordem alfabética.

Esses tipos de ligações estão mais frequentemente presentes quando novas ramificações candidatas são criadas, como o início de uma nova ramificação de funcionalidade 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 ramificação release/2024-October foi criada a partir da ramificação main depois de topic ter sido ramificada de main. Embora isso seja intuitivo para um leitor humano, a ordem das categorias main e release/* na lista indica a ordem preferencial para o 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 pull request. 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 um commit arbitrário no histórico, então não há garantia quanto ao histórico do primeiro pai de que dependia.

  • A ramificação de origem foi avançada usando git commit e git merge comandos. Comandos como git reset --hard ou git 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 pai principal e, portanto, não altera a escolha da 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 o histórico de primeiro-pai das ramificações de destino é comparado da mesma forma. 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.

Próximos passos