Todos sabemos que versionamento de código é algo super importante nos dias de hoje. Este artigo abordará tópicos simples até tópicos um pouco mais avançados na utilização da ferramenta de Git, não irei falar sobre steps de configuração do Git nesse artigo. Além disso no final, comentarei sobre algumas dicas e ferramentas para ajudar no seu dia a dia.
Para criação de um novo repositório, crie uma pasta onde você gostaria que o repositório fique localizado. Após isso abra o terminal onde poderá fazer o init do mesmo.
git init
Após isso seu diretório será trackeado como parte do git com as funcionalidades do .git, entretanto não há nenhum arquivo para ser tracked no momento.
No momento em que seu repositório é criado há duas fontes de verdade do seu repositório:
Commit é o nome dado ao ato de adicionar as mudanças feitas em seu repositório. Quando um commit é criado essas mudanças ficam salvas indefinitivamente em seu repositório, ou seja é um estado dos arquivos que pode ser acessado a qualquer momento a partir de sua criação. Isso permite a fácil reversão caso necessário.
É preciso especificar quais arquivos você quer que entre em seu commit. Arquivos não especificados irão ficar listados como mudanças que não estão dentro do repositório.
// Adicionar um arquivo ao commit
git add <arquivo>// Adicionar todos arquivos ao commit
git add .// Listagem dos arquivos que estão fora/dentro do seu commit atual
git status// Fazer o commit com uma mensagem.
git commit -m "Meu primeiro commit"
Obs: Existem muitos outros parâmetros para utilização do git add e git commit.
Com esses comandos você adicionou seu primeiro commit a seu repositório local. 🎉
Agora que seu commit foi adicionado ao repositório local, como enviar ele para o repositório remoto?
git push origin master
Caso não esteja conseguindo realizar um git push, isso deve siginificar que não está com um repositório remoto linkado ao seu local, é necessário fazer esse step de configuração.
Com isso, você acaba de enviar para o seu repositório tudo que está em seu repositório local 🚀. Agora… como vamos pegar as mudanças do repositório remoto para o repositório local caso alguém tenha adicionado algo lá?
Fetch é o comando utilizado para fazer o download do repositório remoto para sua máquina local sem fazer alterações em suas mudanças atuais, com isso é possível uma visualização do que está ocorrendo no remoto. Basicamente ele serve para atualizar o repositório para este momento atual, entretanto não irá aplicar nenhuma dessas mudanças baixadas.
Pull é o comando mais conhecido e normalmente mais utilizado pois é um modo simplificado de buscar e aplicar as mudanças no repositório remoto em uma só tacada. Entretanto, ele não é nada mais nada menos que um fetch seguido de um merge. É por causa desse merge que ocorre conflitos no seu repositório quando realiza um git pull onde pessoas estão mexendo nos mesmos arquivos que você.
git fetchgit pull
Normalmente por convenção definimos que nossa branch master deve ter apenas código estável/funcional e branches secundárias são aquelas onde cada desenvolvedor fará suas mudanças de feature. Em casos de projetos maiores, normalmente temos uma branch master (versão estável vista pelos utilizadores do código/produto), uma branch develop (versão estável utilizada pelos desenvolvedores do código) e branches secundárias que saem da develop (features onde cada desenvolvedor(es) está trabalhando).
Mas qual a vantagem de utilizar uma branch separadas ao invés de todos trabalharmos na mesma? 🤔
// Criando uma nova branch local para se trabalhar.
git checkout -b <nome para sua branch>
// Faz o checkout para uma branch. Caso não possua a branch //localmente, o comando criará uma versão local e irá para ela.
git checkout <branch existente no remoto/local>// Faz a publicação das mudanças de sua branch local para uma branch //remota origin/<sua branch>. Caso contrário não será possível //enviar suas mudanças para o remoto.
git push origin <sua branch>
Obs: A criação de branches é local até o momento onde ela é publicada ao repositório remoto. Mais funcionalidades do git checkout e git branch.
Essa é a funcionalidade do git que permite a junção de dois ramos diferentes em um mesmo, o que ocorre realmente é a geração de um commit na branch de destino com todas as mudanças realizadas na branch de origem. Este é o momento onde poderão ocorrer conflitos de código, e para o merge ser completo é necessário resolve-los antes. Na linha de comandos o processo é um pouco diferente do que foi explicado, é necessário ir para sua branch de destino e aplicar as mudanças da branch de origem nela.
// Primeiro é necessário ir para a branch de destino, no caso vamos //para a master.
git checkout master
//Agora use o comando de merge para juntar as mudanças.
git merge <nome de sua branch>
Rebase é algo que muitos utilizadores de git tratam como opcional ou desconhecem a forma de utilização. Entretanto eu considero como uma funcionalidade essencial para se ter uma organização do seu repositório boa. Rebase é como o próprio nome diz mudar a base de origem da sua branch para o topo da branch desejada.
Qual a ideia por trás do rebase? Ele pega cada um dos seus commits da sua branch atual e os refaz em cima do final da branch desejada. Os conflitos são resolvidos commit a commit (um dos motivos que rebase causa a dor de cabeça em desenvolvedores é este). Abaixo temos uma representação visual, sendo sua funcionalidade os commits amarelos, e os novos commits da master sendo os verdes.
Como se realiza o rebase? Primeiro iremos para a branch onde quer se alterar a base, e depois indicamos que queremos fazer o rebase para o destino.
git checkout <branch que quer alterar a base>
git rebase origin/master
Isso irá fazer o rebase da sua branch local para a branch desejada. Bastante cuidado nessa parte pois a branch de origem ainda está da forma anterior ao rebase ou seja caso exista duas pessoas trabalhando na mesma branch, problemas poderão ocorrer caso o outro developer faça mudanças na branch de origem, pois é necessário utilizar um force push da sua branch para aplicar as mudanças atuais do rebase. O motivo do problema de duas pessoas trabalharem na branch que receberá o force push será por que o histórico de commits do git mudará fazendo assim que mudanças na origin que não foram consideradas serão apagadas do histórico da branch, para fazer a verificação que tudo está tranquilo antes de realizar o force push basta realizar um:
// Fazer download das mudanças no repositório remoto
git fetch// Verificar se houve commits novos no remoto que não estão //refletidos em seu repositório local.
git log origin<branch>
Não façam um git pull ao invés de git fetch, lembram que eu falei que o git pull aplica as mudanças automaticamente, pois então fazer o git pull vai fazer com que você fique com duas versões da sua branch com um merge de ambas. Vendo que está tudo tranquilo basta dar um git push origin <branch desejada>-f
Após o rebase feito poderá realizar um merge normalmente que resultará visualmente na imagem abaixo:
Isso é mais legível do que merge hell com multiplos merges sendo feitos por multiplas frentes diferentes. Mas vamos concordar que não é a melhor forma de visualização além do que parece que realizamos todos os commits dentro da master que não é algo que queremos. Queremos ter uma separação de linha do tempo com funcionalidades introduzidas a medida que esse tempo passa. Tem como fazer isso, me pergunta? Claro que tem 🚀
Merge é um comando que é fast-forward e isso significa que não é gerado um commit de merge da sua branch caso não haja mudanças da branch destino em relação a branch atual que é literalmente o que o rebase faz, move a base da branch atual para o fim da base de destino, o que resulta na imagem de cima. Então como ficaria o código para realizar isso:
git checkout master
git merge --no-ff <sua branch>
O no fast-forward força a criação de um commit de merge, como mostrado abaixo:
Os pontos vermelhos são os commits de merge gerados. Utilizando essa forma de junção de branches forçamos uma visão legível do histórico do git com as funcionalidades separadas de acordo com o tempo. Temos um exemplo abaixo visual de diferenciação de um histórico
Rebase não só garante uma visibilidade melhor da evolução do seu código como distribui as dores de cabeça de resolução de conflito para todo o time. Apenas lembre-se de que para garantir isso é sempre bom ter um ambiente de versionamento bem definido e que os rebases sejam feitos frequentementes para evitar conflitos, quanto maior tempo sem fazer o rebase com a branch de destino maior a chance de conflitios 😮
Ferramenta de stash salva o estado atual dos arquivos modificados. Permite que o usuário consiga "salvar" suas mudanças sem necessidade de realizar o processo de seleção de arquivos e commit, o que salva bastante tempo e evita que usuários façam commits com pressa. Outra vantagem do stash é que é possível utilizar o mesmo em outra vertical que não a mesma que realizou o seu comando. Basicamente a vantagem do stash é manter o ambiente de trabalho dentro do git limpo de uma forma rápida
// Adiciona todas as mudanças atuais ao topo da pilha de stash
git stash// Aplica e deleta o stash que está no topo da pilha de stash
git stash pop// Apenas aplica o stash que está no topo da pilha.
git stash apply// Listagem de todos os stashes existentes em seu repositório local.
git stash list// Faz o pop de do segundo item da pilha. Por definição se não //especificado irá pegar o item stash@{0} que é o primeiro da pilha.
git stash pop stash@{1}
Obs: Git stash é um comando que salva localmente, ou seja não é possível utiliza-lo e tentar acessar de outro computador. Confira mais sobre git stash.
É um dos melhores comandos que alguns usuários de git nem conhecem. Muito útil quando se quer pegar um commit de uma outra branch sem ter que fazer um rebase, fazer um merge da branch base na sua ou esperar que o outro desenvolvedor faça merge com a branch base.
Como funciona? É bem simples na real, o cherry-pick pega o commit desejado (vamos imaginar que é um bugfix importante) e ele replica o commit na sua branch atual sem mais nem menos. Entretanto, assim como qualquer comando do git temos que ter cuidado pois nem sempre devemos usa-lo
// Achar o commit que quer fazer o cherry-pick
git log// Na branch que quer aplicar o cherry-pick
git cherry-pick <SHA do commit desejado>
Obs: Mais informações do git cherry-pick
Padrões de commit são muito importantes para garantir a legibilidade da história do projeto e que funcionalidades estão sendo aplicadas em um estado do repositório. Algumas sugestões para melhorar a legibilidade dos seus commits:
// Como devemos fazer a leitura do commit
If applied, this commit will refactor subsystem for new login functionality// Como é feito da outra maneira
If applied, this commit will refactored subsystem for new login functionality
Mas por que fazer a leitura do commit dessa forma? Pois tratamos um commit como um estado da aplicação então quando estamos aplicando um commit estamos basicamente dizendo que se esse commit for aplicado iremos refatorar (…).
Pull requests é uma ferramenta para garantir um controle visual do código que entra e sai da sua branch base, garantindo que todos os desenvolvedores se envolvam o com o projeto como um todo e garante que a qualidade do código permaneça boa a medida que o tempo passa. Além disso é possível anexar outras ferramentas que analisam o pull request garantindo a qualidade da feature que vai entrar dentro da branch base, tal como CI (Continous Integration) que garantem que o código novo não quebre o que está em dev, lints que garantem que o código está dentro dos padrões do lint estabelecido, assim como outras features…
Desenvolvedores devem tomar proveito em analise de pull requests de seus colegas para não só agir como keepseeker 🤓 do produto mas também como uma oportunidade de melhorar seus conhecimentos em geral. Por experiência pessoal posso afirmar que aprendi/descobri muita coisa realizando esse processo em PR de colegas de trabalho.
Esse artigo descreveu como ocorre as funcionalidades do git em linhas de comandos de uma forma sucinta (ou seja tem mais coisa a se explorar, então por favor vão 🤓 👉 📖, o mundo de tecnologia é um interminável aprendizado), entretanto tem formas automatizadas que fazem esses processos descritos por baixo do pano com uma plataforma visual para auxiliar o processo do Git entretanto não remove a importância de aprender pelo terminal primeiro para entender como o processo ocorre. Segue uma lista de ferramentas que eu utilizei no decorrer da minha vida universitária e profissional e recomendo darem uma olhada:
Sourcetree
GitKraken
Git Tower
Esses foram os clientes que eu utilizei (atualmente utilizo o Git Tower), entretanto existem outros clientes fora desse que podem adequar melhor a suas necessidades. 🚀
Seja para desenvolver um ecommerce, um app para sua empresa ou uma plataforma para ajudar seu negócio a inovar, estamos disponíveis para te ajudar.