DEV Community

Cover image for Como mostrar apenas os commits da branch atual
Lucas Perez
Lucas Perez

Posted on Edited on

Como mostrar apenas os commits da branch atual

ðŸī󠁧ó Ēó Ĩó Ū󠁧ó ŋ English version of this text here!

Volta e meia eu crio aliases que executam comandos com algumas opçÃĩes que eu uso com frequÊncia. Um deles ÃĐ o meu alias para git log --oneline.

O problema ÃĐ que quando eu executo esse comando, vÃĄrios commits aparecem na minha tela atÃĐ que ela fique completamente cheia, enquanto que a Última linha indica que existem ainda mais commits. Se eu apertar q, eu volto para a minha linha de comando, mas o commit mais recente de todos serÃĄ empurrado para fora da tela (isso acontece comigo porque o meu prompt ocupa duas linhas).

imagem de commits do git preenchendo completamente a tela de um terminal

AlÃĐm desse problema específico do meu prompt grande, eu normalmente tambÃĐm quero apenas os commits na branch em que estou agora. Uma maneira simples que passou pela minha cabeça seria git log --oneline main..HEAD (ou talvez usando main^). Isso parecia apenas que seria mais um alias pra minha coleçÃĢo, mas daí eu lembrei que tenho projetos com branch a main e projetos com branch a master.

Decidi, entÃĢo, praticar minhas habilidades de shell script e fazer um programinha que decidiria automaticamente entre usar main ou master.

Primeiramente

Antes de começar, deixe-me planejar tudo que serÃĄ feito de antemÃĢo.

Se eu fosse escrever pseudo cÃģdigo desse script ou resumí-lo em passos, como seria?
AlÃĐm disso, o que deveria acontecer se eu nÃĢo estiver em um repositÃģrio git?
Vamos pensar sobre essas coisas enquanto escrevemos um plano:

Temos que:

  1. Imprimir alguma mesangem de erro e sair com cÃģdigo nÃĢo zero caso nÃĢo estejamos em um repo git
  2. Descobrir se ou main ou master estÃĢo disponíveis
  3. Executar git log main^/master^..HEAD se possível
  4. Imprimir alguma mensagem de erro e sair com cÃģdigo nÃĢo zero caso contrÃĄrio

1 - Verificar se estamos em um repositÃģrio git

Uma maneira simples, e nÃĢo muito boa, seria de apenas executar ls .git. Se sair 0, estamos num repositÃģrio git. Se nÃĢo, nÃĢo estamos.

Essa nÃĢo ÃĐ uma soluçÃĢo muito boa porque nÃĢo vai funcionar se estivermos dentro de um subdiretÃģrio de um repositÃģrio git. Temos que pensar em outra forma. Torcemos para que o git jÃĄ tenha uma maneira simples e fÃĄcil de verificar isso.

E certamente tem, jÃĄ que o git ÃĐ tÃĢo legal.

Uma pesquisa rÃĄpida no google me mostrou que o comando git rev-parse --git-dir pode ser usado para isso. man git rev-parse mostra mais detalhes, e a opçÃĢo --git-dir realmente parece uma boa opçÃĢo. Quando nÃĢo estamos em um repositÃģrio git, um erro serÃĄ impresso na tela e um cÃģdigo nÃĢo zero serÃĄ retornado, segundo o manual.

Eu nÃĢo estou realmente interessado na mensagem de erro, apenas no cÃģdigo de saída (zero ou nÃĢo zero).

Portanto, para verificar se estamos ou nÃĢo em um repositÃģrio git ao mesmo tempo que escondemos mensagens de erro, eu fiz assim:



#!/bin/sh

if [ ! "$(git rev-parse --git-dir 2> /dev/null)" ]; then
  echo Not in a git repository
  exit 1
fi


ðŸ”Ĩ āļ‚āđˆāļēāļ§āļ”āđˆāļ§āļ™: lucassperez/shell script para mostrar um range de commits ah - āļ›āļĢāļ°āđ€āļ”āđ‡āļ™āļĢāđ‰āļ­āļ™ ðŸ”Ĩ āļ‚āđˆāļēāļ§āļ”āđˆāļ§āļ™: lucassperez/shell script para mostrar um range de commits ah - āļ›āļĢāļ°āđ€āļ”āđ‡āļ™āļĢāđ‰āļ­āļ™

A sintaxe [ ... ] ÃĐ uma forma reduzida do comando test.
O ! vai inverter a verificaçÃĢo, isto ÃĐ, se o comando (nesse caso git rev-parse --git-dir) retornar 0, entÃĢo ele serÃĄ considerado "falso" ou que resultou em uma "falha".
O 2> /dev/null estÃĄ redirecionando a mensagem de erro para /dev/null. Isso ÃĐ uma maneira simples de apenas nÃĢo mostrar mensagens de erro na tela.

EntÃĢo basicamente o que isso estÃĄ fazendo ÃĐ verificando se o comando falhou. Se sim, significa que nÃĢo estamos num repositÃģrio git, entÃĢo uma mensagem de erro ÃĐ impressa e o script retorna 1. Do contrÃĄrio, nada acontece e podemos seguir para os nossos prÃģximos passos.

2 - Descobrir se main ou master existem

Podemos fazer isso usando o comando git branch e o comando grep, mas git rev-parse tambÃĐm pode fazÊ-lo.

A segunda opçÃĢo ÃĐ bastante simples, git rev-parse --verify <nome-da-branch> ÃĐ o suficiente (passe -q para suprimir mensagens de erro):



git rev-parse -q --verify main


ðŸ”Ĩ āļ‚āđˆāļēāļ§āļ”āđˆāļ§āļ™: lucassperez/shell script para mostrar um range de commits ah - āļ›āļĢāļ°āđ€āļ”āđ‡āļ™āļĢāđ‰āļ­āļ™ ðŸ”Ĩ āļ‚āđˆāļēāļ§āļ”āđˆāļ§āļ™: lucassperez/shell script para mostrar um range de commits ah - āļ›āļĢāļ°āđ€āļ”āđ‡āļ™āļĢāđ‰āļ­āļ™

Pra mudar um pouco, porÃĐm, vou fazer com o grep. Dessa forma, podemos aprender um pouquinho mais sobre regexes!

O comando git branch mostra todas as branches disponíveis na sua mÃĄquina local, com a branch atual sendo precedida por um *.
imagem do comando git branch mostrando mostrando as banches main e another-branch
Basicamente podemos usar o grep passando main ou master.

Existe um perigo, porÃĐm. Simplesmente executar:



git branch | grep main


ðŸ”Ĩ āļ‚āđˆāļēāļ§āļ”āđˆāļ§āļ™: lucassperez/shell script para mostrar um range de commits ah - āļ›āļĢāļ°āđ€āļ”āđ‡āļ™āļĢāđ‰āļ­āļ™ ðŸ”Ĩ āļ‚āđˆāļēāļ§āļ”āđˆāļ§āļ™: lucassperez/shell script para mostrar um range de commits ah - āļ›āļĢāļ°āđ€āļ”āđ‡āļ™āļĢāđ‰āļ­āļ™

vai retornar com sucesso se alguma branch contendo a palavra main existir.
imagem do comando git branch com grep mostrando a branch main, mas tambÃĐm a branch not-main

Para resolver esse problema, podemos usar uma expressÃĢo regular melhor do que apenas main. O padrÃĢo que buscamos ÃĐ:

  1. Começo da linha
  2. Possivelmente um *, mas poderia nÃĢo ter tambÃĐm
  3. Espaços em branco (a quantidade depende se um * estava lÃĄ ou nÃĢo)
  4. A palavra main (ou master) exatamente
  5. Final da linha

Vamos fazer por partes:

  1. O regex para o começo da linha ÃĐ ^
  2. Nos regexes, um * ÃĐ um quantificador, que significa "a coisa antes de mim entre 0 e infinitas vezes". Portanto, para encontrar literalmente um *, temos que escapÃĄ-lo: \*. AlÃĐm disso, para tornÃĄlo opcional, podemos usar o quantificador ?, que significa "a coisa antes de mim entre 0 e 1 vezes". Portanto, o regex pra isso tudo seria \*?
  3. Espaços em branco poderiam simplesmente ser um espaço ou \s. Este Último tambÃĐm encontra coisas como tabulaçÃĩes e quebra de linhas. Como a quantidade de espaços pode variar, podemos usar o quantificador *, resultando em \s*
  4. As palavras main ou master podem ser encontradas pelas palavras literais
  5. O regex para o final de uma linha ÃĐ $

Portanto, nosso regex para a branch main seria ^\*?\s*main$. Para a master, ÃĐ claro, ÃĐ extremamente similar.

Um ponto importante, apra usar alguns caracteres especiais no regex, o comando grep deve ser invocado com a flag -E (a opçÃĢo de regex extendido)!

O comando final para a branch main, entÃĢo, poderia ser:



git branch | grep -E '^\*?\s*main$'


ðŸ”Ĩ āļ‚āđˆāļēāļ§āļ”āđˆāļ§āļ™: lucassperez/shell script para mostrar um range de commits ah - āļ›āļĢāļ°āđ€āļ”āđ‡āļ™āļĢāđ‰āļ­āļ™ ðŸ”Ĩ āļ‚āđˆāļēāļ§āļ”āđˆāļ§āļ™: lucassperez/shell script para mostrar um range de commits ah - āļ›āļĢāļ°āđ€āļ”āđ‡āļ™āļĢāđ‰āļ­āļ™

Isso deve funcionar para nÃģs.

3 - Executar git log para a branch correta

Podemos fazer isso com uma sequÊncia de comandos if/elif. Se main existir, usamos main. Se nÃĢo, porÃĐm master existir, usamos master.

AtÃĐ poderíamos guardar o resultado do comando acima (git branch com grep) em uma variÃĄvel e verificÃĄ-la. Dessa forma nÃĢo teremos que executar git branch duas vezes. PorÃĐm, tambÃĐm podemos passar diretamente o comando inteiro para o if, assim:



if [ "$(git branch | grep -E '^\*?\s*main$')" ]; then
  git log main^..HEAD
  exit 0
elif [ "$(git branch | grep -E '^\*?\s*master$')" ]; then
  git log master^..HEAD
  exit 0
fi


ðŸ”Ĩ āļ‚āđˆāļēāļ§āļ”āđˆāļ§āļ™: lucassperez/shell script para mostrar um range de commits ah - āļ›āļĢāļ°āđ€āļ”āđ‡āļ™āļĢāđ‰āļ­āļ™ ðŸ”Ĩ āļ‚āđˆāļēāļ§āļ”āđˆāļ§āļ™: lucassperez/shell script para mostrar um range de commits ah - āļ›āļĢāļ°āđ€āļ”āđ‡āļ™āļĢāđ‰āļ­āļ™

Esse trecho ÃĐ razoavelmente simples. É verificado se main existe usando aquele regex que definimos. Se existir, usamos o git log no range saindo de main (incluída, pois adicionamos o ^) atÃĐ HEAD. Daí saímos 0 para finalizar o script (essa saída 0 provavelmente nÃĢo ÃĐ necessÃĄria e nem muito boa, pois se existir algum bug em nossa lÃģgica/regex, o programa pode falhar silenciosamente, retornando 0 apesar de um erro!)

4 - Imprimir mensagem de erro e sair nÃĢo zero caso main/master nÃĢo sejam encontradas

Podemos simplesmente adicionar um comando else para o trecho acima:



if [ "$(git branch | grep -E '^\*?\s*main$')" ]; then
  git log main^..HEAD
  exit 0
elif [ "$(git branch | grep -E '^\*?\s*master$')" ]; then
  git log master^..HEAD
  exit 0
else
  echo 'Neither main nor master branch found'
  exit 2
fi


ðŸ”Ĩ āļ‚āđˆāļēāļ§āļ”āđˆāļ§āļ™: lucassperez/shell script para mostrar um range de commits ah - āļ›āļĢāļ°āđ€āļ”āđ‡āļ™āļĢāđ‰āļ­āļ™ ðŸ”Ĩ āļ‚āđˆāļēāļ§āļ”āđˆāļ§āļ™: lucassperez/shell script para mostrar um range de commits ah - āļ›āļĢāļ°āđ€āļ”āđ‡āļ™āļĢāđ‰āļ­āļ™

Mas funciona?

Podemos testar nosso script agora! (:

Eu salvei um arquivo chamado git-log-main-master com nosso script e dei a ele permissÃĢo de execuçÃĢo. Vamos testÃĄ-lo:
imagem mostrando apenas commits de main atÃĐ HEAD

Isso foi legal. Mas serÃĄ que nÃĢo conseguimos fazÊ-lo melhor?

E se pudÃĐssemos passar flags do git log para nosso script?

Flags!

Isso ÃĐ bastante simples de se fazer. Em um shell script, a variÃĄvel especial $@ contÃĐm todos os argumentos passados ao script, entÃĢo podemos simplesmente adicionÃĄ-lo às nossas linhas com "git log":



if [ "$(git branch | grep -E '^\*?\s*main$')" ]; then
  git log main^..HEAD "$@"
  exit 0
elif [ "$(git branch | grep -E '^\*?\s*master$')" ]; then
  git log master^..HEAD "$@"
  exit 0
else
  echo 'Neither main nor master branch found'
  exit 2
fi


ðŸ”Ĩ āļ‚āđˆāļēāļ§āļ”āđˆāļ§āļ™: lucassperez/shell script para mostrar um range de commits ah - āļ›āļĢāļ°āđ€āļ”āđ‡āļ™āļĢāđ‰āļ­āļ™ ðŸ”Ĩ āļ‚āđˆāļēāļ§āļ”āđˆāļ§āļ™: lucassperez/shell script para mostrar um range de commits ah - āļ›āļĢāļ°āđ€āļ”āđ‡āļ™āļĢāđ‰āļ­āļ™

Agora se passarmos um monte de flags, serÃĄ executado o git log com essas opçÃĩes:

iamgem mostrando o script sendo executado com as flags --oneline e --graph corretamente

Mas serÃĄ que nÃĢo podemos tornar esse script ainda mais legal de usar? E se passÃĄssemos um nome de uma branch pra usar ao invÃĐs de main ou master?

Isso com certeza pode ser feito. Quem sabe pudÃĐssemos assumir que o primeiro argumento ÃĐ ou um nome de branch ou uma flag, e usar as variÃĄveis posicionais especiais $1, $2 etc.

Talvez o comando pudesse ser git log $1^..HEAD $FLAGS, onde $FLAGS seriam todos os argumentos passados menos o primeiro.

Isso envolveria um tratamento melhor e verificaçÃĩes pra ver se todos os argumentos passados sÃĢo somente flags (daí poderíamos manter main/master e $@) ou se um nome de branch foi passado. É certamente factível, mas vou deixar a possibilidade pra outro post por enquanto... 😅

Aliases...?

Como eu disse, costumo fazer aliases para comandos simples com flags que uso comumente. --oneline ÃĐ definitivamente uma das minhas opçÃĩes mais usadas com git log, e ÃĐ claro, eu fiz um alias:



alias gl='~/scripts/git-log-main-master --oneline'

ðŸ”Ĩ āļ‚āđˆāļēāļ§āļ”āđˆāļ§āļ™: lucassperez/shell script para mostrar um range de commits ah - āļ›āļĢāļ°āđ€āļ”āđ‡āļ™āļĢāđ‰āļ­āļ™ ðŸ”Ĩ āļ‚āđˆāļēāļ§āļ”āđˆāļ§āļ™: lucassperez/shell script para mostrar um range de commits ah - āļ›āļĢāļ°āđ€āļ”āđ‡āļ™āļĢāđ‰āļ­āļ™




Script no final das contas




#!/bin/sh

##############################
# Non zero exit codes:
# 1 - If not in a git repository
# 2 - If neither git branch main nor master is found
##############################

if [ ! "$(git rev-parse --git-dir 2> /dev/null)" ]; then
echo Not in a git repository

exit 1
fi

if [ "$(git rev-parse -q --verify main)" ]; then
git log main^..HEAD "$@"

exit 0
elif [ "$(git rev-parse -q --verify master)" ]; then
git log master^..HEAD "$@"

exit 0
else
echo 'Neither main nor master branch found'

exit 2
fi

ðŸ”Ĩ āļ‚āđˆāļēāļ§āļ”āđˆāļ§āļ™: lucassperez/shell script para mostrar um range de commits ah - āļ›āļĢāļ°āđ€āļ”āđ‡āļ™āļĢāđ‰āļ­āļ™ ðŸ”Ĩ āļ‚āđˆāļēāļ§āļ”āđˆāļ§āļ™: lucassperez/shell script para mostrar um range de commits ah - āļ›āļĢāļ°āđ€āļ”āđ‡āļ™āļĢāđ‰āļ­āļ™




Isso ÃĐ tudo por hoje

Ainda estou aprendendo o bÃĄsico de shell script, e deve haver maneiras melhores de se fazer isso. Qualquer comentÃĄrio e sugestÃĢo ÃĐ mais do que bem vindo! 😊

Top comments (0)