Boas práticas GIT para pessoas e times
30 dicas especiais para Cloud Engineers.
O Básico
1. Configure corretamente nome e e-mail
Para que seus commits não sejam gravados com autor “root” e-mail “root@root” configure esses valores iniciais assim que instalar seu GIT.
$ git config --global user.name "Nome Sobrenome"
$ git config --global user.email "email@domain.ext"
Pode acontecer de ter que mudar de e-mail dependendo do projeto, nesse caso rode isso dentro do diretório do seu projeto para sobrescrever as configurações globais
$ cd meu_projeto/
$ git config user.name "Nome Sobrenome"
$ git config user.email "email@domain.ext"
2. Configure seu editor favorito globalmente
Eu gosto de usar o VIM
$ git config --global core.editor vim
3. Ative o autocorrect
O autocorrect vai te ajudar nos erros mais comuns, afinal quem nunca digitou git stats o bramch né?
$ git config --global help.autocorrect 10
olhe um exemplo quando digitamos BRAMCH ao invés de BRANCH
$ git bramch
WARNING: You called a Git command named 'bramch', which does not exist.
Continuing in 1.0 seconds, assuming that you meant 'branch'.
dev
prod
* main
olhe um exemplo quando digitamo STATS ao invés de STATUS
$ git stats
WARNING: You called a Git command named 'stats', which does not exist.
Continuing in 1.0 seconds, assuming that you meant 'status'.
On branch gh-pages
nothing to commit, working tree clean
É bastante útil não é?
O valor 10 declara 10x10 décimos de segundo, o mesmo que 1 segundo e por aí vai. Caso queira que corrija automaticamente sem aguardar, use o valor 1.
$ git config --global help.autocorrect 1
Dessa forma ele vai digitar o comando para você, veja mais detalhes no link abaixo
como desligar o autocorrect?
$ git config --global --unset help.autocorrect
4. Use uma versão atualizada do GIT
Normalmente o GIT que vem nas distribuições linux é bem antigo então é uma boa ideia atualizar se quer usar recursos mais recentes e versões com mais performance.
Se estiver no mac o Homebrew pode ajudar.
$ brew install git
Com isso você vai usar a última versão estável.
5. Crie aliases para agilizar seu trabalho
Atalhos para mais produtividade, o Git oferece aliases para que possamos economizar alguns caracteres, veja como usar
$ git config --global alias.co checkout
$ git co production
Switched to branch 'production'
outro exemplo
$ git config --global alias.st status
$ git st
On branch gh-pages
nothing to commit, working tree clean
Uma outra forma de criar aliases é editar seu gitconfig e setar manualmengte
$ vim ~/.gitconfig
Adicione uma sessão com essa
[alias]
co = checkout
st = status
Simples e rápido!
Junte seu time e defina os padrões que vão usar
Agora que seu GIT já está atualizado e configurado vamos definir algumas coisas.
6. Sente com seu time e formalize o padrão de versionamento que vão seguir
Combinar antes é sai mais barato do que arrumar depois, converse com seu time e defina:
- Convenções comuns
- Quais serão e como usar branchs de integração
- Quais serão e como usar branchs de features
- Quais serão e como usar demais branchs
- Padrão de nome de branchs para integração
- feature-xyz, hotfix-xyz, stage, test, prod
- Padrão esperado para commit, forma, mensagens
- Templates e forma de se fazer merge
- Regras gerais do que se deve ou se deve não fazer
Eu sugiro que crie um repo git e coloque tudo isso em formato MD, nada melhor do que versionar suas regras :)
Boas práticas com branchs
7. Use e abuse de branchs
O recurso de branch é fantástico, você pode criar a partir de qualquer uma.
Dicas principais:
- Evite gravar diretamente na main.
- Sempre trabalhe em uma branch separada
- Integre sua branch quando finalizar seu trabalho
- Apague sua branch depois que tiver terminado
Exemplo
$ git branch -u main correcao_criacao_vpc
$ git checkout correcao_criacao_vpc
Quando terminar seu ticket, apague a branch
$ git branch -D correcao_criacao_vpc
8. Use branchs de integração
Quando estamos trabalhando com integração contínua o uso de branchs de integração é fundamental, precisamos integrar nosso código com o código de nossos colegas e rodar os testes na pipeline.
Geralmente temos uma branch de integração para desenvolvimento e depois vamos promovendo esse código para outras branchs que vão nos ajudar a fechar a release e publicar, tudo depende do git-flow que seu time acordou e está seguindo.
9. Não escreva direto na branch MAIN
Evitamos escrever direto na branch main pois geralmente é a última versão estável devidamente testada e validada por todos, é de fato a fonte da verdade, portanto, para colocar código lá devemos sempre passar por diversos testes em sua pipeline e revisões de seus colegas.
10. Mantenha sua feature-branch atualizada
Faça rebases regulares para garantir isso!
Exemplo de atualização da branch main localmente e depois rebase
$ git checkout main
$ git pull
$ git checkout feature-xyz
$ git rebase main
Exemplo de merge do código com a main
$ git checkout main
$ git pull
$ git merge feature-xyz
Hoje em dia eu quase não faço merge no braço, geralmente uso MR ou PR, depende da ferramenta que estamos usando.
11. De vez em quando recrie suas branchs de integração
Isso é legal de fazer para dar uma limpada na coisa toda e começar novamente.
$ git checkout main
$ git branch -D devel
$ git branch -u main devel
12. Limpe periodicamente branchs de feature
O ideal é sempre apagar suas branchs de feature ou de teste após finalizar um ticket.
Apesar de ser o ideal, nem sempre lembramos, então de vez em quando é bom olhar e apagar branchs que não estão sendo usadas.
Pode-se até definir um tempo de vida para branchs que não são fixas, e definindo isso podemos até criar uma automação para limpar o repo.
Boas práticas com commit
13. Corrija as mensagens do seu commit se errar
Caso perceba algum typo na sua mensagem de commit, use o amend para corrigir
$ git commit -v --amend
14. Faça commits pontuais e objetivos
Evite fazer um commit com dezenas de arquivos, em especial se esses arquivos trazem mais de uma mudança ou correção. Devemos evitar isso pois fica difícil rastrear, entender e revisar o que foi feito no commit.
Prefira fazer commits pequenos e pontuais de algo que está terminado, algo que funciona e que não traga muitas alterações de uma vez só.
15. Faça commits atômicos quando possível
Já sabemos que commitar poucas alterações é o melhor caminho, mas dá para ser ainda menor.
Os commits atômicos são aqueles que gravam apenas uma única mudança – ainda que envolva vários arquivos – em um único commit.
É claro que nem sempre dá para fazer, mas é uma prática excelente se conseguir fazer.
A ideia do commit atômico é gravar a menor e mais importante melhoria que voce fez no código, sendo grande suficiente para adicionar algum valor, contudo, pequena o suficiente para ser gerenciada com flexibilidade.
Se quiser trabalhar dessa forma tenha em mente duas coisas:
- Trabalhe em uma coisa por vez
- Faça alterações pequenas e pontuais
16. Faça commits regulares e frequentes
Não espere demais!
Algumas pessoas esperam demais até gravar alguma alteração, às vezes ficam ali melhorando algo que já está funcionando, buscando algum tipo de perfeição antes de gravar.
Deixa eu te dizer uma coisa, o git funciona melhor e te ajuda mais quando você grava com frequência ao invés de esperar muitoooo tempo para gravar sua mudança.
Ao gravar com frequência você vai rastrear inclusive como você foi melhorando aquele código ao longo do seu processo e histórico de desenvolvimento.
E lembre-se, o GIT só cuida do seu código depois que você grava, se você fechar o editor por acidente ou se o editor travar, seu código já era, contudo, se estiver commitando com frequência você evita isso.
17. Quebre seu commit em commits menores
As vezes a gente vai trabalhando e se empolga demais, e com isso acaba fazendo mais de uma alteração em um mesmo arquivo, e neste caso, tais alteraçoes que poderiam ser commitadas de forma separada. Se for esse o caso, o commando abaixo te permite escolher quais mudanças você deseja commitar em um determinado arquivo.
$ git add -p <nome_do_arquivo>
Assim vamos conseguir commitar pequenas porções do arquivo por vez.
18. Não faça commit de algo que você não finalizou
Nunca, eu repito, nunca grave algo que não está funcionando ou que não está completo.
19. Teste seu código antes de gravar
Essa é uma das coisas mais básicas que vou falar hoje, mas tem que falar e tem que fazer.
Caso não saiba, gravar código quebrado é algo bastante incômodo, poderá irritar seus colegas, podendo em alguns casos chegar a ser considerado uma falta de respeito e falta de profissionalismo.
Verifique a sintaxe do seu código, rode um linter e execute o código para ver se o que fez está funcionando, seja uma feature, seja um bugfix, seja um hotfix, afinal, se o código estiver funcionando e se sua solução resolver o ticket, isso será o melhor dos mundos.
O git inclusive oferece um sistema de HOOKS que permite por exemplo, executar comandos de checagem antes de de gravar seu código, nesse caso estou falando do hook “pre-commit”, veja o link abaixo e leia sobre esse e outros hooks, é um recurso muito útil, acredite.
20. Escreva mensagens de commit claras
As mensagens precisam fazer sentido e ser úteis para todos do time.
20.1 Commitando em uma linha
A mensagem tem que fazer sentido, ser fácil de ler e ser suficiente para entender o que foi feito.
Exemplos
Podemos usar convenções para mostrar que fizemos uma correção
fix: corrige bug quando modulo vai crair a 2o VPC na AWS
ou uma refatoração
refact: refatora código que configura IAM para EKS na AWS
ou uma documentação
doc: adiciona docs para uso do modulo IAM/EKS
ou que inserimos testes
test: adiciona testes unitários no módulo
ou que criamos uma nova feature
feat: adiciona recurso para lidar com ALB no EC2/AWS
Entendendo a estrutura
É simples
feat: adiciona fature para recursos ALB no EC2/AWS #220412
^--^ ^-----------------------------------------^
| |
| +-> Sumário da sua mudança
|
+-------> Tipo: docs, feat, fix, refact, ou test.
Se você estiver usando um sistema de tickets junto, adicione o número do ticket na mensagem, sistemas como GitLab e GitHub já farão a associação para você entre a issue e o commit.
Evite colocar ponto final na mensagem, afinal é um título.
Vale lembrar que você deve evitar escrever mais de 50 caracteres ou vai quebrar a saída do “git log”.
De que modo escrever a mensagem?
Em alguns blogs vocês verão pessoas que defendam usar verbos no imperativo ou presente do indicativo, e faz sentido. Em ambos os casos a ideia é que o commit responda essa pergunta:
"Em caso de aplicar esse commit ele..."
Resposta
...altera código X
...corrige módulo Y
...refatora manifesto Z
...cria feature W para módulo X
Eu já gosto de usar particípio do passado, pois foi algo que já foi realizado e nem precisa fazer a perguntinha para ver como tem que escrever, neste caso você pode afirmar ao invés de perguntar, dessa forma:
"Nesse commit foi..."
Resposta
...alterado código X
...corrigido módulo Y
...refatorado manifesto Z
...criada a feature W para módulo X
Enfim, existem longas threads sobre isso na internet, quase uma guerra santa, contudo, IMHO isso vai depender de cada um, ou da forma como cada time decidiu trabalhar.
No final o importante é você versionar seu código e conseguir entender o que fez ali lendo a mensagem de commit :)
20.2 Usando o editor para algo mais detalhado
As vezes precisamos escrever um pouco mais, indo além do “one line commit”, especialmente se foi uma correção complexa, se tem alguma pegadinha, ou se for preciso explicar porque você fez aquilo daquela forma. No caso do trabalho e o dia-a-dia dos Cloud Engineers nem sempre é necessário, mas se for, veja como fazer.
Nesse caso, como é uma mensagem longa, não podemos fazer “one line commit”, temos que ir para o editor.
$ git commit
E escrever a mensagem
Assunto da mensagem com no máximo 50 caracteres, sem ponto final
Descrição em múltiplas linhas
sobre seu commit. Use até 72 caracteres
Outros parágrafos podem vir após inserir
uma linha em branco
Aqui nao tem mais limite de caracteres
Podemos usar bullets também, ajuda a organizar a informação
- Enumerando
- Alterações
- Realizadas
- Por
- Este
- Commit
Se existe um ticket coloque
o número dele na mensagem e os tickets relacionados
Esse commit resolve o problema do ticket #2222
E está relacionado com o ticket #3333 e #4444
É bem simples!
21. Não reescreva o histórico da branch principal
Se você já gravou o código na branch principal, e o código alterado já está disponível para outras pessoas verem, recomenda-se não alterar esse histórico.
Fazer rebase na MAIN ou qualquer que seja o nome da sua branch upstream, ou mesmo em uma branch de integração pode causar problemas para seus colegas e eles podem ter que lidar com conflitos ou ter que fazer stash e baixar toda a branch novamente. Fora que normalmente alterações nessas branchs geralmente acionam gatilhos em ferramentas de CICD, o que pode gerar um deploy com regressão.
Dito isso, muito cuidado com suas branchs, em especial a upstream e as branchs de integração.
Na sua branch de feature você faz o que quiser, use o rebase sem problema algum, mas só nela ok?
Boas práticas com merge
22. Faça squash antes de fazer um merge
Antes de fazer um merge verifique seu histórico de commit, veja se é possível melhorar o histórico, reduzir e juntar algumas coisas, as vezes 20 commits podem ser agrupados em 10, fica mais limpo, organizado e facilitará a revisão por seus pares.
$ git rebase -i HEAD~20 # apresenta os últimos 20 commits para fazer o squash
Faça o squash na sua branch de trabalho antes de mandar o PR/MR e altere apenas os seus commits ok?
23. Use e abuse de MRs e PRs no GitHub e GitLab
A vantagem de usar PR ou MR seja no GitLab ou GitHub é que você tem facilidades para fazer squash, resolver conflitos, enxergar o que mudou (diff), solicitar revisão de pares, receber comentários e então finalmente fazer o merge. São excelentes recursos e devemos usá-los pois facilitam nossa vida.
Outras coisas interessantes
24. Use nomes consistentes para seus remotes
Origin é um nome padrão, mas não é obrigatório tá?
$ git push origin main
Podemos mudar esse nome para dar mais contexto e ficar mais claro de qual remote estamos falando
$ git push gitlab main
$ git push github main
$ git push bitbucket main
$ git push clienteX main
Colocar um contexto no nome do remote ajuda bastante, especialmente se tem vários remotes.
25. Prefira autenticação SSH ao invés de user/senha
Autenticação através de chaves é mais segura, tanto que algumas ferramentas como GitHub desabilitam push em outros métodos.
Criando uma chave ssh segura (ed2559)
Como criar um chave segura?
$ ssh-keygen -o -a 100 -t ed25519 -f ~/.ssh/nome_da_sua_chave -C “nome@domain.ext”
Quer saber por que usar o ed25519?
Basicamente pois é um algoritmo mais moderno que usa curvas elípiticas, mais performático comparado com outras alternativas.
Se quiser saber mais mergulhe nesse post!
Definindo o uso de chaves ssh para repos específicos
No meu caso eu trabalho com várias chaves ssh, uma para projetos pessoais, uma para projetos na empresa que trabalho e sempre crio chaves para projetos ou freelas que eu estou fazendo.
É sempre bom evitar usar a mesma chave para tudo.
Mas como organizar isso?
Simples edite o arquivo ~/.ssh/config e configure a chave para cada server
Host nativeltrail_gitlab
Hostname gitlab.nativetrail.io
User git
IdentityFile ~/.ssh/id_ed2559_gitlab_nativetrail_key
Host client_x_gitlab
Hostname gitlab.cliente-x.com
User git
IdentityFile ~/.ssh/id_ed2559_gitlab_clientex_key
Host gitlab
Hostname gitlab.com
User git
IdentityFile ~/.ssh/id_ed2559_gitlab_key
Host github
Hostname github.com
User git
IdentityFile ~/.ssh/id_ed2559_github_key
Pronto, diferentes chaves para diferentes servidores e serviços.
26. Use e abuse do .Gitignore
O Gitignore é um arquivo essencial em nosso repositório, é através dele que dizemos para o GIT ignorar alguns arquivos e não versioná-los.
O Github traz uma bela coleção de templates para isso, veja no link abaixo:
usando o gitignore local
neste caso crie na raiz do diretorio um arquivo com o nome .gitignore e insira o que deseja ignorar.
_site
_temp
_build
*.zip
*.tar.gz
e pronto, seu git vai ignorar esses padroes, saiba mais na documentação:
usando o gitignore global
Esse arquivo é global e todos os projetos vão ler ele, é bem útil para coisas comuns e para projetos que ainda não tem um .gitignore construído
Criando o arquivo
$ touch ~/caminho/para/seu/global/.gitignore
Ativando via CLI
$ git config --global core.excludesFile ~/caminho/para/seu/global/.gitignore
Caso prefira edite seu .gitconfig diretamente e insira a configuração
[core]
excludesFile = ~/caminho/para/seu/global/.gitignore
No mac eu uso esse conteúdo
# General
.DS_Store
.AppleDouble
.LSOverride
# Icon must end with two \r
Icon
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# Files that might appear on external disks
.Spotlight-V100
.Trashes
# Vscode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/*.code-snippets
# Local History for Visual Studio Code
.history/
# Built Visual Studio Code Extensions
*.vsix
27. Use tags para criar referências no seu histórico
Tags que identificam milestones
$ git tag milestone-id -m
$ git push --tags
Tags que identificam um estado
$ git tag stable -m
$ git push --tags
Tags que identificam versões
$ git tag v1.2.3 -m
$ git push --tags
Existem várias formas de usar tags, seu uso facilita a identificação de um momento específico em seu histórico de desenvolvimento, tal como o fechamento de uma release, a conclusão de um milestones, a identifição e uma versão, o que possibilita que façamos clone do código naquele momento exato.
28. Se possível use versionamento semântico
Caso não conheça acessa o site https://semver.org
O versionamento semântico consiste basicamente no uso de três numeros que podem ser incrementados, como o exemplo abaixo:
2.3.5
MAJOR
O primeiro número é chamado de major, ele deve ser incrementando quando alguma mudança causa uma quebra de compatilidade de API
MINOR
O segundo número é chamado de minor, ele deve ser incrementado quando uma nova funcionalidade é adicionada, sem quebra de compatibilidade
PATCH
O terceiro número é chamado de patch, ele deve ser incrementado quando fazemos algum tipo de correção na versão minor
BUILD/RELEASE
Ao ler o semver.org você verá outras possibilidades de versionar, usando build number e release name, veja alguns exemplos:
1.0.0-alpha
1.0.0-beta
1.0.0-rc1
1.0.0-rc2
1.0.0+20130313144700
1.0.0-0.3.7
O versionamento semântico é bem flexível e fácil de usar, você vai ver.
Posso automatizar o incremento de versão?
Como as regras são claras fica fácil entender como incrementar a versões manualmente e podemos até mesmo automatizar isso em nossa pipeline.
Posso criar o meu próprio método?
Claro, cada time pode definir seu jeito de versionar, mas lembre-se criar um repo onde você explica isso para todo mundo, em formato MD. :)
29. Cuidado com Push usando FORCE
Quando você manda um
$ git push origin main --force
Você está sobrescrevendo tudo que tem no ORIGIN na branch MAIN.
Todo o cuidado é pouco, se for fazer avise a turma, peça permissão e faça um backup antes.
Quais problemas isso pode gerar?
Se alguém fez um push e você não atualizou sua branch local, os commits do coleginha serão perdidos.
Se alguém fez um clone e você mandou um force removendo várias coisas, no próximo pull o coleginha vai lidar com conflitos ou coisas piores, talvez tenha até que apagar o repo e baixar novamente.
Isso pode gerar algumas situações chatas com seu time, tome cuidado, use com cuidado.
30. Aprenda mais sobre o GIT e pratique
Aprender, entender e usar boas práticas vem com a experiência do dia a dia, quanto mais ler para conhecer seus recursos, quanto mais usar, mais precisará aprender, é assim que funciona.
Então vai lá e estuda!
Sucesso!
Refs
- https://deepsource.io/blog/git-best-practices/
- https://opensource.com/article/20/7/git-best-practices
- https://cbea.ms/git-commit
- https://github.com/git-tips/tips
- https://codeburst.io/git-tips-and-tricks-to-improve-your-git-workflow-3f8652fa4a62
[s]
Guto
Se gostou manda um alo no twitter @gutocarvalho.