Chad Russell
Novatec
Original English language edition published by Apress, Copyright © 2016 by Apress, Inc.. Portugueselanguage edition for Brazil copyright © 2016 by Novatec Editora. All rights reserved. Edição original em Inglês publicada pela Apress, Copyright © 2016 by Apress, Inc. Edição em Português para o Brasil copyright © 2016 pela Novatec Editora. Todos os direitos reservados. © Novatec Editora Ltda. 2016. Todos os direitos reservados e protegidos pela Lei 9.610 de 19/02/1998. É proibida a reprodução desta obra, mesmo parcial, por qualquer processo, sem prévia autorização, por escrito, do autor e da Editora.
Editor: Rubens Prates PY20160928 Tradução: : Lúcia A. Kinoshita Revisão gramatical: Priscila A. Yoshimatsu Editoração eletrônica: Carolina Kuwabata ISBN: 978-85-7522-526-4 Histórico de impressões: Outubro/2016
Primeira edição
Novatec Editora Ltda. Rua Luís Antônio dos Santos 110 02460-000 – São Paulo, SP – Brasil Tel.: +55 11 2959-6529 E-mail: novatec@novatec.com.br Site: www.novatec.com.br Twitter: twitter.com/novateceditora Facebook: facebook.com/novatec LinkedIn: linkedin.com/in/novatec
capítulo 1
Controle de versões
Se você ainda não usa nenhum tipo de sistema de controle de versões em seu projeto, definitivamente deve começar agora. Independentemente de você ser um desenvolvedor trabalhando sozinho ou se faz parte de uma equipe maior, um sistema de controle de versões proporciona vários benefícios a qualquer projeto, seja ele grande ou pequeno. Caso você não tenha familiaridade com um sistema de controle de versões, ele é usado para capturar e registrar alterações em arquivos de seu projeto. Esse sistema exibe um histórico visual dessas alterações, oferecendo-lhe a capacidade de retornar e ver quem as fez e o que essas pessoas mudaram – é possível ver tanto os arquivos quanto os conteúdos alterados, quando as alterações foram feitas e, por meio da leitura de suas mensagens de commit, por que elas foram feitas. Além disso, esse sistema oferece um mecanismo para segregar alterações em seu código, conhecido como branches (mais sobre isso posteriormente). Existem vários sistemas de controle de versões disponíveis, alguns gratuitos e de código aberto, enquanto outros são proprietários e exigem licença. Neste capítulo, nosso foco estará no Git, que é gratuito e de código aberto. O Git foi inicialmente desenvolvido por Linus Torvalds para o projeto Linux Kernel. Ele é um DVCS (Distributed Version Control System, ou Sistema Distribuído de Controle de Versões) que permite que você distribua várias cópias (espelhos) de seu repositório a outros membros de sua equipe, possibilitando a monitoração das mudanças. Isso significa que cada pessoa com um clone do repositório tem uma cópia de trabalho completa do sistema no momento da clonagem. O Git foi projetado para ser simples, rápido e totalmente possível de ser distribuído. 11
12
Ferramentas essenciais para desenvolvedores PHP
Este capítulo tem como propósito apresentar uma visão geral do Git, incluindo informações suficientes para que você possa começar a usá-lo todos os dias em seus projetos. Como só tenho um capítulo para discutir isso, apenas tocarei na superfície das funcionalidades mais comumente utilizadas do Git. No entanto, deve ser mais do que suficiente para que você se sinta à vontade em usá-lo. Para uma apresentação mais completa e detalhada do Git, dê uma olhada no livro Pro Git de Scott Chacon e Ben Straub, publicado pela editora Apress.
Usando o Git Para começar a usar o Git, inicialmente é preciso instalá-lo em seu sistema. Binários para Mac OS X, Windows, Linux e Solaris estão disponíveis em http://git-scm.com para download do instalador apropriado ao seu sistema operacional. Além disso, o Git também está disponível para sistemas RedHat/CentOS por meio do gerenciador de pacotes yum ou do apt-get no Debian/Ubuntu. No Mac OS X, você pode obtê-lo instalando as ferramentas de linha de comando do Xcode. Neste livro, usaremos uma versão do Git para Linux.
Configuração do Git Agora que o Git está instalado, vamos criar uma configuração mínima definindo o seu nome e seu endereço de email na ferramenta de configuração do Git para que essas informações sejam mostradas nos commits que você fizer (um commit é o ato de colocar uma nova versão de seu código no repositório). Podemos fazer isso usando a ferramenta git config: $ git config --global user.name "Chad Russell" $ git config --global user.email chad@intuitivereason.com
Podemos conferir se essas configurações foram aceitas usando a ferramenta git config novamente, desta vez usando a chave da propriedade como a configuração que queremos verificar: $ git config user.name Chad Russell $ git config user.email chad@intuitivereason.com
Capítulo 1 ■ Controle de versões
13
Note que você executará os mesmos comandos de configuração tanto em ambientes Windows quanto Unix.
Inicializando o seu repositório Para criar o seu primeiro repositório Git, basta usar o comando git init. Esse comando inicializará um repositório Git vazio em seu diretório de códigos-fontes. Após a inicialização, você poderá então executar seu primeiro commit em seu novo repositório. Neste exemplo, temos um diretório vazio no qual faremos a inicialização e, em seguida, adicionaremos um arquivo README; por fim, vamos acrescentar e fazer commit do arquivo em nosso novo repositório. Lembre-se de que o Git iniciará com base no diretório em que o comando Git for chamado. Por exemplo, se você estiver em: C:\Program Files (x86)\Git
o resultado será: Initialized empty Git repository in C:/Program Files (x86)/Git/bin/.git/
Usaremos o repositório e o diretório a seguir à medida que avançarmos no livro para acompanhar vários exemplos de código que utilizaremos: $ git init Initialized empty Git repository in /Apress/source/.git/
Commit inicial Agora que inicializamos o nosso repositório vazio, adicionaremos um arquivo README bem básico a ele e então executaremos o commit inicial: $ echo "This is our README." > README.md
Se observarmos o status atual de nosso repositório usando git status, veremos que agora temos um arquivo não monitorado, o que significa que é um arquivo que ainda não foi adicionado ao nosso repositório, isto é, não está sendo monitorado pelo Git para acompanhar as mudanças. Você pode usar git status sempre que quiser ver o status do branch de trabalho de seu repositório:
14
Ferramentas essenciais para desenvolvedores PHP $ git status On branch master Initial commit Untracked files: (use "git add <file>..." to include in what will be committed) README.md
Agora adicionaremos o arquivo ao nosso repositório usando git add: $ git add README.md
Se executarmos git status novamente, veremos que o nosso arquivo foi adicionado, mas seu commit ainda não foi feito no repositório (não foi salvo): $ git status On branch master Initial commit Changes to be committed: (use "git rm --cached <file>..." to unstage) new file: README.md
Por fim, faremos commit de nossa alteração e o novo README estará no repositório; a partir de agora, ele será monitorado para mudanças: $ git commit -m "Initial commit. Added our README" [master (root-commit) e504d64] Initial commit. Added our README 1 file changed, 1 insertion(+) create mode 100644 README.md
Com base na mensagem recebida de git commit, podemos ver que nosso commit foi salvo. Se executarmos git status novamente, veremos que, no momento, não há mais nada que exija um commit: $ git status On branch master nothing to commit, working directory clean
Capítulo 1 ■ Controle de versões
15
Staging das alterações Temos nosso arquivo inicial monitorado no repositório e vimos como acrescentar um novo arquivo para o Git monitorar. Vamos agora alterar o README e então fazer o stage (preparação) e o commit dessa alteração. Acrescentei uma mudança no arquivo README.md, alterando o texto inicial para algo um pouco mais informativo. Vamos executar git status novamente e ver o que ele mostra: $ git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: README.md
O comando mostra que o nosso README foi modificado, mas não sofreu um stage para commit ainda. Fazemos isso usando o comando git add. Vamos adicionar o arquivo e verificar o status mais uma vez: $ git add README.md $ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) modified: README.md
Por fim, faremos este novo commit, que concluirá a alteração que fizemos no arquivo: $ git commit -m "Updated README" [master ca476b6] Updated README 1 file changed, 1 insertion(+), 1 deletion(-)
Nota As mudanças de staging podem ser configuradas de modo um pouco diferente em um ambiente Windows.
16
Ferramentas essenciais para desenvolvedores PHP
Visualizando o histórico Com todas as mudanças que acabamos de fazer, é conveniente ser capaz de retornar e visualizar o histórico de nosso repositório. Uma das maneiras mais simples de fazer isso é usar o comando git log. Se nenhum argumento for passado, git log mostrará todos os commits em seu repositório, começando pelas alterações mais recentes e seguindo em ordem cronológica decrescente a partir daí: $ git log commit ca476b6c41721cb74181085fd24a40e48ed991ab Author: Chad Russell <chad@intuitivereason.com> Date: Tue Mar 31 12:25:36 2015 -0400 Updated README commit dc56de647ea8edb80037a2fc5e522eec32eca626 Author: Chad Russell <chad@intuitivereason.com> Date: Tue Mar 31 10:52:23 2015 -0400 Initial commit. Added our README
Há várias opções e argumentos que você pode passar para git log. É possível limitar a quantidade de resultados passando um número como argumento; você pode visualizar o resultado apenas para um arquivo específico e até mesmo modificar o formato da saída usando o argumento --pretty, junto com várias opções diferentes. Por exemplo, se quiser ver apenas o último commit de nosso arquivo README.md e resumi-lo em uma só linha, o comando a seguir pode ser usado: $ git log -1 --pretty=oneline -- README.md ca476b6c41721cb74181085fd24a40e48ed991ab Updated README
Para descrever esse comando por partes, estamos lhe dizendo para se limitar a apenas um resultado com -1, usar o formato elegante oneline e especificar -- README.md para que apenas o nosso arquivo README.md seja considerado. Nota De longe, os comandos que você usará com mais frequência são: git add, git commit, git log, git pull e git push. Esses comandos adicionam arquivos, fazem commit dos arquivos no repositório, fazem pull das alterações (trazem) de uma origem remota ou fazem push das
Capítulo 1 ■ Controle de versões
17
alterações locais (enviam) para uma origem remota (por exemplo, um repositório hospedado – mais sobre esse assunto posteriormente). No entanto, existem vários comandos e subcomandos adicionais que o Git disponibiliza para executar diversas tarefas. Para ver uma lista completa dos comandos, utilize git --help, ou git --help a para mostrar os subcomandos disponíveis.
Ignorando arquivos específicos Com frequência, haverá alguns arquivos e diretórios em seu projeto que você não vai querer que sejam monitorados pelo Git. Ele oferece uma maneira simples de especificar isso por meio de um arquivo Git Ignore chamado .gitignore. Você pode salvá-lo em qualquer lugar de seu projeto, mas geralmente começará com um no diretório-raiz do projeto. Depois de ter criado e salvado esse arquivo, você poderá editá-lo em seu IDE ou editor de texto e acrescentar arquivos e/ou paths que queira ignorar. Por enquanto, gostaria de ignorar os arquivos de configuração que o meu IDE – o PHPStorm – cria. O PHPStorm cria um diretório chamado .idea, no qual ele armazena alguns arquivos específicos para as minhas configurações do IDE para este projeto. Definitivamente, não queremos esses arquivos em nosso repositório, pois não estão relacionados especificamente ao projeto e poderiam causar problemas para outros desenvolvedores que clonassem esse código e usassem o PHPStorm. Nosso arquivo .gitignore inicial agora terá o seguinte aspecto: # O arquivo .gitignore principal de nosso projeto .idea/*
Por enquanto, temos duas linhas; a primeira é um comentário, que pode ser adicionado em qualquer lugar do arquivo usando o caractere de sustenido #. A segunda linha diz ao Git para ignorar a pasta .idea e tudo que ela contiver, usando asterisco para indicar a correspondência com um caractere-curinga. Devemos então fazer commit desse arquivo em nosso repositório para que ele seja distribuído a qualquer um que possa clonar esse repositório e contribuir com ele. À medida que seu projeto crescer e você tiver novos arquivos e diretórios que não queira em seu repositório, basta continuar a fazer acréscimos
18
Ferramentas essenciais para desenvolvedores PHP
nesse arquivo. Outros itens comumente ignorados são arquivos de configuração que contêm senhas ou outras informações específicas de sistema, arquivos temporários como caches, outras mídias ou recursos que não sejam diretamente necessários ao seu projeto ou não sejam mantidos pela sua equipe de desenvolvimento.
Removendo arquivos Às vezes, você precisará remover arquivos de seu repositório. Há algumas maneiras diferentes de abordar a remoção de arquivos, conforme suas intenções. Se quiser remover totalmente um arquivo tanto do repositório quanto a sua cópia de trabalho local, você poderá usar o comando git rm para essa tarefa. Se você apagar o arquivo de sua cópia local usando o sistema operacional ou o seu IDE, ele será apresentado como um arquivo apagado, que precisa de um commit. Vamos dar uma olhada. Inicialmente, vamos criar um arquivo-texto simples para ser adicionado em nosso repositório, fazer o seu commit e então apagá-lo: $ touch DELETEME $ git add DELETEME $ git commit -m "Adding a file that we plan on deleting" [master 5464914] Adding a file that we plan on deleting 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 DELETEME $ git rm DELETEME rm 'DELETEME' $ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) deleted:
DELETEME
$ git commit -m "Removed our temporary file" [master 6e2722b] Removed our temporary file
Capítulo 1 ■ Controle de versões
19
1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 DELETEME $ git status On branch master nothing to commit, working directory clean
Agora apagaremos esse arquivo inicialmente no sistema local e, em seguida, vamos removê-lo do Git e fazer o commit da alteração: $ touch DELETEME $ git add DELETEME $ git commit -m "Adding another temporary file to delete" [master b84ad4f] Adding another temporary file to delete 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 DELETEME $ rm DELETEME $ git status On branch master Changes not staged for commit: (use "git add/rm <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) deleted: DELETEME no changes added to commit (use "git add" and/or "git commit -a") $ git rm DELETEME rm 'DELETEME' $ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) deleted: DELETEME $ git commit -m "Removing our second temporary file" [master e980b99] Removing our second temporary file 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 DELETEME
20
Ferramentas essenciais para desenvolvedores PHP
Por fim, talvez você queira apagar um arquivo do Git para que ele não seja mais monitorado, porém deseja mantê-lo localmente. Às vezes você pode ter acidentalmente feito o commit de um arquivo de configuração que agora foi adicionado ao seu arquivo .gitignore; você deseja removê-lo do Git, mas quer mantê-lo localmente, por motivos óbvios. Para isso, utilizaremos a opção --cache com o comando git rm: $ touch DELETEME $ git add DELETEME $ git commit -m "Adding a temporary file to delete one more time" [master f819350] Adding a temporary file to delete one more time 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 DELETEME $ git rm --cached DELETEME rm 'DELETEME' $ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) deleted: DELETEME Untracked files: (use "git add <file>..." to include in what will be committed) DELETEME $ git commit -m "Removed temporary file just in the repository" [master 26e0445] Removed temporary file just in the repository 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 DELETEME $ git status On branch master Untracked files: (use "git add <file>..." to include in what will be committed) DELETEME
Capítulo 1 ■ Controle de versões
21
Branching e merging Branching (ramificação) é o mecanismo que permite separar vários seg-
mentos de alterações em seu código em uma espécie de sub-repositório. Merging (mescla ou combinação) é o método para reunir novamente esse código. Por exemplo, suponha que você tenha um repositório de linha principal (main line) no qual é feita a maior parte do desenvolvimento. Você tem então alguns requisitos para a implementação de um conjunto totalmente novo de funcionalidades em sua aplicação, mas continuará fazendo diversas alterações não relacionadas a isso e correções de bug em sua base de código existente. Ao criar um branch (ramo) separado somente para essa nova funcionalidade, você poderá continuar a fazer e a monitorar suas alterações no código da linha principal e trabalhar nas modificações para a nova funcionalidade separadamente. Depois que estiver pronto para integrar essas modificações em seu código principal, você fará um merge, que combinará suas alterações no branch da linha principal. Porém, observe que os branches do Git não são como uma ponte para os branches do Subversion (git svn), pois estes são usados somente para capturar os esforços ocasionais de desenvolvimento em larga escala, enquanto os branches do Git estão mais integrados ao nosso fluxo de trabalho cotidiano. Para começar, vamos criar um branch para explorar essa funcionalidade: $ git branch branch-example $ git checkout branch-example Switched to branch 'branch-example'
Criamos o nosso novo branch, chamado branch-example, com o primeiro comando. O segundo comando diz ao Git para mudar para esse branch; assim podemos começar a trabalhar e a monitorar as alterações nele. A alternação entre branches é feita com o comando git checkout. Criaremos agora um arquivo de teste para esse novo branch e faremos o commit desse arquivo: $ touch test.php $ git add test.php $ git commit -m 'Added a test file to our branch'
22
Ferramentas essenciais para desenvolvedores PHP
Se retornarmos ao nosso branch inicial (master), veremos que esse arquivo não está lá: $ git checkout master Switched to branch 'master' $ ls README.md $ git log commit e504d64a544d6a1c09df795c60d883344bb8cca8 Author: Chad Russell <chad@intuitivereason.com> Date: Thu Feb 26 10:23:18 2015 -0500 Initial commit. Added our README
Merging Depois que nossas alterações no branch de teste estiverem prontas para aparecer no branch master, precisamos fazer um merge. Quando fizermos um merge, o Git comparará as mudanças nos dois branches e tentará combiná-las automaticamente. No caso de haver uma colisão nas mudanças, o que significa que as mesmas linhas de código foram alteradas nos dois branches, você deverá intervir e resolver o conflito manualmente. Após resolvê-lo, isso será monitorado como outro commit e você poderá finalizar o seu merge. Vamos fazer o merge das alterações em nosso branch-example com o branch master: $ git merge branch-example Updating e504d64..a6b7d2d Fast-forward test.php | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 test.php
Agora que fizemos o merge, não precisaremos mais de nosso branch-example neste caso. Podemos simplesmente apagá-lo usando o comando git branch mais uma vez: $ git branch -d branch-example
Capítulo 1 ■ Controle de versões
23
Stashing das alterações Ao trabalhar com seu projeto, haverá muitas ocasiões em que talvez você precise fazer um pull das alterações de um repositório remoto antes de estar pronto para fazer commit dos arquivos com os quais está trabalhando ou, quem sabe, precise alternar para outro branch a fim de concluir outra tarefa antes de estar pronto para fazer commit, mas não quer perder suas alterações. É nessa hora que o comando git stash se mostra útil. Para fazer stash de (guardar) suas alterações, basta chamar o comando git stash. Você pode ver as stashes salvas passando o subcomando list e pode reaplicar as mudanças com o subcomando apply. Vamos ver isso em ação: $ git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: test.php $ git stash Saved working directory and index state WIP on master: 08e9d29 adding a test file HEAD is now at 08e9d29 adding a test file $ git status On branch master nothing to commit, working directory clean
Podemos ver que tínhamos alterações em test.php para as quais um commit ainda não havia sido feito; após a chamada a git stash, temos um diretório de trabalho limpo. Veja: $ git stash list stash@{0}: WIP on master: 08e9d29 adding a test file $ git stash apply On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed)
24
Ferramentas essenciais para desenvolvedores PHP (use "git checkout -- <file>..." to discard changes in working directory) modified: test.php no changes added to commit (use "git add" and/or "git commit -a") $ git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: test.php
Podemos ver a stash que salvamos usando git stash list. Podemos reaplicá-la e vê-la de volta em nosso diretório de trabalho após chamar git stash apply. Por padrão, chamar git stash apply aplicará a stash mais recente da lista. Se quiser aplicar uma stash específica, forneça o seu número, que pode ser visto na chamada a git stash list. Usando a lista da saída anterior como exemplo, podemos usar o seguinte: $ git stash apply stash@{0}
Tagging A tagging (atribuição de rótulos) no Git permite atribuir tags (etiquetas) a qualquer commit específico com um rótulo (label) para futuras referências. Por exemplo, você pode usá-la para atribuir tags a versões específicas de seu código ou outros marcos importantes durante o desenvolvimento. O Git oferece dois tipos de tags. Existem as tags leves, que são apenas rótulos que apontam para um commit. Por outro lado, as tags anotadas são objetos completos, com checksum, contêm o nome e o email da pessoa que efetua a tagging e podem incluir uma mensagem. É altamente recomendável que você sempre utilize tags anotadas, a menos que seja necessário atribuir tags a algo temporariamente – nesse caso, uma tag leve será suficiente.
Tags leves Vamos criar uma tag leve simples para demonstração e, então, apagá-la e criar uma tag anotada.
Capítulo 1 ■ Controle de versões
Crie inicialmente uma tag leve: $ git tag v0.0.1
Agora mostre os detalhes da tag: $ git show v0.0.1 commit a6b7d2dcc5b4a5a407620e6273f9bf6848d18d3d Author: Chad Russell <chad@intuitivereason.com> Date: Thu Feb 26 10:44:11 2015 -0500 Added a test file to our branch diff --git a/test.php b/test.php new file mode 100644 index 0000000..e69de29
Podemos apagar uma tag usando a opção -d: $ git tag -d v0.0.1 Deleted tag 'v0.0.1' (was a6b7d2d)
Tags anotadas Crie agora a versão anotada: $ git tag -a v0.0.1 -m "Initial Release"
Mostre os detalhes da tag anotada: $ git show v0.0.1 tag v0.0.1 Tagger: Chad Russell <chad@intuitivereason.com> Date: Sun Mar 15 18:54:46 2015 -0400 Initial Release commit a6b7d2dcc5b4a5a407620e6273f9bf6848d18d3d Author: Chad Russell <chad@intuitivereason.com> Date: Thu Feb 26 10:44:11 2015 -0500 Added a test file to our branch diff --git a/test.php b/test.php new file mode 100644 index 0000000..e69de29
25
26
Ferramentas essenciais para desenvolvedores PHP
Como podemos ver, na versão anotada temos a data, o nome e o email da pessoa que criou a tag.
Desfazendo alterações Haverá ocasiões em que você fará acidentalmente um commit que deseja desfazer ou talvez queira reiniciar sua cópia de trabalho local, retornando ao estado em que ela se encontrava no último commit ou em um commit específico do histórico do repositório. Desfazer alterações no Git pode ser dividido das seguintes maneiras: • Corrigir (amend) • Remover da área de stage (un-stage) • Reiniciar arquivo (file reset) • Reset soft • Reset misto • Reset hard
Corrigir (amend) Desfazer um commit anterior alterando a mensagem de commit ou acrescentando outros arquivos pode ser feito com a opção --amend do git. Por exemplo, suponha que você tenha dois arquivos para commit e, acidentalmente, fez commit de apenas um deles. Você pode concatenar o outro arquivo para o qual deseja fazer commit com o mesmo arquivo e até mesmo alterar a mensagem de commit usando a opção --amend, assim: $ git add second.php $ git commit -m "Updated commit message" --amend
Remover da área de stage (un-stage) Essa ação remove um arquivo da área de staging para o qual um commit ainda não foi feito. A remoção de um arquivo da área de staging é feita por meio do comando git reset. Por exemplo, suponha que você tenha feito stage acidentalmente de dois arquivos para commit, mas queria
Capítulo 1 ■ Controle de versões
27
fazer stage e commit de apenas um deles por enquanto. Você utilizaria o comando git reset junto com o nome de arquivo para removê-lo da área de staging, assim: $ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: first.php new file: second.php $ git reset HEAD second.php $ git status On branch master Changes to be committed: (use "git reset HEAD <file>..." to unstage) new file: first.php Untracked files: (use "git add <file>..." to include in what will be committed) second.php
Reiniciar arquivo (file reset) Reiniciar um arquivo significa reverter suas alterações de trabalho para um arquivo de volta ao commit mais recente ou um commit anterior especificado por você. Para reiniciar um arquivo para o commit mais recente, utilize git checkout: $ git status On branch master Changes not staged for commit: (use "git add <file>..." to update what will be committed) (use "git checkout -- <file>..." to discard changes in working directory) modified: first.php $ git checkout -- first.php
28
Ferramentas essenciais para desenvolvedores PHP $ git status On branch master nothing to commit, working directory clean
Se quiser reiniciar um arquivo de volta a um commit específico, utilize git reset junto com o hash do commit e o nome do arquivo, assim: $ git reset a659a55 first.php
Reset soft Um reset soft reinicia o índice de seu repositório para o commit mais recente ou um commit especificado; suas alterações de trabalho permanecem inalteradas e seus arquivos na área de staging permanecem lá. O comando é chamado com a opção --soft do git reset. Você pode especificar o hash de um commit para reiniciar ou pode omitir esse valor e a reinicialização será feita para o commit mais recente: $ git reset –soft 26e0445
Reset misto De modo muito semelhante a um reset soft, um reset misto reinicia o índice de seu repositório para o commit mais recente ou um commit especificado; suas alterações de trabalho permanecem inalteradas. No entanto, ele remove qualquer arquivo da área de staging. Essa é a ação default se usarmos apenas git reset ou git reset com o hash de um commit, assim: $ git reset 26e0445
Reset hard Por fim, o reset hard é a mais perigosa de todas as opções, portanto use-o somente quando for absolutamente necessário. É um reset hard de seu repositório de volta para um dado commit, ao mesmo tempo que todas as alterações de trabalho e da área de staging são descartadas. Essa ação não pode ser desfeita, portanto certifique-se de que quer realmente fazer isso antes de executá-la: $ git reset --hard e504337 HEAD is now at e504337 Added our first .gitignore file
Capítulo 1 ■ Controle de versões
29
Controle de versões na nuvem: Bitbucket e GitHub Ter um repositório hospedado remotamente é uma prática comum quando usamos Git em situações que não sejam apenas para projetos pessoais. Embora haja muitas maneiras diferentes de fazer isso, há dois serviços populares que permitem ter repositórios hospedados na nuvem: o Bitbucket (http://bitbucket.com) e o GitHub (http://github.com). Cada um desses serviços oferece planos tanto gratuitos quanto pagos. A principal diferença no plano gratuito oferecido pelos dois serviços é que o Bitbucket permite uma quantidade ilimitada de repositórios privados, limitados a cinco colaboradores, enquanto o GitHub oferece somente repositórios gratuitos públicos. Depois que tiver uma conta em um desses serviços e criar o seu repositório, você especificará esse repositório remoto em sua configuração local do Git para permitir enviar e receber alterações de e para ele.
Bitbucket Vamos começar pelo Bitbucket. Ao acessar o site pela primeira vez, você criará uma nova conta. Depois que a conta for criada, você fará login e terá a opção de criar um novo repositório. Antes de prosseguirmos, há um passo que podemos executar para facilitar bastante a interação com esse repositório, que é adicionar uma chave SSH a ser usada na autenticação. Uma das principais vantagens do Bitbucket é que ele é integrado ao JIRA, além de ter suporte para Mercurial.
Chave SSH Você pode adicionar uma chave SSH à sua conta do Bitbucket, o que lhe permitirá interagir com ele a partir do Git em seu computador local sem precisar digitar a sua senha do Bitbucket repetidamente. Para isso, acesse a seção Manage Account (Administrar conta) e localize “SSH Keys” (Chaves SSH). A partir daí você pode adicionar uma chave SSH de seu computador local, que será usada como autorização quando você estiver trabalhando com qualquer repositório remoto em sua conta. Se você nunca configurou uma chave SSH, isso é feito de forma simples no Mac OS X e no Linux, e você pode usar o Git Bash no Windows.
30
Ferramentas essenciais para desenvolvedores PHP
No Mac OS X ou no Linux, abra um terminal e, no Windows, abra um prompt do Git Bash; em seguida, execute este comando e responda algumas perguntas que serão apresentadas a você: $ ssh-keygen -t rsa -C "chad@intuitivereason.com"
É altamente recomendável que você aceite os valores default sugeridos, incluindo o path para armazenar o novo par de chaves. Depois de finalizados esses passos, você terá criado um par de chaves tanto pública quanto privada. Localize a chave pública (usando o path mostrado pelo processo ssh-keygen) e abra-a usando o seu editor de texto favorito. Então copie o conteúdo da chave pública para a sua conta do Bitbucket e salve-o. Com isso, você concluirá a configuração de chave para a sua conta.
Criando o seu primeiro repositório remoto Com o SSH configurado na conta do Bitbucket, você pode agora criar o seu repositório. Para começar, clique no botão Create (Criar) na barra de navegação superior, o que o levará ao formulário Create. Insira as informações sobre o seu projeto e, em seguida, clique em Create Repository (Criar repositório). Você será direcionado para a página de configuração do repositório. Algumas opções sobre o que fazer com ele serão apresentadas. Se você ainda não criou o seu repositório local, como fizemos antes, poderá usar a opção “Create from scratch” (Criar do zero). Entretanto, em nosso caso, queremos fazer um push do repositório atual para esse novo repositório Git remoto. Seguindo as instruções apresentadas nessa tela, vamos ligar o repositório e executar o primeiro push copiando o nosso código atual para lá: $ git remote add origin git@bitbucket.org:intuitivereason/pro-php-mysql.git $ git push -u origin --all Counting objects: 6, done. Delta compression using up to 8 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (6/6), 524 bytes | 0 bytes/s, done. Total 6 (delta 0), reused 0 (delta 0) To git@bitbucket.org:intuitivereason/pro-php-mysql.git * [new branch] master -> master Branch master set up to track remote branch master from origin.
Capítulo 1 ■ Controle de versões
31
Agora que fizemos um push com sucesso, podemos clicar no ícone “Source” (Fonte) no Bitbucket para ver o nosso código visível aí.
GitHub Em vez de usar o Bitbucket, talvez você queira usar o GitHub; ao compará-los, podemos dizer que eles têm estruturas de cobrança muito diferentes, além de diferirem quanto ao visualizador de histórico e os recursos de colaboração. Os passos para usar o GitHub são muito semelhantes. Inicialmente, encontre e clique no botão New Repository (Novo repositório), e um formulário Repository Create (Criação de repositório) será apresentado; esse formulário é semelhante àquele do Bitbucket. Nesse local, você preencherá o formulário e criará o repositório. Na próxima tela, serão apresentadas instruções conforme este seja um novo repositório ou um existente, assim como no Bitbucket. Podemos fazer a adição desse repositório exatamente como fizemos no Bitbucket: $ git remote add origin git@github.com:intuitivereason/pro-php-mysql.git $ git push -u origin --all
Pushing, pulling e resolução de conflitos Assim como fizemos inicialmente o push de nosso código para o novo repositório remoto, usaremos o comando git push para continuar fazendo push do código para ele; do mesmo modo, utilizaremos o comando git pull para fazer pull do código do repositório cujo commit possa ter sido feito por outras pessoas desde o nosso último pull. Por exemplo, suponha que você tenha convidado outro desenvolvedor para colaborar em seu projeto. Você faz um pull do código mais recente do repositório remoto e então executa algumas tarefas. O desenvolvedor 2 faz o mesmo, porém faz commits e pushes de suas alterações para o repositório remoto antes de você. Quando fizer um push, você receberá uma mensagem do Git informando que sua versão de repositório está desatualizada. Você deve então usar o comando git pull para buscar qualquer alteração e tentar fazer um merge automaticamente e um rebase das alterações
32
Ferramentas essenciais para desenvolvedores PHP
com as suas. Depois você poderá fazer um push de suas alterações para o repositório. Os dois desenvolvedores continuarão seguindo esse padrão enquanto estiverem trabalhando com o repositório. Caso ambos trabalhem no mesmo arquivo e tenham alterações que se sobreponham, o Git não será capaz de determinar qual é a versão correta a ser usada. Isso se chama conflito. Você deve resolver manualmente os conflitos, fazer commit das alterações resolvidas e fazer um push de volta no repositório remoto.
Ferramentas para o Git Há uma série de ferramentas para facilitar o trabalho com o Git. Muitos IDEs oferecem integração com o Git, e tanto o Bitbucket quanto o GitHub oferecem suas próprias ferramentas GUI que facilitam bastante essa tarefa.
PHPStorm Caso você não tenha familiaridade com o PHPStorm, ele é um IDE PHP popular, disponível para várias plataformas (Linux, Mac OS X e Windows), desenvolvido pela JetBrains. É o IDE que uso nos vários exemplos; no entanto, você não precisa ter o PHPStorm para fazer qualquer um dos exercícios deste livro. Ele pode ser baixado a partir de: https://www.jetbrains.com/phpstorm/download/
Se você tiver um repositório Git na pasta-raiz de seu projeto no PHPStorm, ele o detectará automaticamente e oferecerá entradas de menu para executar uma série de ações diferentes, como mostra a Figura 1.1. Podemos ver que há uma série de ações disponíveis se visualizarmos essas opções quando estivermos em nosso arquivo test.php. A partir daí, podemos fazer commit ou adicionar o arquivo, caso ele ainda não tenha sido adicionado. Também podemos executar um diff para comparar o nosso arquivo local com a mesma versão no repositório ou com a versão mais recente que possa estar em um repositório remoto. Também podemos
Capítulo 1 ■ Controle de versões
33
compará-lo com outro branch em nosso repositório ou ver o histórico de todas as alterações nesse arquivo. Outra função é “Revert” (Reverter), que nos permite rapidamente reverter qualquer alteração sem commit em nosso arquivo para que ele retorne ao estado em que se encontrava no último commit local.
Figura 1.1 – Entradas de menu para o Git no PHPStorm.
A Figura 1.2 mostra a entrada Repository (Repositório) do submenu e as ações disponibilizadas nessa opção.
Figura 1.2 – Entrada do submenu Repository (Repositório) do Git no PHPStorm.
A partir dessa entrada, podemos ver os branches, atribuir tags, fazer merge, fazer ou desfazer uma stash de nossas alterações atuais, ou buscar, fazer pull ou push das alterações de e para um repositório remoto.
34
Ferramentas essenciais para desenvolvedores PHP
SourceTree A aplicação SourceTree é um cliente Git gratuito para usuários de Windows e de Mac, desenvolvido pela Atlassian, que é a mesma empresa que administra o Bitbucket. É um cliente GUI muito eficaz para o Git, que facilita bastante trabalhar e interagir com repositórios Git, tanto local quanto remotamente.
Instalando o SourceTree Você pode fazer o download do SourceTree acessando http://www. sourcetreeapp.com. Depois de baixá-lo, execute o instalador e siga as instruções para instalá-lo em seu computador de desenvolvimento. Na primeira vez em que executar o SourceTree, ele solicitará que você faça login com uma conta Bitbucket ou GitHub. Você pode fazer login ou ignorar esse passo. Se optar por fazer login, você poderá ver seus repositórios remotos na janela principal de marcadores/navegação do SourceTree. Você sempre pode optar por adicionar uma dessas contas vinculadas mais tarde.
Adicionando um repositório Para adicionar um repositório Git no SourceTree, clique no botão New Repository (Novo repositório) e escolha se está clonando um repositório remoto existente, adicionando um repositório local ou criando um novo repositório local ou remoto (Figura 1.3).
Figura 1.3 – Adicionando um novo repositório no SourceTree.
Capítulo 1 ■ Controle de versões
35
Adicione o novo repositório local que criamos anteriormente neste capítulo selecionando “Add existing local repository” (Adicionar repositório local existente). Isso o fará navegar para o diretório em que o repositório foi inicializado e clicar no botão Add (Adicionar). Esse repositório agora estará visível na janela de marcadores/navegação do SourceTree. Basta dar um clique duplo no nome do repositório para que a GUI completa seja apresentada (Figura 1.4).
Figura 1.4 – Visão de repositório do SourceTree.
A partir daí você pode continuar a trabalhar com o Git executando todas as ações que discutimos até agora, além de outras, incluindo fazer commit, criar branches, efetuar merge, fazer push e pull de e para um repositório remoto, e outras ações.
GUI do GitHub O GitHub tem sua própria GUI para Git, também disponível gratuitamente. Ela é muito limpa e intuitiva para usar, mas não tem alguns dos recursos avançados que você encontrará no SourceTree. No entanto, se você está procurando uma interface bonita e limpa para usar com o Git, definitivamente vale a pena dar uma olhada nela.
36
Ferramentas essenciais para desenvolvedores PHP
Instalando a GUI do GitHub Assim como o SourceTree, a GUI do GitHub está disponível tanto para usuários de Windows quanto para usuários de Mac. Estes podem fazer download acessando https://mac.github.com, e os usuários de Windows, a partir de https://windows.github.com. Depois de baixado e instalado, o GitHub o orientará no processo de configuração para concluir a instalação.
Adicionando um repositório Um recurso interessante da GUI do GitHub é que ela é capaz de encontrar repositórios Git em seu sistema e apresentá-los durante a instalação, com a opção de importá-los para começar a trabalhar com eles na GUI do GitHub. Se você optar por não fazer isso, poderá adicionar ou criar um novo repositório mais tarde usando a entrada do menu. Depois que seu repositório for adicionado à GUI do GitHub, a visão de repositório será apresentada, conforme vemos na Figura 1.5.
Figura 1.5 – Visão de repositório da GUI do GitHub.
Capítulo 1 ■ Controle de versões
37
gitg O gitg é uma GUI de código aberto para o Git, desenvolvido pela fundação Gnome, e serve apenas para usuários de Linux.
Instalando o gitg O gitg está disponível para instalação tanto com yum quanto com apt-get. O gitg não tem a eficácia e a usabilidade que encontramos no SourceTree, no GitHub ou nem mesmo no IDE PHPStorm. Apesar disso, ele oferece uma interface bonita para navegar ou pesquisar o histórico de um repositório em sistemas Linux.
Adicionando um repositório Para adicionar um repositório usando o gitg, clique no ícone de “engrenagem”, e você verá um submenu para abrir um repositório local ou clonar um repositório remoto. Após a adição, você poderá clicar para abrir a visão de repositório, como vemos na Figura 1.6.
Figura 1.6 – Visão de repositório do gitg.
38
Ferramentas essenciais para desenvolvedores PHP
Resumo Neste capítulo, apresentamos o GIT, que é um DVCS (Distributed Version Control System, ou Sistema Distribuído de Controle de Versões). Discutimos o básico sobre o uso do Git no desenvolvimento cotidiano, como adicionar e fazer commit de alterações, efetuar merge e criar branches. Também vimos como trabalhar com repositórios remotos com os serviços populares GitHub e Bitbucket. Em seguida, discutimos a forma de trabalhar com outros desenvolvedores e administrar a resolução de conflitos com arquivos cujos commits já tenham sido feitos; em seguida, analisamos algumas ferramentas que podemos usar para facilitar ainda mais o trabalho com o Git. Espero que você tenha um conhecimento que o faça se sentir à vontade com o Git e seja capaz de começar a usá-lo em seus projetos imediatamente! No próximo capítulo, discutiremos a virtualização de ambientes de desenvolvimento.