Comandos do Git que provavelmente você não conhece
Comandos Modernos do Git e Features que Você Deveria estar Usando
Já se foram os dias em que os comandos básicos do git, como add
, commit
, push
e pull
, eram tudo o que usávamos, como se ainda estivéssemos em 2005. No mundo dinâmico do desenvolvimento de software, o git evoluiu significativamente, oferecendo uma série de recursos avançados que muitos de nós podem não estar aproveitando totalmente.
Como engenheiros de software que interagem com o git diariamente, é essencial manter-se atualizado com as últimas melhorias e ferramentas que ele oferece.
Este conteúdo visa iluminar alguns dos comandos modernos e menos conhecidos do git
que foram introduzidos ao longo dos anos, que poderiam simplificar significativamente nosso fluxo de trabalho e aumentar nossa produtividade.
Vamos explorar esses novos comandos do git e descobrir como eles podem transformar nossa experiência diária de programação.
Switch
A partir de 2019, mais precisamente, introduzido na versão 2.23 do Git, temos o comando git switch, que podemos usar para alternar entre branches:
git switch outra-ramificacao
git switch - # Voltar para a ramificação anterior, similar ao "cd -"
git switch ramificacao-remota # Alternar diretamente para uma ramificação remota e começar a rastreá-la
Isso é interessante, mas nós já estamos alternando entre branches no Git desde sempre usando o git checkout
, então por que a necessidade de um comando separado?
O git checkout
é um comando bastante versátil - ele pode (entre outras coisas) restaurar arquivos específicos ou até commits específicos, enquanto o novo git switch
serve apenas para mudar de ramificação. Além disso, o switch
realiza verificações de consistência adicionais que o checkout
não faz, por exemplo, o switch abortaria a operação se isso levasse à perda de alterações locais.
Restore
Outro novo subcomando/recurso adicionado na versão 2.23 do Git é o git restore
, que podemos usar para restaurar um arquivo para a última versão "commitada":
# Desfazer mudanças feitas em um arquivo, equivalente a "git reset some-file.py"
git restore --staged some-file.py
# Desfazer e descartar mudanças feitas em um arquivo, equivalente a "git checkout some-file.py"
git restore --staged --worktree some-file.py
# Reverter um arquivo para algum commit anterior, equivalente a "git reset commit -- some-file.py"
git restore --source HEAD~2 some-file.py
Os comentários no trecho acima explicam o funcionamento de vários comandos git restore.
Falando de forma geral, o git restore
substitui e simplifica alguns dos casos de uso do git reset
e git checkout
, que são recursos já sobrecarregados. Veja também esta seção da documentação para comparação entre revert,
restoree
reset`.
Sparse Checkout
O próximo recurso é o git sparse-checkout
, uma funcionalidade um pouco mais obscura que foi adicionada no Git 2.25, lançado em 13 de janeiro de 2020.
Suponha que você tenha um grande monorepositório, com microserviços separados em diretórios individuais, e comandos como checkout
ou status são extremamente lentos devido ao tamanho do repositório, mas talvez você realmente só precise trabalhar com um único subdiretório/árvore.
Bem, o `git sparse-checkout vem para o resgate:
$ git clone --no-checkout https://github.com/derrickstolee/sparse-checkout-example
$ cd sparse-checkout-example
$ git sparse-checkout init --cone # Configura o git para combinar apenas arquivos no diretório raiz
$ git checkout main # Faz checkout apenas dos arquivos no diretório raiz
$ ls
bootstrap.sh LICENSE.md README.md
$ git sparse-checkout set service/common
$ ls
bootstrap.sh LICENSE.md README.md service
$ tree .
.
├── bootstrap.sh
├── LICENSE.md
├── README.md
└── service
├── common
│ ├── app.js
│ ├── Dockerfile
... ...
No exemplo acima, primeiro clonamos o repositório sem realmente fazer o checkout de todos os arquivos. Em seguida, usamos git sparse-checkout init --cone
para configurar o git para combinar apenas arquivos no diretório raiz do repositório. Assim, após executar o checkout
, temos apenas 3 arquivos em vez de toda a árvore. Para baixar/fazer checkout
de um diretório específico, usamos git sparse-checkout set ...
Como já mencionado, isso pode ser muito útil ao trabalhar localmente com repositórios grandes, mas é igualmente útil em CI/CD para melhorar o desempenho de um pipeline, quando você deseja construir/implementar apenas parte do monorepositório e não há necessidade de fazer checkout de tudo.
Para uma descrição detalhada sobre sparse-checkout
, veja este artigo.
Worktree
Não é incomum que alguém precise trabalhar em múltiplas funcionalidades em uma única aplicação (repositório) ao mesmo tempo, ou talvez um bug crítico apareça enquanto você está no meio do desenvolvimento de uma solicitação de funcionalidade.
Nessas situações, você precisa ter múltiplas versões/ramificações do repositório clonadas, ou precisa guardar/descartar o que estiver trabalhando no momento. A resposta para essas situações é o git worktree
, lançado em 24 de setembro de 2018:
git branch
# * dev
# master
git worktree list
# /.../some-repo ews5ger [dev]
git worktree add -b hotfix ./hotfix master
# Preparando worktree (nova branch 'hotfix')
# HEAD agora está em 5ea9faa Commit assinado.
git worktree list
# /.../test-repo ews5ger [dev]
# /.../test-repo/hotfix 5ea9faa [hotfix]
cd hotfix/ # Worktree limpo, onde você pode fazer suas mudanças e enviá-las
Este comando permite que tenhamos múltiplas ramificações do mesmo repositório conferidas ao mesmo tempo. No exemplo acima, temos 2 branches, dev
e master
. Digamos que estamos trabalhando em uma funcionalidade na branch dev
, mas nos pedem para fazer uma correção de bug urgente. Em vez de guardar as mudanças e resetar a branch, criamos um novo worktree no subdiretório ./hotfix
a partir da branch master
. Podemos então ir para esse diretório, fazer nossas mudanças, enviá-las e retornar ao worktree original.
Para um artigo mais detalhado, veja este texto.
Bisect
Por último, mas não menos importante, o git bisect
, que não é tão novo assim (Git 1.7.14, lançado em 13 de maio de 2012), mas muitas pessoas ainda utilizam apenas recursos do git
de cerca de 2005, então acho que vale a pena mencionar de qualquer forma.
Conforme a página de documentação descreve: git-bisect
- Utilize a busca binária para encontrar o commit que introduziu um bug:
git bisect start
git bisect bad HEAD # Indique o commit com problema
git bisect good 479420e # Indique um commit que você sabe que funciona
# Bissectando: restam 2 revisões para testar depois desta (aproximadamente 1 passo)
# [3258487215718444a6148439fa8476e8e7bd49c8] Refatoração.
# Teste o commit atual...
git bisect bad # Se o commit não funcionar
git bisect good # Se o commit funcionar
# O Git bisecta a metade esquerda ou direita do intervalo com base no último comando
# Continue testando até encontrar o responsável
git bisect reset # Retorna ao commit original
Começamos explicitamente a sessão de bissecção com git bisect start
, após o qual fornecemos o commit que não funciona (provavelmente o HEAD
) e o último commit ou tag que sabemos que funciona. Com essa informação, o git
fará checkout de um commit no meio do caminho entre o commit "ruim" e o "bom". Neste ponto, precisamos testar se essa versão tem o bug ou não, então usamos git bisect good
para informar ao git que funciona ou git bisect bad
se não funcionar. Continuamos repetindo o processo até que não restem commits e o git
nos informará qual commit introduziu o problema.
Recomendo consultar a página de documentação, que mostra mais algumas opções para o git bisect
, incluindo visualização, repetição ou pulo de commits.
Conclusão
Se você procurar por algum problema relacionado ao git, é muito provável que acabe em uma pergunta no StackOverflow com uma resposta que possui milhares de votos positivos. Embora essa resposta provavelmente ainda seja válida, ela pode estar desatualizada, pois foi escrita há 10 anos. Portanto, pode existir uma maneira melhor, mais simples e fácil de fazer isso. Então, quando enfrentar algum problema com o git, recomendo verificar a documentação do git para comandos mais recentes, todos com excelentes exemplos, ou explorar as páginas do manual para descobrir muitas opções e flags que foram adicionadas aos comandos clássicos ao longo dos anos.
Créditos ao autor: Martin Heinz, confira na íntegra o conteúdo (link)