Git: a ferramenta que não pode faltar para desenvolvedores
Escrito em 28 de Junho de 2022 por Gabriel Sugai
Atualizado em 02 de Fevereiro de 2024
De onde veio o Git?
Antes de começar a estudar essa ferramenta, vamos voltar um pouco no tempo para entender o que motivou a sua criação e quais problemas o Git nos ajudou a solucionar. Se você nunca trabalhou com desenvolvimento em time, talvez seja um pouco difícil de imaginar o valor que o Git tem hoje em dia, mas vamos tentar imaginar um cenário como exemplo.
Imagine que você e seu amigo estão fazendo o TCC da faculdade. Vocês decidem escrever as partes do texto separadamente e depois juntar tudo em um arquivo só.
Se não houver um planejamento bem detalhado, isso pode causar vários problemas na hora de unificar esses textos, como: partes repetidas, algum trecho apagado por engano e etc.
Além disso, eu tenho certeza que você já salvou um arquivo com o seguinte padrão: tcc_v1, tcc_v2, tcc_v2_final, tcc_v3…. E, no final, não sabia mais qual era a versão correta do projeto.
Esses são problemas que existiam no desenvolvimento de software há alguns anos, pois todas as modificações nos projetos eram notificadas por arquivos ou e-mails, e isso causava diversos ruídos de comunicação.
Quando o problema foi descoberto, foram criadas ferramentas de versionamento que buscavam solucionar a questão.
No entanto, o Git não foi a ferramenta pioneira. Na verdade, sua história começou quando a ferramenta de versionamento que era utilizada pelo kernel (núcleo) do Linux deixou de ser gratuita.
Quando isso ocorreu, Linus Torvalds viu que seria necessário criar uma ferramenta própria para atender as necessidades do Linux, porém, essa ferramenta nova devia ter algumas características importantes.
Algumas metas do novo sistema eram os seguintes:
- Velocidade;
- Projeto simples;
- Forte suporte para desenvolvimento não-linear (milhares de ramos paralelos);
- Completamente distribuído;
- Capaz de lidar com projetos grandes como o kernel do Linux com eficiência (velocidade e tamanho dos dados).
E assim, em 2005, foi criado o Git, uma ferramenta de versionamento open source que conquistou a comunidade Dev.
Conhecendo o Git
Agora que você já sabe um pouco da história do Git e qual o seu valor no nosso dia a dia, vamos começar a estudá-lo.
O poder do Git é muito maior do que você pode estar imaginando. Utilizando o Git, nós podemos revisitar versões antigas do nosso projeto, desde um minuto atrás ou até anos.
Basicamente, o Git agrupa e guarda nossas modificações em “fotos” do momento em que salvamos e podemos comparar, retornar e/ou desfazer essas modificações a hora que quisermos. Essas "fotos" são chamadas de commits e são o histórico do nosso projeto.
Outra funcionalidadeque o Git possui são as branchs. Se você assistiu Vingadores, deve se lembrar de quando eles voltam no tempo para buscar as joias do infinito, a anciã avisa ao Banner que aquilo poderia criar ramificações na linha do tempo.
Basicamente, a branch do Git é uma ramificação na linha do tempo do seu projeto. Isso significa que quando criamos uma nova branch no nosso projeto, ela é idêntica a main (linha principal), porém, a partir dali, podemos fazer o que quisermos nessa nova "linha do tempo".
No final desse processo, podemos realizar um merge (processo para unir as 2 linhas do tempo) ou podemos "podá-las" e deletá-las - assim como os guardiões do tempo na série do Loki -, e a branch main não seria afetada de maneira alguma por essa branch paralela.
Criando um repositório Git
Utilizar o Git é muito simples: primeiro você precisa criar um repositório git. Para fazer isso, basta criar uma pasta e usar o comando:
$ git init
No exemplo a seguir, criei uma pasta chamada "exemplo_git" e utilizei o comando git status (vou falar mais sobre ele mais a frente). Como essa pasta não é um repositório git, recebi um erro.
Vamos transformá-lo em um repositório git e executar o comando novamente para ver o que acontece.
Ao utilizar o comando git init, a minha pasta agora se transformou em um repositório git. Como padrão é criada a branch "master".
Como a palavra master se remete a um termo relacionado a injúria racial, a comunidade optou por alterar o nome dessa linha padrão para "main". Hoje em dia, o próprio git sugere que você altere esse nome padrão e indica os nomes mais usados para que você possa escolher.
Para alterar o nome da branch, basta utilizar o comando:
$ git branch -m main
Como você pode ver, quando utilizei o comando git status novamente, o git retornou algumas informações, sendo elas: o branch atual que estamos (main); não existe nenhum commit, e também não existe nada para ser "commitado”.
Git commit
No momento, criamos um repositório git com sucesso! A seguir, vamos criar um arquivo e tentar manipulá-lo com o comando:
$ touch README.md
Criei um novo arquivo no nosso repositório, e utilizando o git status novamente, podemos notar que a resposta do comando foi diferente. Como existe um novo arquivo no nosso repositório, o git nos informa que existe um arquivo que ainda não está sendo "acompanhado", vamos experimentar utilizar esse comando:
git add
O comando abaixo adiciona o arquivo informado ao stage do git, ou seja, informa ao git que esse arquivo será adicionado ao próximo commit que iremos realizar. Agora, vamos realizar nosso primeiro commit.
$ git add <file>
Como nosso novo arquivo já está na área de stage, basta utilizarmos o comando:
$ git commit -m 'Primeiro commit'
git commit é o comando para criar um commit. Aqui, estamos passando a opção "-m" para criar o commit com uma mensagem. É possível utilizar somente git commit. O seu editor de texto padrão irá abrir para que você escreva a mensagem do commit. Como nosso commit é uma mensagem curta, a opção "-m" é o suficiente.
Podemos ver que nosso commit foi criado. Vamos utilizar o git log para visualizar o nosso histórico de commits:
O código identificado do nosso primeiro commit é 5f31dff7ecef9a4edee6a6ff944d7f296ea0e65e. Podemos chamá-lo de commit-hash ou simplesmente de hash.
Ele é o responsável por referenciar esse commit no nosso repositório. No git, existem vários comandos para trabalhar com os commits e, para utilizá-los, é necessário informar qual commit desejamos manipular.
Logo após o hash, podemos visualizar a seguinte informação (HEAD → main). Esse dado nos informa que esse commit é o "Head", ou seja, é a "ponta" da nossa branch ou “o último commit".
Na linha seguinte, temos o autor desse commit, seguido da data que ele foi criado e a mensagem do commit (que enviamos junto a opção -m na hora que criamos o commit).
Vamos modificar um pouco esse arquivo agora.
Agora que adicionamos uma nova linha ao nosso arquivo, vamos utilizar o comando git status novamente e ver o que acontece.
Podemos ver que o git nos informa que o arquivo foi modificado, ou seja, ele analisou esse arquivo no seu histórico e identificou uma mudança. Vamos ver o que foi alterado nesse arquivo? Para isso, utilize o seguinte comando:
$ git diff <ARQUIVO>
O comando git diff README.md retornou o seguinte:
Entendendo as linhas
A primeira linha se refere a qual arquivo estamos analisando. Como meu arquivo estava vazio, as modificações que eu realizei são todas de adição, ou seja, apenas inseri novos dados no arquivo e por isso o git nos mostra essa mensagem em verde com o "+" no início de cada linha.
Caso eu tivesse alterado alguma frase antiga, ela apareceria duplicada, com uma linha com o sinal "-" indicando o valor antigo, e uma linha com o sinal "+" indicando o novo valor daquela linha no arquivo, como no exemplo abaixo, onde eu removi o sinal de exclamação “!”:
Vamos commitar essas modificações seguindo os mesmos passos que vimos anteriormente sobre como criar um commit, e vamos dar uma olhada no git log novamente.
Como podemos ver, o HEAD foi alterado para esse último commit que fizemos.
Git Branchs
Agora que já aprendemos um pouco sobre commits, vamos começar a brincar um pouco com as git branchs. Todo conhecimento que aprendemos sobre commits continuam valendo aqui. A única diferença é que vamos trabalhar em uma nova "linha do tempo".
Vamos começar criando nossa nova branch. Nesse caso, vamos utilizar o seguinte comando:
$ git checkout -b nova_branch
O git checkout pode ser usado de algumas formas. Aqui, estamos utilizando-o para alterar a nossa branch da main para a nova_branch. Estamos utilizando a opção -b para informar ao git que essa branch que estamos tentando acessar é uma nova branch. Assim, o git irá criar essa branch e acessá-la.
Como podemos ver, estamos em uma nova branch. Vamos ver o git log dela:
Ué? O log é exatamente igual ao quando estávamos na main? Sim! Isso acontece porque só trocamos de branch, não criamos nenhum commit novo.
Porém, podemos visualizar que o HEAD ainda está no último commit que fizemos, mas está apontando para a nova_branch, indicando nosso ponto atual no “tempo”. A partir daqui, tudo o que fizermos na nossa nova "linha do tempo" será exclusiva dela.
Vamos fazer algumas modificações nos arquivos.
Realizei algumas modificações no nosso README e adicionei um novo arquivo. Vou realizar o commit e exibir o log para você:
Como esperado, o HEAD agora está no novo commit apontando para a nova_branch, e podemos ver que o commit anterior informa que é um commit da branch main, ou seja, não foi criado nessa nova branch.
Adicionando outro commit podemos ver que eles não possuem essa informação "main", comprovando que ele foi criado nessa nova_branch, que é a que estamos no momento:
Vamos voltar para a main e ver como está o log por lá? Para isso, basta usar o seguinte comando:
$ git checkout main
Vamos dar uma olhada no log:
Ué? Tudo que fizemos na outra branch não existe mais? Exatamente!
Lembra que eu disse que branchs são como "linhas do tempo" diferentes? Tudo que fizemos na nova_branch foi feito em uma “linha do tempo” separada da main e só existe lá. Por isso, usar branchs nos dá um poder gigantesco para trabalhar com desenvolvimento.
Dessa forma, podemos pegar um projeto, criar uma nova branch e fazer o que quisermos lá, sem alterações nada nosso projeto inicial. Assim, basta excluir a branch e será como se nada tivesse acontecido.
Mas e se depois de criar novas coisas em outra branch eu quiser adicionar ao projeto principal? Teria que voltar para a main e escrever tudo de novo? Se essas perguntas passaram pela sua cabeça, fique tranquilo! Caso você queira trazer as alterações que você fez em outra branch, basta uni-las utilizando o seguinte comando:
$ git merge <BRANCH>
O comando git merge serve para unir 2 branchs. Você informa a branch que deseja unir e ela será "mergeada" na branch atual que você está.
No nosso caso, nossa branch atual é a main e queremos "mergear" a branch nova_branch, para isso basta utilizar git merge nova_branch e o git trará as modificações da nova_branch para a branch main:
Vamos dar uma olhada no novo log?
Muito simples né? Agora todos os commits que fizemos na nova_branch estão na main.
Conflitos
Agora vamos falar de um dos maiores medos daqueles que começam a utilizar o git: os conflitos!
O nome pode parecer um pouco intimidador, mas, garanto que quando você terminar de ler esse artigo, verá que os conflitos não são nada demais. Os conflitos ocorrem quando 2 commits modificam o mesmo arquivo.
Estudando/trabalhando sozinho é bem difícil que você encontre um conflito. Geralmente, conflitos ocorrem quando existe mais de uma pessoa trabalhando no mesmo projeto, pois elas podem estar trabalhando em diferentes tarefas que necessitam modificar um mesmo arquivo.
Nesse caso, dependendo do que for modificado no arquivo, um conflito pode acontecer.
A seguir, criei um conflito para que você possa ver com mais clareza o que é isso. Comecei fazendo uma modificação na branch main no README.md, e criei um commit.
Em seguida, utilizei o comando git checkout nova_branch e realizei uma modificação na mesma linha que modifiquei o README na nossa branch main, e criar um commit.
Agora, para gerar o conflito, basta voltar para a branch main utilizando o checkout. Depois, basta utilizar o git merge novamente:
Agora se utilizarmos o git status, ele nos dirá onde se encontra o conflito:
Nosso conflito ocorreu no README (como esperado). Para ver o conflito, alguns editores de texto (vim, vscode, sublime, etc…) exibem conflitos de forma diferente dentro dos arquivos, porém, para exemplificar para todos, vamos utilizar o git diff README.md que aprendemos anteriormente.
Assim, independente do editor que você use, a visualização do conflito será a mesma, então vamos lá:
Podemos ver que ele tem uma linha <<<<<< HEAD, outra linha ======== e outra linha >>>>>> nova_branch.
Lembra que o HEAD simboliza a branch que estamos? Portanto o conteúdo entre <<<<HEAD e ====== são as modificações do commit que foram feitos na branch que você está atualmente, e o conteúdo entre ======= e >>>>>>> nova_branch, são as modificações que estão vindo da outra branch através do git merge.
Viu? É bem simples. O próximo passo é bem variável, pois você pode apagar a sua modificação e deixar somente a que está vindo, apagar a que está vindo e deixar a sua, manter as 2 modificações ou até mesmo apagar as 2 e criar uma nova linha.
Aqui, depende somente do que você julgar ser o melhor. No entanto, é preciso ter cuidado, pois se for uma linha de código, outras partes do sistema podem estar utilizando-a. Logo, considere analisar bem o que será feito.
Aqui, eu decidi remover as 2 modificações e criar uma nova que satisfaça as 2. (lembre-se sempre de remover os marcadores <<<<<< HEAD, ======= e >>>> branch, o git não os remove sozinho). Após resolver o conflito, eu usei o comando git diff para ver como ficou:
Agora, vamos utilizar o comando git add README.md e o git status novamente:
Agora, vamos utilizar o comando:
$ git merge --continue
Provavelmente, uma tela como essa abaixo se abrirá no seu terminal:
Essa é a mensagem de commit estendida, que dependerá do editor padrão configurado no seu computador. No meu meu caso é o vim, então, basta utilizar o comando :q para sair dessa tela - mas isso depende do editor padrão do seu computador (vale ressaltar que você pode editar essa mensagem). Utilizando o git log , agora podemos ver que foi criado um novo commit e a mensagem é referente ao merge:
Como foi necessário modificar os arquivos para remover os conflitos, o git cria um commit para salvar essas modificações.
Considerações finais
Nesse artigo, estudamos o básico de um fluxo de trabalho utilizando o git, aprendemos como criar commit, branchs e como resolver conflitos.
O git possui diversos comandos que não mencionei aqui, mas que valem a pena serem estudados, pois ajudam muito durante os problemas do dia a dia de um desenvolvedor.
Para te ajudar, deixei algumas documentações e um site que encontra o melhor comando para executar a ação que você precisa: o “Git Explorer”.
Além disso, busque criar commits atômicos, ou seja, objetivos. Suas mensagens de commit devem descrever exatamente o que seu commit faz, pois isso facilita a identificação do commit e em futuras manutenções do projeto.
Crie commits com poucos arquivos, tente realizar modificações isoladas. Modificar o comportamento de um método pode ser um commit, mas modificar um fluxo inteiro talvez possa ser quebrado em vários commits. A dica é: se você não conseguir resumir as modificações do seu commit em uma frase, talvez ele esteja modificando muitos arquivos.
Se você gostou de entender mais sobre o tema, que tal aprofundar os seus conhecimentos e descobrir tudo sobre Ruby?
Documentações
Referências
Escrito em 28 de Junho de 2022 por
Gabriel Sugai
Desenvolvedor web, formado em Mecatrônica Industrial pela FATEC-SA. Tem experiência na linguagem Ruby, em desenvolvimento orientado a testes, em nuvem e em programação orientada a objetos