Git Fetch Pull Request: Proficiency Unlocked

Nicola Paolucci
Nicola Paolucci
Voltar para a lista

Hoje em dia, aplicar uma correção a um projeto é tão fácil quanto criar uma bifurcação (que evoca uma cópia remota completa do projeto para você hackear): é só selecionar o arquivo que quer alterar, pressionar Editar e fazer o commit das correções.

E se você for quem recebe uma pull request (a partir daqui, PR)? Usar uma interface de usuário da web polida é ótimo e costuma ser tudo de que você precisa. Clique em um botão para aprovar, clique em um botão para fazer o merge e pronto.

Aprovação da pull request

Mas nem sempre esse é o caso! É comum ter que baixar as alterações incluídas em uma pull request (PR) localmente, executar alguns testes e ver como elas ficam no IDE para entender o que foi feito.

As etapas para fazer o download — para ser mais explícito: fazer o fetch e o checkout — das pull requests de seu colega ou colaborador são conceitualmente simples, mas se tornam ainda mais fáceis se você conhecer algumas informações e dicas importantes.

Então, deixe-me guiá-lo para uma melhor compreensão dos recursos de linha de comando que o git oferece para lidar com pull requests da linha de comando com facilidade.

Antes de começar: enriquecer o prompt do shell com o nome e o status do branch

Sempre fico surpreso com quantas pessoas têm um prompt de comando simples que não mostra o branch do git em que estão ou se têm arquivos modificados ou sem commit no diretório de trabalho. Se você pensou "Ei, sou eu!", permita que eu ajude você e o deixe de queixo caído ao mesmo tempo!

Faça um favor a si mesmo e instale algo parecido com o incrível Liquid Prompt, que mostra excelentes anotações sobre o status do seu diretório de trabalho git (e também vai ser compatível com qualquer outro VCS):

Liquid Prompt

(Na captura de tela acima, você vê meu prompt alertando que estou no branch newbranch, adicionei 5 linhas aos arquivos que rastreio no meu diretório de trabalho e removi 0)

Todos trabalhando no mesmo repositório

Se você trabalha no mesmo repositório que sua equipe, o processo de check out de uma pull request é muito simples: basta fazer o fetch e o checkout o branch do qual a pull request foi criada:

  • Obtenha todos os branches que foram publicados no seu repositório compartilhado:
git fetch origin
  • Crie um branch local que rastreie o branch remoto em que você tem interesse:
git checkout -b PRJ-1234 origin/PRJ-1234
  • Agora você pode fazer diff, merge e testar o que quiser assim:
 git diff main ./run-tests.sh
  • Quando estiver satisfeito, volte para a IU da web e dê feedback ou aprove a alteração na hora.

Colaboradores trabalhando em suas próprias bifurcações

O processo muda um pouco quando alguns dos colaboradores trabalham em bifurcações separadas. Nesse caso, você pode fazer o fetch do branch remoto em que houve o commit do recurso ou da contribuição:

  • Adicione o branch remoto do colaborador primeiro:
git remote add jsmith http://bitbucket.org/jsmith/coolproject.git
  • Colete todas as atualizações mais recentes do origin primeiro, seu repositório principal:
 git checkout main git fetch origin git merge main
  • Obtenha todos os branches que foram publicados na bifurcação do colaborador:
git fetch jsmith
  • Crie um branch local que rastreie o branch remoto em que você tem interesse:
git checkout -b jsmith-PRJ-1234 jsmith/PRJ-1234
  • Agora você pode fazer diff, merge e testar o que quiser assim:
 git diff main ./run-tests.sh

Reduzir o trabalho usando refs de pull request

A estratégia acima funciona, mas várias coisas podem dificultar sua vida:

  • E se você tiver muitos colaboradores, cada um com suas próprias bifurcações? Adicionar todas as bifurcações e lidar com elas em separado se torna impraticável.
  • E se você nem mesmo tiver acesso a algumas das bifurcações e não puder fazer o checkout do branch de origem?

A solução para ambos os problemas acima é usar refs de pull requests que alguns servidores git oferecem. O procedimento que vou mostrar é compatível com alguns servidores git e varia um pouco dependendo do que você usa. A seguir, vou abordar como fazer o fetch de todas as pull requests no Stash (agora chamado de Bitbucket Server) e no GitHub.

Não tenha medo das Refspecs

O primeiro pré-requisito é conhecer as Refspecs. Refspecs são legais e você não deve ter medo delas. São mapeamentos simples de branches remotos para referências locais. Em outras palavras, uma maneira direta de dizer ao git que "tal branch remoto (ou tal conjunto de branches remotos), deve ser mapeado para tais nomes no local, em tal espaço de nome".

Por exemplo, um comando como:

 git fetch +refs/heads/main:refs/remotes/origin/main

Vai mapear o branch remoto main no branch remoto origin para um origin/main local, então você pode digitar:

 git checkout origin/main

E ainda fazer referência a esse branch remoto. O sinal de mais (+) na definição está lá para indicar que a gente quer que o git atualize a referência mesmo que ela não seja rápida.

Esse comando é usado para baixar todas as pull requests pelo mapeamento de como o repositório remoto armazena os HEADs de PR e pelo mapeamento deles para um espaço de nome local para facilitar a referência.

Portanto, desde que você tenha um branch remoto origin (ou upstream) definido, veja a seguir o que fazer.

Observação: como bem observado por vários desenvolvedores do Stash (agora chamado de Bitbucket Server), as referências que vou demonstrar abaixo são consideradas não documentadas e privadas e podem mudar a qualquer momento.

Baixar todas as pull requests: Stash

  • Bifurque um repositório.
  • Clone a bifurcação no local:
git clone git@stash.atlassian.com:durdn/tis.git
  • Adicione o repositório original upstream como upstream.
git remote add upstream git@stash.atlassian.com:tpettersen/tis.git
  • Obtenha os heads mais recentes do mantenedor "upstream"
git fetch upstream
  • Adicione a refspec que vai mapear os heads de pull requests remotos para um espaço de nome de pr local. Você pode usar um comando config:
 git config --add remote.origin.fetch '+refs/pull-requests/*/from:refs/remotes/origin/pr/*'
  • Se você olhar em .git/config, as entradas de fetch passam a ser:
[remote "upstream"] url = git@stash.atlassian.com:docker/libswarm.git fetch = +refs/heads/*:refs/remotes/upstream/* fetch = +refs/pull-requests/*/from:refs/remotes/upstream/pr/*
  • Agora ficou fácil fazer o fetch de todos os branches de pull requests:
$ git fetch upstream remote: Counting objects: 417, done. remote: Compressing objects: 100% (274/274), done. remote: Total 417 (delta 226), reused 277 (delta 128) Receiving objects: 100% (417/417), 105.28 KiB | 0 bytes/s, done. Resolving deltas: 100% (226/226), done. From stash.atlassian.com:docker/libswarm * [new ref] refs/pull-requests/10/from-> upstream/pr/10 [...] * [new ref] refs/pull-requests/100/from -> upstream/pr/100 * [new ref] refs/pull-requests/101/from -> upstream/pr/101 [...] * [new ref] refs/pull-requests/109/from -> upstream/pr/109 * [new ref] refs/pull-requests/110/from -> upstream/pr/110 [...]
  • Agora, para mudar para uma pull request específica, é só fazer assim:
git checkout pr/102

Baixar todas as pull requests: GitHub

Se as bifurcações ou upstreams estiverem no GitHub, ele vai funcionar exatamente como mostrado acima, mas o comando config muda para:

git config --add remote.origin.fetch '+refs/pull//head:refs/remotes/origin/pr/'

E o remoto em .git/config vai mudar para incluir uma configuração de fetch adicional para mapear os heads de PR para um espaço de nome local chamado pr:

[remote "upstream"] url = git@github.com:docker/libswarm.git fetch = +refs/heads/*:refs/remotes/upstream/* fetch = +refs/pull/*/head:refs/remotes/upstream/pr/*

Fetch de uma única pull request usando refs

Se você não quiser configurar as entradas de fetch em .git/config e só quiser chegar logo a uma pull request, pode usar um único comando:

  • Confira uma única PR no Stash:
git fetch refs/pull-requests/your-pr-number/from:local-branch-name
  • Confira uma única PR no GitHub:
git fetch refs/pull/your-pr-number/head:local-branch-name

E se você estiver usando muito o comando acima, você pode agilizar o processo criando um git alias:

# For Stash git config alias.spr '!sh -c "git fetch origin pull-requests/${1}/from:pr/${1}" -' # For Github git config alias.gpr '!sh -c "git fetch origin pull/${1}/head:pr/${1}" -'

Com esse alias configurado, é possível fazer o fetch de uma pull request com este comando simples (obrigado, Inuits):

git spr 100

Conclusão

Espero que você tenha achado essas informações úteis! No final, manter o controle sobre o trabalho de seus colegas ou colaboradores é fácil quando você cria alguns aliases simples ou adiciona as refspecs adequadas ao .git/config. Fico feliz em responder a quaisquer perguntas que você possa ter no Twitter em @durdn ou @AtlDevtools.

Pronto(a) para aprender Git?

Tente este tutorial interativo.

Comece agora mesmo