O Git é uma ferramenta poderosa para controle de versão e tem presença dominante nesta área. Para a maioria das tarefas do dia a dia, o Git pode ser simples de usar graças à repetição de comandos. No entanto, há muitas situações em que você precisa de mais do que o básico. Como tal, existem diversos comandos avançados do Git que podem elevar suas habilidades com a ferramenta a um novo patamar.

Isso também vai te apresentar vários conceitos do Git que você normalmente não encontraria. Por exemplo, como usar o armazenamento temporário, conhecido como stashing, em vez de fazer commits de mudanças, como fazer rebase e como adicionar arquivos à sua área de teste, também chamada de staging area. Ao dominar esses conceitos, você talvez descubra que eles são ainda mais úteis para a sua equipe.

Neste artigo, apresentamos diferentes comandos avançados do GIT que você vai querer conhecer. Contudo, antes de começar a utilizá-los, é importante ter algumas habilidades e compreender certos conceitos e informações. Vamos analisar isso primeiro.

Pré-requisitos recomendados

Embora você possa aprender o básico do Git e entender alguns dos comandos intermediários, como git delete, você precisa compreender mais ferramentas para lidar com comandos avançados.

As dicas que compartilhamos aqui não serão adequadas para um iniciante no Git, portanto, se o controle de versão, em geral, for novo para você, recomendamos que passe algum tempo usando os comandos básicos diariamente antes de tentar avançar no seu repertório.

Em resumo, aqui está uma lista rápida de aspectos que você precisa entender:

  • Conceitos básicos do Git, como commits, branches, pull requests e outros.
  • Familiaridade com os comandos básicos do Git, como git add, git merge, git commit e git push.
  • Para tarefas avançadas do Git, você precisa ser capaz de navegar em um Terminal.

É vantajoso ter experiência trabalhando com o Git em um ambiente de equipe, já que muitos desses comandos podem ter um impacto significativo em um código compartilhado. Por exemplo, você pode usar alguns desses comandos apenas quando estiver em uma posição de responsabilidade. Isso significa que você deve ser cauteloso e compreender quando é apropriado utilizar esses comandos.

Git avançado: 12 comandos poderosos que você vai querer conhecer

O restante deste artigo abordará 12 comandos avançados do Git que levarão você além do básico e o transformarão em um assistente do Git. Vamos começar com um comando que você talvez use mais do que outros.

1. Rebasing

Em primeiro lugar, o rebasing é um poderoso comando no Git que oferece uma alternativa às solicitações de pull. Ele permite que você integre todos os novos commits que você fez após uma divergência da branch em uma nova branch e insira as alterações no topo da base. Isso pode ser útil quando você deseja incorporar alterações de outra branch sem criar um commit de merge, por qualquer motivo.

Um caso de uso comum para o rebasing é quando você está trabalhando em um branch de funcionalidade e deseja incorporar as alterações da branch principal sem gerar um commit de merge. Isso ajuda a manter o histórico do projeto limpo, embora possa levar mais tempo para ser executado e você possa encontrar mais erros durante o merge.

Para fazer o rebasing de um branch, use o comando git rebase. Aqui está um exemplo em que estamos fazendo rebasing de uma branch para outra:

git checkout foo-branch

git rebase main

Você também pode listar os commits que pretende liberar e dar a você a chance de editá-los com antecedência. Portanto, é possível agrupar commits, editar mensagens de commit e realizar outras ações. Para isso, você pode utilizar a opção --interactive ou --i para executar um “rebasing interativo”

git rebase --interactive <other-branch-name>

Falando nisso, a redução de commits em um único para organizar um histórico de commits é um caso de uso comum para o rebasing. Isso pode tornar o histórico de commits mais fácil de ler e entender.

Para fazer isso durante um rebasing, você segue o sinalizador com o número de commits que deseja agrupar, o que combinará os commits em um só:

git rebase -i HEAD~3

Isso abrirá uma janela interativa de rebasing, muito parecida com uma janela de commit, na qual você pode escolher e editar os commits que deseja eliminar:

Executando um rebasing do git no Terminal.
Executando um rebasing do git no Terminal.

Você tem uma lista de commits na parte superior da tela e uma seleção de comandos na parte inferior, juntamente com algumas outras informações relevantes. A opção padrão é pick um commit, o que significa escolher esse commit sem efetuar alterações nele.

No entanto, existem muitos outros comandos que podem ajudar na navegação durante um rebase. Por exemplo, você pode reescrever uma mensagem de commit ou agrupar vários commits juntos. Para fazer essas alterações e utilizar os comandos, você precisará interagir com o editor do seu Terminal. O editor padrão costuma ser o Vim, portanto, é importante estar familiarizado com esse editor.

A etapa final é salvar suas alterações e, em seguida, enviá-las para a branch remota.

2. Revertendo, resetando e cancelando o ambiente de teste

O Git é notório quando se trata de desfazer alterações. Em geral, é um processo difícil, com uma tendência a gerar erros. No entanto, se você fizer alterações no diretório de trabalho ou na área de teste que deseja desfazer, existem alguns comandos do Git que podem ajudar.

Na verdade, o Git fornece orientação sobre como desfazer o estágio de um arquivo se você executar um git status:

O Git mostra como remover um arquivo da área de teste durante a exibição do status.
O Git mostra como remover um arquivo da área de teste durante a exibição do status.

Dessa forma, você pode remover um commit da branch atual e enviá-lo para outro lugar com facilidade:

git reset HEAD <commit>

Isso faz com que sua branch volte um commit, como se você removesse o último commit conhecido. Você pode até ter um caso de uso em que deseja redefinir uma branch para o seu estado original. Nesse caso, você pode redefinir em relação à origem remota, usando git reset --hard origin/main, por exemplo. No entanto, observe que essas alterações serão perdidas para sempre.

Embora o comando git checkout seja usado com frequência e seja considerado básico, você também pode usá-lo para remover o estágio dos arquivos antes de um commit:

git checkout -- <filename>

Observe o espaço entre os traços e o espaço reservado para o nome do arquivo. Aqui, o comando remove o estágio do arquivo que você especificar e descarta as alterações do diretório de trabalho. Observe que isso excluirá todas as alterações locais que você fizer em um arquivo. Portanto, certifique-se duas ou até três vezes de que realmente não precisa dessas alterações não salvas.

Você também pode utilizar o  git revert para desfazer as alterações feitas em um commit. No entanto, isso não desfaz as alterações, mas cria um novo commit que desfaz as alterações feitas no commit anterior.

A principal diferença aqui é que o comando não move nenhum ponteiro de indicação para o novo commit, mas mantém os commits antigos. Isso é útil quando você deseja desfazer alterações sem removê-las do histórico de commits.

O comando espera receber uma indicação e é simples reverter o commit mais recente:

git revert HEAD

No entanto, você tem muito mais possibilidades de restaurar e alterar arquivos e commits. As próximas duas entradas desta lista de comandos avançados do Git tratarão disso.

3. Restaurando arquivos para estados padrão

Com o Git, você pode restaurar facilmente um arquivo ao seu estado padrão usando um comando relativamente novo: git restore. Na verdade, você deve considerar esse comando como um substituto para git reset na maioria das circunstâncias, pois oferece recursos mais avançados. Por exemplo, você pode obter o mesmo resultado com git restore --staged <filename> e com git reset HEAD.

No entanto, o comando pode fazer mais: você também pode restaurar os arquivos para os estados padrão. Para isso, execute git status também:

git restore <filename>

Isso removerá as alterações do diretório de trabalho como se nada tivesse acontecido. Assim como em git checkout -- <filename>, você deve se certificar de que não quer nenhuma das alterações locais, pois elas serão irreversíveis.

4. Alteração de commits

Provavelmente haverá muitas ocasiões em que você enviará um commit e depois perceberá que esqueceu de incluir algo importante. Com o Git, você pode alterar facilmente o commit para incluir o necessário.

Para fazer isso:

  • Primeiro, faça as alterações nos arquivos que você precisa para o projeto.
  • Faça a preparação típica usando git add.
  • Recomende essas alterações na área de teste usando um comando diferente para fazer a confirmação:
git commit --amend

Isso faz uma alteração no commit original com o novo, usando a sua área de teste para isso. Portanto, certifique-se de que não precisa mais da versão anterior do commit, pois ela será perdida. Além disso, recomendamos o uso da opção --amend com commits locais em vez de commits remotos, pelos mesmos motivos que explicamos em outras partes deste artigo.

Você também pode usar git commit --amend para editar apenas a mensagem do commit com o seguinte comando:

git commit --amend -m "New commit message"

5. Registro no Git

O uso do registro do Git é valioso para ajudar você a entender o histórico de um repositório. No entanto, não classificaríamos o comando git log como avançado. Em vez disso, você pode usar várias opções para filtrar a saída de acordo com suas necessidades:

git log

git log --decorate

git log --stat

Por exemplo, ao adicionar decorações a uma entrada de registro, são impressos os nomes das referências para todos os commits exibidos. A opção --stat exibe as inserções e exclusões em um commit:

Executando um comando git log --stat no Terminal.
Executando um comando git log –stat no Terminal.

Você também pode usar outras opções para personalizar a saída do registro, o que é chamado de “limitação de commits.” Por exemplo, você pode usar os seguintes comandos:

git log --author=<author-name>

git log --grep=<pattern-string>

Aqui, você pode filtrar o registro por nomes de autores específicos ou padrões de texto. Na verdade, você pode combinar várias opções e sinalizadores para gerar um registro para uma finalidade específica. Por exemplo, veja este comando:

git log --oneline --author=<author-name> --since=<date> feature-temp

Isso busca todos os commits com a branch feature-temp de um único autor desde uma data especificada, e então os exibe usando entradas de linha única. Observe que o parâmetro <date> também pode ser uma string:

--since=”Two weeks ago”

Além disso, se quiser pesquisar um arquivo específico em vez de uma branch, você pode executar:

git log --oneline --author=bartonfink --since=”5 days ago” -- readme.rm

Esse conjunto de exemplos apenas mostra a superfície do que você pode fazer com seus registros, mas há muito espaço para encontrar commits exatos dentro deles com base nos seus critérios de pesquisa.

6. Hooks do Git

Você provavelmente usa macros e outros scripts automatizados para executar o código às vezes. O Git também inclui esse tipo de funcionalidade na forma de hooks. Esses scripts são executados automaticamente em resposta a determinados eventos, como commits ou pushes. Existem também muitas maneiras de usar os hooks para reforçar a formatação do código, executar testes e muito mais.

Existem dois tipos de hooks: no lado do cliente e no lado do servidor:

  • Os hooks do lado do cliente são acionados com base em ações locais, como commits e merges.
  • Os hooks do lado do servidor serão acionados devido a operações de rede. Isso pode ocorrer quando um repositório recebe um commit enviado, entre outros exemplos.

O Git sempre preencherá seu repositório com vários exemplos de hooks assim que você executar um  git init. No entanto, você precisa remover a extensão .sample para poder usá-los:

Uma pasta no macOS mostrando os hooks de exemplos que o Git instala na inicialização.
Uma pasta no macOS mostrando os hooks de exemplos que o Git instala na inicialização.

Observe que você só pode executar um tipo de hook por vez, embora seja possível usar vários scripts de uma só vez com algum trabalho adicional. Dessa forma, os nomes dos arquivos devem corresponder ao tipo de hook que você gostaria de usar com base nos scripts de exemplo: pre-commit, update e assim por diante.

Criando um hook do Git

Para criar um hook do Git, você precisa criar um script executável no subdiretório .git/hooks sem uma extensão. Ele ainda será executado, desde que você o adicione à pasta hooks.

Você pode usar qualquer linguagem de script que desejar, desde que ela possa ser executada como um executável. Sugerimos Ruby ou Python, mas você pode usar Bash, Perl e muitas outras. Tudo o que você precisa fazer aqui é alterar o caminho para o seu interpretador do padrão Bash:

#!/usr/bin/env python

A partir daí, você pode escrever seu código normalmente. Por exemplo, aqui está um script prepare-commit em Python que solicita ao usuário que escreva boas mensagens de confirmação:

#!/usr/bin/env python

import sys, os

path_commit_msg = sys.argv[1]

with open(commit_msg_filepath, 'w') as f:

f.write("# You’ll need to provide a better commit message than that, buddy!")

Embora nem sempre seja necessário, recomendamos que você execute o chmod +x .git/hooks/<hook-name> na linha de comando para garantir que possa executá-lo.

De modo geral, os hooks podem ser uma ferramenta poderosa para automatizar tarefas repetitivas e aplicar práticas recomendadas na sua equipe.

7. Referências de commits

No Git, você identifica os commits pelo hash de criptografia SHA-1. Embora seja possível fazer referência aos commits pelo hash completo, isso pode ser tedioso e suscetível a erros:

bc7623b7a94ed3d8feaffaf7580df3eca4f5f5ca

Em vez disso, o Git oferece várias maneiras de você se referir aos commits usando nomes mais curtos e mais fáceis de memorizar. Por exemplo, você pode usar um nome da branch ou tag. Por exemplo, considere uma branch chamada “develop”. Aqui está um exemplo em que nos referimos ao último commit nessa branch:

git diff develop..HEAD

Isso mostra as diferenças entre o último commit (HEAD) na branch “develop” e o commit atual.

Você também pode se referir a um commit por sua posição relativa no histórico de commits. Por exemplo, você pode se referir a dois commits antes do atual usando a abreviação HEAD~2:

git diff HEAD~2..HEAD

O Git também oferece várias outras maneiras de você se referir aos commits, como usar o símbolo “@” para se referir ao branch atual ou usar o símbolo “^” para se referir ao principal de um commit. Ao usar essas notações abreviadas, você pode economizar tempo e evitar erros ao trabalhar com commits.

8. Stashing

Em circunstâncias normais, você pensaria que não há como armazenar as alterações feitas nos arquivos sem fazer o commit. “Stashing” é a maneira de você fazer isso temporariamente. É útil quando você precisa trocar de branch ou trabalhar em uma tarefa diferente, mas não quer confirmar as alterações ainda.

Por exemplo, se precisar trocar de branch para trabalhar em algo no meio do fluxo, você pode armazenar as alterações na branch atual e fazer o checkout da outra. A partir daí, você pode trabalhar na outra branch, fazer o commit e enviar essas alterações. Em seguida, você pode fazer o checkout e recuperar seu trabalho na branch original.

Para armazenar as alterações, você pode fazer isso de duas maneiras:

git stash

Isso armazena suas alterações em um novo stash e reverte seu diretório de trabalho para o último commit HEAD (o estado em que você tinha antes de fazer novas alterações). Você pode listar as alterações usando git stash list e inspecionar o stash usando git stash show. O último comando também aceita qualquer formato aceito pelo git diff.

A partir daqui, você pode trocar de branch ou trabalhar em uma tarefa diferente. Quando você quiser recuperar suas alterações, execute o seguinte comando:

git stash apply

Isso aplicará as últimas alterações armazenadas ao seu diretório de trabalho. No entanto, observe que você ainda poderá se deparar com conflitos se alterar demais o arquivo. Afinal de contas, git stash é uma solução temporária para o problema que você está enfrentando.

Você também pode ter vários stashes e pode especificar qual stash aplicar usando o seguinte:

git stash apply stash@{n}

O espaço reservado {n} recebe um número inteiro, e stash@{0} representa o último stash. A documentação oficial do Git inclui alguns outros exemplos de git stash.

9. Bissetriz

Com certeza você já se deparou com um bug ou um problema e não tinha ideia por onde começar. Nessas situações, a “bissetriz” pode ajudar você a identificar rapidamente o commit que introduziu o problema.

Em resumo, o comando vasculha erros fazendo uma busca nos commits que você realizou. Se encontrar um commit com problema, ele vai te mostrar qual é. O que torna esse comando tão útil são todos os subcomandos que você pode utilizar com ele.

Para usar o bisecting, primeiro você precisa executar o comando git bisect start. O Git levará você ao primeiro commit no histórico do seu projeto.

A partir daí, você precisa indicar se esse commit é bom ou ruim usando os comandos relevantes:

git bisect good

git bisect bad

O Git levará você para o próximo commit para testar sua “qualidade” Observe que você também pode substituir “bom” por “antigo” e ruim por “novo” para corresponder ao seu caso de uso específico (embora não seja possível misturar os termos)

A partir daqui, você pode continuar a marcar cada commit como bom ou ruim até encontrar o commit que introduziu o bug. No entanto, você não precisa percorrer todos os commits – é possível especificar identificadores exatos para restringir e encurtar a pesquisa:

git bisect bad feature-test

Aqui, você usa o nome de um branch, mas poderia ser uma revisão específica usando um número inteiro, uma referência de hash e muito mais. Independentemente disso, após procurar e encontrar o bug, você pode executar um dos seguintes comandos para voltar ao seu código mais recente:

git bisect reset

Como acontece com todos os comandos avançados do Git nesta lista, existe muito mais a ser analisado, e a documentação do Git será uma leitura essencial para você.

10. Comparação de branches

Nossa entrada sobre referências de commit fala sobre o uso do git diff. Agora, é hora de analisar isso com mais detalhes. Muitas vezes você terá várias branches que contêm alterações diferentes. O Git permite que você compare as diferenças entre duas branches usando o comando git diff. Na verdade, você pode usá-lo de várias maneiras, muitas vezes em conjunto com outros comandos, para investigar e analisar um repositório.

O comando básico git diff fornecerá a você um resultado com uma visão geral das alterações. Ele se parece muito com o resultado de uma investigação de mesclagem de confirmação:

Mostrando a saída de uma solicitação de git diff.
Mostrando a saída de uma solicitação de git diff.

No entanto, você pode detalhar as branches exatas, os hashes e muito mais. Por exemplo, para comparar duas branches, você executa o comando git diff branch1..branch2 e substitui os espaços reservados:

git diff feature-branch pre-prod

Você também pode comparar as diferenças entre a branch atual e outra branch:

git diff HEAD..pre-prod

Observe que o uso de dois pontos aqui mostrará a diferença entre os pontos finais das duas branches. Em contrapartida, o uso de três pontos retornará a diferença entre o antecessor comum das duas branches e usará isso para o teste.

Assim como em git log, você pode limpar a saída e refinar o que ela retorna. Por exemplo, o git diff --name-only branch1..branch2 verificará apenas quais arquivos diferem e deixará de fora o contexto:

Executando um comando git diff --name-only no Terminal.
Executando um comando git diff –name-only no Terminal.

Você pode achar que a saída é difícil de analisar, especialmente se o “diff” for longo. Nesses casos, você pode usar a opção --color-words:

Executando o comando git diff --color-words e visualizando a saída no Terminal.
Executando o comando git diff –color-words e visualizando a saída no Terminal.

Em geral, o git diff pode ser tão poderoso quanto outros comandos, especialmente quando você invoca determinadas opções e refina as diferenças que retorna.

11. Aplicando commits individuais

Às vezes, você pode querer aplicar um commit específico de uma branch para outra sem mesclar as duas branches. O Git permite que você faça isso usando git cherry-pick. Você deve usar isso com cuidado, mas saiba que o git cherry-pick pode ajudá-lo em alguns cenários.

Uma situação é quando você tem branches de recursos desatualizados que não são mesclados em main ou trunk. Você pode usar uma combinação de comandos (como git log) para extrair commits antigos relevantes e reaplicá-los em outro lugar.

Use o registro git para encontrar a referência de um commit. A partir daí, certifique-se de que você está na branch para a qual gostaria de selecionar uma referência. Por exemplo, suponha que você queira selecionar o commit xxxxxaaaaaa na branch “trunk“. Primeiro, faça o checkout da sua branch.

git checkout trunk

…e depois faça o cherry-pick do seu commit:

git cherry-pick xxxxxaaaaaa

Sua mensagem de confirmação estará provavelmente desatualizada em muitas ocasiões. Para resolver isso, você pode passar a opção --edit para o comando. Isso permitirá que você forneça uma nova mensagem de confirmação antes de fazer o cherry-pick.

12. Melhorando o ‘git add’

Para o nosso último comando avançado do Git, mostraremos o git add. Este comando fundamental do Git possui algumas capacidades surpreendentes.

Por exemplo, se você estiver adicionando arquivos individuais à área de teste, poderá usar o seguinte:

git add -p

A opção -p permite que você prepare as alterações de forma interativa. Você pode revisar as alterações feitas em cada arquivo e, em seguida, escolher quais serão preparadas. Isso pode economizar muito tempo e ajudar você a evitar a preparação de uma alteração indesejada.

Embora você saiba que pode preparar arquivos individuais, também é possível especificar um diretório. Por exemplo, para preparar todos os arquivos no diretório “new-feature“, você pode especificar um diretório:

git add new-feature

Você pode até querer ver qual será o resultado de um git add sem executar o processo por completo. Você tem uma opção para isso:

git add --dry-run

git add -n

Quando você executar isso, o Git mostrará se irá adicionar ou ignorar os arquivos. Por falar em arquivos ignorados, você também pode adicioná-los ao ambiente de teste, se desejar:

git add --force

git add -f

Em termos simples, adicionar arquivos ao ambiente de teste não é apenas uma questão de “adicionar ou não adicionar”. Por isso, um dos comandos mais importantes do Git é versátil o suficiente para lidar com diversas situações diferentes.

Resumo

Uma vez que você domine os comandos básicos do Git, terá 80% do que precisa para executar as tarefas regulares de controle de versão em seu projeto. No entanto, é nos últimos 20% que os comandos avançados do Git podem realmente se destacar.

Comandos e técnicas como rebasing, bisecting, restauração de arquivos e outros podem ajudá-lo a sair de situações complicadas rapidamente. Além disso, você pode oferecer um valor significativo à sua equipe e projeto, ajudando a otimizar fluxos de trabalho, aumentar a produtividade e ter um impacto mais amplo como desenvolvedor.

Pretende usar alguns desses comandos avançados do Git no seu dia a dia? Compartilhe conosco na área de comentários abaixo!

Jeremy Holcombe Kinsta

Editor de Conteúdo & Marketing na Kinsta, Desenvolvedor Web WordPress e Escritor de Conteúdo. Fora do universo WordPress, eu curto praia, golfe e filmes. Também enfrento problemas de gente alta ;).