-
Notifications
You must be signed in to change notification settings - Fork 106
Roteiro git
Este roteiro é destinado àqueles que querem contribuir com o Manual do PHP utilizando o git
em linha de comando. É especificamente destinado aos que preferem esse ambiente em particular, mas também àqueles que pretendem se tornar tradutores permanentes do manual.
Para contribuições esporádicas ou sem instalação de ferramentas veja o roteiro de como realizar contribuições pela interface web do GitHub.
AVISO:: Os comandos e procedimentos abaixo ainda foram pouco revisados. Caso você seja um usuário proficiente do
git
, solicitamos a revisão e contribuição dos comandos abaixo. Os scripts abaixo tentam superar a questão de falta de familiaridade com ogit
e outros tantos comandos que são quase sempre utilizados em conjunto.
Para contribuir com o manual são quatro passos, assim resumidos:
- Baixar ou atualizar os arquivos fontes;
- Traduzir ou sincronizar uma tradução;
- Validar a consistência do manual;
- Commit, push e pull request.
Embora seja possível utilizar ambientes Windows e outros para traduzir o manual, o ambiente explicado aqui é um Linux (especificamente Debian/Ubuntu), dada a facilidade de instalação (ou virtualização) dessa distribuição em particular.
Os fontes oficiais são gerenciados nos repositórios GitHub oficiais. Autores e tradutores com acesso direto podem operar contra o repositório oficial. Mas nesse roteiro é mostrado o uso de um repositório fork, que permite a contribuição de pessoas sem acesso direto (que é o caso mais comum, aliás).
O primeiro passo é na verdade realizado no site no GitHub. Abra uma conta lá, e depois disso, navegue até a URL de criação do seu fork, que é: https://github.com/php/doc-pt_br/fork
Após criado o seu fork, é necessário também que o git
em linha de comando esteja instalado no computador. Em um terminal, instale e verifique a instalação:
sudo apt-get install git
git --version
Depois é preciso baixar os fontes uma única vez. Para tanto, execute:
# Configurações iniciais
GU="seu_USER_github_aqui"
# Primeira baixa de arquivos
mkdir phpdoc
cd phpdoc
git clone [email protected]:php/doc-base.git doc-base
git clone [email protected]:php/doc-en.git en
git clone [email protected]:$GU/doc-pt_br pt_BR
# Conjunto de scripts para facilitar o dia a dia
ln -s pt_BR/.tools/test/all.sh all.sh
ln -s pt_BR/.tools/test/conf.sh conf.sh
ln -s pt_BR/.tools/test/diff.sh diff.sh
ln -s pt_BR/.tools/test/find.sh find.sh
ln -s pt_BR/.tools/test/gind.sh gind.sh
ln -s pt_BR/.tools/test/open.sh open.sh
ln -s pt_BR/.tools/test/push.sh push.sh
ln -s pt_BR/.tools/test/test.sh test.sh
ln -s pt_BR/.tools/test/trim.sh trim.sh
ln -s pt_BR/.tools/test/wipe.sh wipe.sh
# Adicionando uma fonte upstream ao clone local
# (pular esse passo quem tiver o acesso direto)
git -c pt_BR remote add upstream https://github.com/php/doc-pt_br
git -c pt_BR remote set-url --push upstream /dev/null
# O GitHub reclama se você não tiver nome e email
# preenchidos, então vamos adiantar esse passo.
git -c pt_BR config user.name "Nome Sobrenome"
git -c pt_BR config user.email "[email protected]"
Isso irá criar uma pasta phpdoc
no mesmo diretório que os comandos forem executados. Todo o ambiente de tradução está configurado aqui. Dentro dessa pasta, haverá outras três:
- doc-base: Contém scripts e outros arquivos necessários para a compilação do manual;
- en: Contém os arquivos originais do manual, em inglês;
- pt_BR: Contém os arquivos traduzidos do manual para português do Brasil.
Você somente vai mexer com arquivos dentro de pt_BR
. Para ver se tudo deu certo, faça um git -C pt_BR status
, qual deve retornar algo como:
No ramo master
Your branch is up to date with 'origin/master'.
nothing to commit, working tree clean
Essas mensagens são um sinal que deu tudo certo. Os passos acima serão feitos uma única vez. O procedimento normal é uma repetição dos passos seguintes.
Antes de começar algum trabalho, é importante atualizar todos os fontes e verificar se o manual está compilando. Isso é realizado através do comando:
./conf.sh
Caso tenha curiosidade, inspecione o conteúdo desse script, que mostra a sequência de comandos de atualização e compilação do manual.
Executar esse comando vai ser seu primeiro contato com as mensagens que aparecem durante a compilação, que são muitas. Mas não se angustie. Se no final aparece um gatinho em ASCII art, é porque as coisas deram certo o suficiente. Mas se tiver um tempo, dê uma lida nas mensagens, para conhecê-las um pouco, e para procurar alertas de falhas e erros.
O principal comando de compilação é a linha:
php doc-base/configure.php -q --with-lang=pt_BR --enable-xml-details --disable-xpointer-reporting
Esse script verifica a integridade dos fontes XML, e na verdade faz muitas outras coisas também. Como o manual do PHP é separado em literalmente milhares de arquivos, é preciso juntá-los todos em único ponto, misturando arquivos em inglês e traduzidos, fora outros detalhes. Tudo isso é disparado pelo doc-base/configure.php
, e por isso ele deve ser rodado com frequência.
Há na verdade dois scripts interessantes para se utilizar sempre que for começar uma tradução ou atualização. A saber:
-
all.sh
: Atualiza e compila o manual, e gera umrevcheck.html
local. Bom para executar no começo de um dia de trabalho, e; -
conf.sh
: Atualiza e compila o manual, bom de executar a cada arquivo alterado.
Nota: O --disable-xpointer-reporting
omite alguns avisos que são comuns e normalmente não são fatais. Mas caso o manual esteja com problema de compilação, remover essa opção pode ajudar a esclarecer a razão.
O manual do PHP é um documento enorme, e trabalho não falta. Você até pode escolher que tipo de contribuição realizar, mas normalmente exista um issue aberto no GitHub que serve de coordenação, para evitar duas pessoas mexendo em um mesmo arquivo.
Existe um relatório que lista a situação do manual e quais arquivos precisam de atenção dos tradutores, chamado de revcheck. O comando ./all.sh
cria ele localmente, mas você pode consultar uma versão online deste relatório, pelos links a seguir. Em ordem de prioridade, você deve se concentrar nos:
- Arquivos desatualizados.
- Arquivos sem rastreamento.
- Arquivos não traduzidos.
Os links acima são atualizados uma vez por dia, e por isso mesmo podem estar desatualizados. Para saber a situação exata dos arquivos locais, você pode visualizar o revcheck.html
, criado pelo ./all.sh
, ou se quiser criar apenas o revcheck.html
sem mexer em mais nada, isso é possível com os comandos seguintes:
php doc-base/scripts/revcheck.php pt_BR > revcheck.html
xdg-open revcheck.html
Já o processo de tradução em si é bem simples. Arquivos originais e traduzidos têm os mesmos caminhos dentro dos repositórios, mudando apenas a pasta inicial, en
ou pt_BR
. No caso de arquivo inexistente na tradução, basta copiar o arquivo do en
para pt_BR
, mantendo o caminho interno. Depois é abrir ambos os arquivos, original e tradução, copiar o XML em inglês e traduzir a parte texto, preservando tags e comentários XML.
O script open.sh
facilita muito esse procedimento de ficar abrindo o mesmo arquivo em duas pastas diferentes.
Dica 1: Veja como configurar um editor de texto simples, que permita abrir os arquivos lado a lado ou que permita alternar abas rapidamente via teclado. Abrir arquivos lado a lado ajuda na hora de novas traduções, e o rápido alternar abas permite descobrir alterações estruturais "no olho".
Dica 2: Tente preservar a quantidade linhas igual entre os dois arquivos, além de tentar manter as tags estruturais nas mesmas linhas entre original e tradução. Isso fará muita diferença depois, na hora de atualizar as traduções. É muito mais fácil encontrar o que é preciso atualizar quando essa “compatibilidade de linhas” é preservada.
TODO:
Adaptar open.sh
para usar o editor configurado no git
, ou Gnome/KDE padrão, e por fim descrever essa funcionalidade aqui.
Os arquivos originais podem conter um comentário XML bem no começo do arquivo, com o seguinte texto:
<!-- $Revision:$ -->
Nos arquivos traduzidos essa linha deve ser substituída (ou incluída) por uma linha no formato:
<!-- EN-Revision: hhhh Maintainer: xxxx Status: ssss --><!-- CREDITS: zzzz,yyyy,xxxx -->
Onde:
-
hhhh
: É o hash completo do arquivo em inglês que aparece nas ferramentas de documentação. -
xxxx
: É o apelido do tradutor que se responsabiliza em manter esse arquivo atualizado. Informar aqui seu nome de usuário GitHub, sua antiga credencial php.net, ou ou ainda_
caso seja uma contribuição esporádica (explicado abaixo). -
ssss
: É um código de status, explicado abaixo. -
zzzz,yyyy,xxxx
: Uma relação de todas as pessoas que trabalharam no arquivo, incluindo você. Logins separados por vírgula, acréscimos no final.
Os valores previstos para o Status
são:
-
ready
: Significa que a tradução está pronta. -
rev
: Significa que a tradução está pronta, mas que o tradutor solicita que outra pessoa revise. -
wip
: Sigla de work in progress, uma tradução que está no meio do caminho. Arquivoswip
são altamente desencorajados na tradução brasileira.
Basicamente o que você faz é atualizar o texto traduzido, sincronizar o hash conforme a ferramenta de controle, acrescentar seu login na lista CREDITS:
.
Você pode também preencher seu login em Maintainer:
, caso queira puxar para si a responsabilidade de manter o arquivo atualizado. Tome o cuidado de verificar se o nome do Maintainer
anterior está na lista de CREDITS
, e se não tiver, acrescente-o também, antes do seu. Arquivos com o Maintainer
preenchido com _
não tem um Maintainer
designado, e podem ser livremente alterados.
Pode ocorrer do arquivo original não conter uma linha com <!-- $Revision:$ -->
. Nesses casos, as tags comentário de revisão e crédito devem ser colocadas ao final da primeira linha. de texto no arquivo traduzido.
Observação: Os scripts de monitoração das traduções utilizam expressões regulares bem simples para ler a tag de revisão, então os espaços, ordem e formato geral das tags precisam ser exatamente como nos exemplos acima. De outra forma o script não rastreia corretamente as traduções.
Antes de fazer um push
para o seu fork ou um pull request contra o repositório oficial, é estritamente necessário validar se a alteração não quebra a compilação do manual. Isso é feito através do comando:
./conf.sh
ou
php doc-base/configure.php --with-lang=pt_BR --enable-xml-details
Sempre fazer isso antes de fazer qualquer comando git
.
Ou o que é mais fácil de lembrar: Sempre execute o ./conf.sh
, ao antes e depois de mexer em qualquer arquivo!
Observação 1: O conf.sh
atualiza o manual antes de compilar. Isso pode ser bom por um lado (melhora a certeza que o manual compila depois que enviar suas alterações), mas pode ter o efeito colateral de quebrar a sua compilação local por causa de alguma alteração de terceiros. Isso dificulta o problema de separar se a quebra é por conta de alguma alteração sua ou de algo que foi trazido na atualização. Mas não tem muita escapatória. Ninguém vai aplicar um patch com o manual quebrado, menos ainda vai aplicar um patch que aparentemente quebra a compilação do manual, então melhor correr atrás e ter o manual sempre validando.
Observação 2: Existe uma maneira de visualizar suas alterações localmente, sem esperar a publicação no site oficial, mas que exige a instalação de um toolchain bem mais extenso.
Após realizar as alterações desejadas, execute um ./conf.sh
para verificar a lista de arquivos modificados, e ver se não teve alguma coisa inesperadamente alterada.
Para enviar suas alterações você deve executar uma sequência de passos bem detalhada:
- Executar
git add
para cada arquivo novo ou alterado; - Criar um commit local com um
git commit
; - Enviar o commit local para o seu fork, através de um
git push
; - Iniciar um Pull request a partir do seu fork (o link aparece na resposta do comando acima).
Caso isso pareça muito complicado, alguns scripts facilitam a vida. Primeiro faça um:
./diff.sh
Isso vai mostrar todas as alterações que o git
percebeu que você fez. Confira tudo, para ver se não tem nada fora do lugar ou se tem alguma alteração indesejada. Se estiver tudo certo, daí você pode fazer um:
./push.sh "Descrição resumida da tradução ou atualização."
A mensagem pode ser simples no caso de só atualizar textos, mas deve ser bem detalhada no caso de alterações em código. No guia de edição há uma descrição de como escrever mensagens melhores, que inclusive podem disparar procedimentos automatizados.
Feitos o ./diff.sh
e o ./push.sh
, suas alterações foram encaminhadas ao seu fork particular. O último passo é criar um pull request com essas alterações, de forma que as alterações do seu fork sejam encaminhadas para revisão e aplicação no repositório oficial. Caso não sabia como fazer isso, veja os detalhes em 1, 2 e 3.
Pode acontecer do seu repositório ficar dessincronizado, com o GitHub mostrando uma mensagem parecida com This branch is N commits ahead
. Isso não causa problemas, mas acaba sendo chato. Em um dia que não tiver nenhum trabalho em andamento ou pull request aberto, ao final deste guia tem uma explicação de como resolver, e depois ainda, de como evitar completamente esse problemas.
Existe na verdade todo um "estilo de vida git" para evitar esse e vários outros problemas, mas como exige o uso de branchs descartáveis, e muito mais comandos git
, isso é explicado como um anexo, mais no final.
Ufa!
Parece muita coisa, e da primeira vez deve dar até medo. Mas não se preocupe. Depois que fizer um ou duas vezes, fica bastante automático, e o medo desaparece.
E é isso. Terminou, daí é GOTO 1.
O GitHub é realmente muito bom, mas tem uma enorme pegadinha. O uso de squash merges pela interface web necessariamente torna dois ramos incompatíveis entre si, o que por sua vez, torna dois repositórios incompatíveis entre si.
E isso pode ser extremamente surpreendente, dado que essas são as opções padrão da interface web, e mais que isso, repositórios inteiros podem ser configurados para fazerem somente squash merges, de forma que toda vez que um pull request é aceito, o seu repositório fork acaba incompatível com o upstream, e nada que você faça no seu clone pode resolver.
Então, como ter uma vida tranquila, fazendo várias alterações, sem ficar perdendo o fork e o clone a cada alteração? A resposta para isso é usar apenas branchs temporários, chamados de features branchs na documentação, mas cuja a documentação desse "estilo de vida" raramente vem acompanhada das coisas que tem de se evitar para que a sistemática de branchs temporários funcione. Então vamos começar por aí.
Para que tudo funcione sem problemas e sem parar, é necessário:
- Não fazer nenhuma alteração no ramo
master
; - Puxar ramos apenas do ramo
master
; - Nunca faça merges. Nunca mesmo.
Esses "não" vão soar estranhos, eu bem posso imaginar. Mas tenha paciência, que vai fazer sentido logo mais. Dito os "não", agora os "sim":
- Todas as alterações em branchs;
- Novas alterações em novos branchs;
-
git commit
,git push
e pull requests apenas de branchs; - Apos o merge do pull request, deletar o branch;
- De quando em quando, sincronizar o
master
do seu fork.
Funciona assim. Você vai começar um novo esforço, digamos, começar a mexer em novos arquivos em um final de semana. A sequência de comandos para atualizar o master e puxar um comando dele é:
cd pt_BR
git switch master
git pull
git branch dez2024
git switch dez2024
E pronto. Nesse momento você está dentro de um ramo chamado dez2024
do seu clone, e você pode trabalhar normalmente. Não se preocupe em dar nomes pomposos aos seus branches locais, que, se tudo der certo, no final você mesmo vai apagá-los em poucos dias.
Nada muda nos comandos de verificar diferenças, criar commits. Só muda um pouco o push
que nessa hora o git
vai reclamar que o branch local não existe no fork, mas ele mesmo oferece na mensagem de erro o comando de push
que faz o procedimento completo.
Na mensagem de sucesso do push
vai ter o link de criar o pull request, e aqui segue o procedimento normal.
Os últimos dois itens, apagar branchs e sincronizar o fork, eu tenho como hábito fazer tudo de uma vez, da seguinte maneira. Quando eu recebo um email do GitHub avisando que um pull request foi mesclado, nesse email vem um link chamado view it on GitHub
. Eu abro esse link, e no final vai ter o botão de apagar o branch do seu fork. Após o branch apagado, eu clico no meu avatar GitHub, na parte de cima e a direita da página, e clicar em Your repositories
. Na lista que aparece, selecione o repositório fork, que deve aparecer apenas com a mensagem de This branch is N commit
. Esse é o melhor dos cenários. Nesse caso é só clicar em Sync fork
> Update branch
e... voilá.
Nenhum repositório sem sincronia, nenhum repositório incompatível. O próximo trabalho acontece em um próximo branch, iniciado nos comandos acima.
E o melhor de tudo, isso até permite fazer várias coisas em paralelo. Você pode a qualquer momento fazer um git switch
e "voltar" nos ramos locais, que essas alterações vão cair nos PRs separados, mesmo que eles já estejam abertos.
Muitas coisas funcionam muito melhor, com branches separados, depois que você descobre que o git switch
é um verdadeiro amigo.
Mesmo utilizando branchs descartáveis, as vezes ocorrem conflitos apenas pelo uso dos squash merges do GitHub, que na prática criam um commit novo que por "não existir" nem no fork, nem no clone local, ele sempre gera conflito nos pull request. Isso também ocorre quando você faz puxa um branch de um branch, e cai no mesmo problema quando o primeiro branch é mesclado usando a opção squash.
Para resolver isso, o jeito é recriar a história do seu branch descartável, de forma a incluir o commit squashed e eliminando as duplicações. Toda documentação e discussão de internet de como fazer isso é incrivelmente confusa, e aqui estou explicando os passos mais automatizados possíveis.
O procedimento consiste em migrar para o branch master
, atualizá-lo, e daqui tirar um novo branch temporário. Até agora, nada complicado. O último comando é o temido rebase
, já na sua forma automatizada. Apenas para lembrar, se qualquer coisa der errado, basta executar um git rebase --abort
e tudo volta como antes.
git switch master
git pull
git branch temp
git rebase -s ours BRANCH
Você tem enormes chances de tudo dar certo, e os comandos acima terminam com um Successfully rebased and updated refs/heads/temp.
. Pode checar observando o histórico com um git log
ou checando o conteúdo dos arquivos. Após isso, você pode remover o branch quebrado com um git branch -d NOME
e renomear o branch temporário com um git branch -m OLD NEW
.
Você pode se encontrar na triste situação que as alterações de um ramo no seu clone entrarem em conflito com alterações no upstream. Em outras palavras, quando o GitHub reclama que um Pull Request não pode ser aplicado por causa de conflitos, basicamente porque ocorreram alterações simultâneas em um mesmo pedaço de algum arquivo. A solução para isso é o temido rebase
. E temido porque, quando dá errado, começam mensagens de erros mil, aparentemente intermináveis, o que normalmente levam as pessoas a simplesmente apagam o clone, e mesmo o fork inteiro em conflito, recriar tudo, para daí então recriar as alterações e por fim reenviar um PR todo novo. Isso não é necessário.
Geralmente os rebases automatizados funcionam bem, mas mesmo quando eles falham, tem uma forma de ser tudo ou nada. Ele funciona completamente, ou ele falha completamente, sem as aterrorizantes mensagens de erro infindáveis. A sequência é descrita abaixo. Mas nada como você ir lá e tirar uma cópia do clone, e assim poder simplesmente ter confiança que tudo pode voltar ao normal se o procedimento abaixo ainda assim assustar. Bora lá:
git fetch upstream
git switch master # Ou nome do ramo a reescrever
Os comandos acima apenas atualizam dados, e não geram alterações. Agora chegou o ponto da reescrita. Execute um dos comandos abaixo:
git rebase -Xtheirs upstream/master # Rebase preferindo suas alterações
git rebase -Xours upstream/master # Rebase preferindo alterações upstream
Eu bem imagino, que sua reação ao ler os comandos acima é desconfiar que os comandos estão errados, afinal a opção theirs
/ours
parece invertida. Pois é. É invertido mesmo.
Se tudo der certo, não vai aparecer mensagem nenhuma. Apenas inspecione pelo git log
que suas alterações ainda existem, porém agora com hashs diferentes. Agora vem a hora perigosa, de fazer um git push --force
, que tem o efeito de destruir hashs nos repositórios remotos. Antes de fazer isso, execute um:
git remote -v
Para confirmar que você os remotos que serão afetados se tratam do seus fork, e nunca dos repositórios oficiais. Confirmado isso, é só fazer o comando push
acima, o que sincroniza o seu fork e clone, e permitirá que PRs possam novamente ser aplicados automaticamente pela interface do GitHub.
Caso de qualquer problema, em qualquer ponto do processo, basta executar um:
git rebase --abort
E as coisas voltam como eram, antes de começar o rebase.
Depois de algum tempo, você pode notar que o seu repositório fork no GitHub apresenta a mensagem This branch is N commits ahead
, mesmo após todas as suas alterações terem sido aceitas e todos os repositórios estarem sincronizados. Uma (longa) explicação das causas dessa eterna dessincronização é dada neste link, mas aqui focaremos apenas em como fazer a mensagem sumir.
Só adianto que se tratam de comandos DESTRUTIVOS, e por isso mesmo que só devem ser realizados no seu repositório fork, e nunca contra os repositórios oficiais. Aviso dado, bora lá. Os comandos para remover a mensagem são os seguintes, separados em três blocos:
git fetch upstream
git switch master # Nome do ramo a recriar
git rebase -s ours upstream/master # DESTRÓI dados locais
git push --force origin +master # DESTRÓI dados remotos
O primeiro comando apenas baixa dados do repositório oficial no seu fork. Se ele falhar, veja e execute os comandos relacionados a upstream
mencionados na seção "Configurações iniciais".
O segundo grupo já envolve alterações destrutivas. No caso o rebase
reescreve os commits no histórico local, e isso dessincroniza o fork GitHub do seu clone local. O sinal que as coisas deram certo é o rebase
terminar com a mensagem Successfully rebased and updated refs/heads/master.
Caso alguma coisa dê errado, basta executar um git rebase --abort
, que tudo volta como antes.
Por fim, o git push --force
sobrescreve o ramo master
do repositório remoto origin
com os dados locais, efetivamente apagando dados no repositório remoto. O repositório origin
deve ser o seu fork GitHub no caso, e é criado automaticamente pelo git clone
. Note que entre os comandos de configuração, tomamos o cuidado de invalidar a URL de push de upstream
, e assim evitar acidentes.
Porém isso não evita a rota destrutiva que tradutores com acesso direto sempre possuem, então as pessoas com acesso direto devem tomar cuidados redobrados, de somente executar esses comandos em checkouts de repositórios secundários (ou melhor ainda, nunca executar esses comandos).