Skip to content
This page has been auto-translated and may contain errors.View in English

O fluxo de pull request

docs.scrimba.com

Você esteve trabalhando em uma funcionalidade em seu próprio branch e ela está pronta. O projeto é compartilhado: outras pessoas também fazem commits nele, então você não faz push direto para main e espera pelo melhor. Você quer que a alteração seja revisada, discutida se necessário, e integrada de uma forma que o resto do time possa ver. Todo esse caminho, desde um branch em sua máquina até o código chegar em main, é o fluxo de pull request, e é assim que quase todos os times no GitHub fazem mudanças. O lado do Git disso usa apenas comandos dos capítulos anteriores, um branch, um commit e um push:

bash
$ git switch -c add-five-day-forecast
Switched to a new branch 'add-five-day-forecast'
$ git add src/forecast.js
$ git commit -m "Add five-day forecast panel"
$ git push -u origin add-five-day-forecast
Branch 'add-five-day-forecast' set up to track 'origin/add-five-day-forecast'.

Esse push envia seu branch para o GitHub. Nada foi integrado ainda, e nada foi sequer proposto para revisão. O próximo passo, abrir o pull request, acontece no site do GitHub.

O que acontece quando você abre um pull request

No GitHub, após um push como o acima, você geralmente verá um banner oferecendo para comparar seu novo branch contra main. Clique nele, escreva um título e uma breve descrição do que mudou e por quê, e abra a página que ele cria. Essa página é um pull request, frequentemente abreviado como PR: uma solicitação para integrar um branch em outro, com uma conversa em andamento anexada a ele.

Um pull request propõe um merge e espera aprovação. Alguém, talvez você, talvez um colega de time, lê a mudança, deixa comentários, e apenas faz merge uma vez que parece certo. Até que isso aconteça, seu branch e main permanecem exatamente como eram antes de você abrir a página.

Você não precisa esperar até que uma funcionalidade esteja terminada para abrir o PR. Muitos times abrem um mais cedo e o marcam como rascunho, o que sinaliza "ainda não pronto para revisão" enquanto ainda oferece um lugar para os revisores comentarem sobre a direção antes do trabalho estar concluído. Uma boa descrição vincula qualquer problema relacionado e diz o que você testou, para que um revisor não tenha que reconstruir isso apenas do diff.

O GitHub mantém uma referência para cada pull request no remoto, mesmo antes de você adicionar o branch do PR ao seu próprio repositório: refs/pull/<number>/head. Busque-a diretamente para verificar o PR de um colega em sua máquina, sem adicionar seu fork como remoto primeiro.

bash
$ git fetch origin pull/42/head:pr-42
From github.com:mara-chen/weather-app
 * [new ref]         refs/pull/42/head -> pr-42
$ git switch pr-42
Switched to branch 'pr-42'

Agora pr-42 é um verdadeiro branch local construído a partir do pull request número 42, pronto para executar e testar antes de deixar um único comentário.

JunoO que acontece quando você abre um pull request Um pull request é uma solicitação para integrar seu branch em outro, aberto no GitHub após você fazer push. Alguém revisa a mudança primeiro, e apenas então ela é integrada. O loop diário é branch, push, abrir um pull request, obter revisão, fazer merge.
JunoO que acontece quando você abre um pull request Um PR propõe um merge e mantém a conversa em torno dele, e você pode abrir um mais cedo como rascunho para obter feedback antes de o trabalho estar terminado. Escreva a descrição como se um revisor realmente fosse lê-la: o que mudou, por quê, e o que você testou.
JunoO que acontece quando você abre um pull request O GitHub mantém uma referência oculta para cada pull request, refs/pull/<number>/head, para que você possa buscar o PR de um colega direto em sua máquina com git fetch origin pull/42/head:pr-42 em vez de adicionar seu fork como remoto. Teste a mudança localmente antes de deixar seu primeiro comentário.

Fork versus branch

Abrir um pull request a partir de um branch funciona quando você tem acesso de escrita ao repositório, que é o caso normal em projetos de seu próprio time. Contribuir para um projeto ao qual você não tem acesso de escrita precisa de um passo extra: um fork, sua própria cópia do repositório em sua própria conta do GitHub.

Você faz branch e commit dentro de seu fork exatamente como faria em um projeto que você possui, faz push para seu fork, e então abre o pull request do branch do seu fork de volta ao repositório original. O GitHub compara através dos dois repositórios da mesma forma que compara dois branches dentro de um repositório, então o fluxo de revisão e merge parece idêntico de qualquer forma.

Se você planeja enviar mais de um PR para um projeto que você fez fork, vale a pena adicionar o repositório original como um segundo remoto, geralmente nomeado upstream, enquanto origin continua apontando para seu próprio fork. Execute git fetch upstream e faça merge de upstream/main em seu branch para acompanhar um projeto que avançou desde que você fez fork dele, usando os mesmos passos que o capítulo Remotes and GitHub cobre para qualquer remoto.

JunoFork versus branch Faça branch diretamente quando você tem acesso de escrita a um repositório, os projetos do seu próprio time. Faça fork quando não tem: um fork é sua própria cópia do repositório de alguém, e você faz branch e push dentro dessa cópia antes de abrir o pull request de volta ao original.
JunoFork versus branch Um fork é uma cópia completa de um repositório sob sua conta, usado para contribuir onde você não tem acesso de escrita. Você faz branch, commit e push dentro de seu fork normalmente, e o GitHub compara o branch do seu fork contra o repositório original da mesma forma que compara dois branches dentro de um projeto.
JunoFork versus branch Mantenha dois remotos em um projeto do qual fez fork: origin para seu próprio fork, upstream para o repositório original, para que você possa buscar e fazer merge de suas mudanças conforme ele avança. O próprio PR ainda compara o branch do seu fork contra o branch base do repositório original.

Obtendo seu pull request através da revisão

Uma vez que um PR está aberto, ele se torna uma conversa em andamento sobre o diff. Um revisor lê a mudança, deixa comentários em linhas específicas, e aprova ou solicita mudanças. Quando mudanças são solicitadas, continue commitando e fazendo push para o mesmo branch: cada push atualiza o mesmo PR em vez de criar um novo. Uma vez que um revisor aprova e qualquer verificação necessária passar, o PR está pronto para fazer merge.

O GitHub rastreia uma revisão como um de três estados: aprovado, mudanças solicitadas, ou comentado (feedback sem nenhum veredicto em qualquer sentido). Responda aos comentários conforme você os aborda e marque a conversa como resolvida para que um revisor possa ver de relance o que resta. Se você faz push de uma correção para um comentário específico, ajuda dizer isso em sua mensagem de commit ou em uma resposta, já que um revisor trabalhando em um PR longo está procurando por exatamente isso.

Quantas aprovações um PR precisa, e se cada thread de comentário tem que ser marcado como resolvido antes do botão de merge desbloquear, geralmente é uma regra anexada ao próprio branch base em um projeto bem administrado.

JunoObtendo seu pull request através da revisão Um revisor comenta em seu pull request e pode solicitar mudanças. Commit e push mais trabalho para o mesmo branch para abordá-lo, e o PR se atualiza automaticamente. O merge acontece uma vez que alguém aprova.
JunoObtendo seu pull request através da revisão As revisões chegam em um de três estados: aprovado, mudanças solicitadas, ou comentado. Faça push de correções para o mesmo branch para atualizar o PR, responda aos comentários conforme você os resolve, e mantenha o revisor orientado em uma thread longa.
JunoObtendo seu pull request através da revisão Os estados de revisão determinam se o botão de merge desbloqueia, mas a barra exata, quantas aprovações, se cada thread de comentário deve ser resolvida, geralmente é uma regra anexada ao branch base em um projeto bem administrado.

Por que um pull request não fará merge

Às vezes o botão de merge em um PR fica acinzentado, e o GitHub mostra uma mensagem em seu lugar: "This branch has conflicts that must be resolved" ou "This branch is out of date with the base branch." Ambas as mensagens descrevem um estado normal e corrigível: main avançou desde que você fez branch, geralmente porque o PR de outra pessoa foi integrado enquanto isso, e seu branch precisa acompanhar antes que o GitHub possa combinar os dois de forma limpa. Isso acontece em qualquer projeto com mais de um colaborador, então espere por isso em vez de temê-lo.

Corrija isso localmente da mesma forma que você faria para trazer quaisquer dois branches juntos:

bash
$ git switch add-five-day-forecast
$ git fetch origin
From github.com:mara-chen/weather-app
   9f8e7d6..b7c9e21  main       -> origin/main
$ git merge origin/main

Se nada se sobrepõe, o merge se completa por si só e você faz push, e o PR se atualiza e o botão desbloqueia. Se as mesmas linhas mudaram dos dois lados, o Git marca o conflito no arquivo para você resolver exatamente como coberto em Merging and conflicts: abra o arquivo, edite para remover os marcadores de conflito para o resultado que você quer, então git add e git commit para terminar o merge, e faça push novamente.

Um pull request travado precisa acompanhar ou seu conflito resolvido.

Em um PR que permanece aberto por mais de um ou dois dias, vale a pena fazer merge de main em seu branch de tempos em tempos em vez de esperar pelo botão ficar bloqueado. Um branch que está um dia desatualizado geralmente faz merge sem nenhum conflito; um que está três semanas desatualizado tem muito mais superfície para duas mudanças colidirem nas mesmas linhas. O botão "Update branch" do GitHub na página do PR faz esse mesmo merge para você quando não há nada para resolver manualmente.

Alguns times fazem rebase de um branch de funcionalidade para main em vez de fazer merge, para manter o histórico eventual linear em vez de mostrar um commit de merge para cada PR. Esse trade-off é o mesmo coberto em Merging and conflicts: rebase reescreve os commits do seu branch, o que é seguro contanto que você seja o único com cópias deles, então um branch de funcionalidade solo que apenas vive em sua máquina e em seu PR é um candidato razoável. Fazer rebase de um branch que outras pessoas já fizeram pull e construíram em cima não é, já que reescreve histórico no qual elas estão confiando.

JunoPor que um pull request não fará merge Um botão de merge acinzentado significa que seu branch está atrás de main ou tem um conflito com ele. Nada está quebrado. Mude para seu branch, busque, e faça merge de main, resolvendo qualquer conflito da mesma forma que você faria em qualquer outro lugar, depois faça push novamente.
JunoPor que um pull request não fará merge Faça merge de main em um branch de longa duração de tempos em tempos em vez de esperar o GitHub bloquear o botão de merge. Catch-ups menores e mais frequentes significam conflitos menores, e o botão "Update branch" do GitHub pode fazer o caso sem conflito para você.
JunoPor que um pull request não fará merge Fazer merge ou rebase de seu branch para main ambos corrigem um PR travado, e um branch de funcionalidade solo é seguro para fazer rebase já que ninguém mais tem uma cópia de seus commits. Uma vez que outras pessoas fizeram pull de um branch, continue fazendo merge nele em vez disso.

O que um pull request é, sob o capô

Um pull request não é um objeto do Git, e não há nenhum comando git que crie um. Git e GitHub não são a mesma coisa: Git só conhece commits, branches e outras refs (uma ref é um nome apontando para um commit). O GitHub constrói toda a página do PR, os comentários, e o botão de merge em cima de duas refs que ele compara: seu branch (a head) e o branch em que você está fazendo merge (a base, geralmente main). Essa comparação é por que você abre um pull request no site do GitHub (ou através da ferramenta de linha de comando do GitHub ou API), e nunca com um comando git simples.

Porque um PR vive no GitHub, separado do histórico do repositório, seus comentários e conversa de revisão não viajam com os commits. Se você nunca mover um projeto para um host diferente, cada commit vem com você inalterado, mas os pull requests e suas discussões ficam para trás no GitHub, já que nunca foram parte dos dados do Git em primeiro lugar.

O GitHub computa o diff de um PR encontrando a base de merge, o commit mais recente que a head ref e a base ref compartilham, e comparando a head contra esse ponto em vez de contra o que quer que main pareça agora. Cada push para o branch adiciona uma nova versão ao mesmo PR em vez de criar uma nova comparação. Proteção de branch é a camada de política sentada em cima de tudo isso: uma regra que você (ou sua organização) anexa a um branch, mais frequentemente main, que pode exigir verificações de status aprovadas, exigir um número definido de revisões de aprovação, e bloquear pushes diretos para que cada mudança seja forçada através de um pull request. O Git em si não impõe nenhum disso. Ele permitirá que você faça push direto para main do seu terminal até que a regra do GitHub recuse a solicitação.

JunoO que um pull request é, sob o capô Um pull request é uma funcionalidade do GitHub em camadas em cima do Git: Git rastreia commits e branches, e o GitHub adiciona a página do PR e o botão de merge comparando dois deles. Manter Git e GitHub separados em sua cabeça explica muito do que de outra forma parecia mágica.
JunoO que um pull request é, sob o capô Um PR compara seu branch contra um branch base e vive inteiramente no GitHub, então seus comentários e histórico de revisão não se movem se o repositório nunca muda de host. Os próprios commits são a única parte que é realmente Git.
JunoO que um pull request é, sob o capô Um PR é o GitHub comparando uma ref de head contra uma ref de base de sua base de merge compartilhada, atualizada com cada push. Proteção de branch é a política imposta em cima, exigindo verificações ou revisões antes do merge. Git em si não impõe nenhum disso: ele permitirá que você faça push direto para main até que a regra do GitHub o impeça.