Git

O Git é um sistema de controle de versão distribuído, usado para gerenciar e rastrear mudanças no código-fonte de projetos. Ele permite que desenvolvedores trabalhem juntos de forma organizada, mantendo um histórico completo de todas as alterações. 

origin/main: repositorio de origem (no github) no branch/ramificação main (na linha do tempo principal)
local/main: repositorio local no branch principal

Em caso de salto de linha, a linha é completamente removida e inserida uma nova com o salto \n na hora de verificar o git.

É possivel utilizar o Git Bash para gerenciar suas versões (link). Para instalá-lo, haverá uma opção durante a instalação do git para permitir instalar o git bash Para verificar se o git foi instalado corretamente, abra o terminal e escreva git --version.

Um Pull Request (PR) é uma solicitação para mesclar mudanças de um branch para outro em um repositório Git, geralmente em plataformas como GitHub, GitLab ou Bitbucket. Ele é usado para revisar, discutir e aprovar alterações antes de integrá-las ao branch principal (como main ou develop).

🔗 Blobs, Trees e Commits
  • Blobs armazenam o conteúdo dos arquivos. são objetos no Git que armazenam o conteúdo de arquivos sem metadados.
  • Trees armazenam a estrutura do diretório e referenciam blobs.
  • Commits referenciam trees e armazenam metadados sobre mudanças.

Cada banch tem um arquivo com o nome da propria branch, que contém um apontamento para um hash de um commit. Quando usamos uma branch o Head muda o apontamento para ela.

Inicializar repositórios

O comando ssh-keygen é usado para gerar chaves SSH, que são como senhas seguras, mas muito mais protegidas e práticas. Na pratica serve para Autenticação segura sem digitar senha toda hora.

Ele cria dois arquivos:

  1. Chave privada → Fica no seu computador (NUNCA compartilha!)

  2. Chave pública → Você pode enviar para servidores, GitHub, GitLab, etc.

depois pegue a chave no caminho que foi salvo:  cat C:\Users\Diogo/.ssh/id_ed25519.pub (windows) ou /home/seu_usuario/.ssh/ (linux) e cole no github Settings → SSH and GPG keys → New SSH key.

bash
$ git config user.name "Seu Nome" # Configura o nome para usuário do projeto local (para global use --global)
$ git config user.email "seuemail@empresa.com"
$ git config --global init.defaultBranch main # Configurar para que todo novo repositório use main como branch principal
$ git init # Inicializa um repositório definido acima como main
$ git config --global user.name # Ver usuário global do Git, para usuários e email locais retire o --global
$ git config --global user.email
$ git config --list # Ver todas as configurações atuais do Git
$ ssh-keygen # Gerar chaves SSH, pressione enter
$ ssh -T git@github.com # testar se o acesso ssh funcionou

Comandos Git

Observe o comando -f no push com cuidado pois é um recurso perigoso que pode apagar trabalhos anteriores.

bash
$ # mostra os arquivos commitados com detalhes
$ git log --stat 
$ # mostra de forma resumida os commits
$ git log --oneline
$ # mostra as diferenças
$ git diff
$ # crase serve para destacar parte da mensagem
$ git commit -m 'mensagem `destaque`' 
$ # Adiciona todos os arquivos e já faz o commit no mesmo comando.
$ git commit -am 'Mensagem'
$ # emenda o mesmo commit(commits são imutaveis, por isso ele altera o commit original que terá um novo hash), ou seja cria um novo commit para substituir o commit anterior. Permite corrigir mensagens de commit, adicionar arquivos esquecidos ou remover arquivos do commit anterior.
$ git commit --amend
$ # Mesma coisa acima, mas pula a confirmação de mudança de nome do arquivo
$ git commit --amend --no-edit
$ # Mesma coisa acima mas atualiza apenas a data do commit
$ git commit --amend --data=now
$ # força um commit amend para substituir um arquivo no origin.
$ git push -f
$ # move/renomeia o arquivo
$ git mv nome_antigo.txt nome_novo.txt
$ # Restaura o estado do/dos arquivos não commitados
$ git restore .

Ao empurrar (push) uma nova branch pela primeira vez, o git deseja saber para qual repositório (origin) e o nome da branch na origin

Quando uma branch é enviada para a origin é criada uma branch local intermediaria (remote-tracking branch) que aponta para a branch la da origin. Ao deletar uma branch que já tem um tracking local com uma branch remota, apaga-se apenas o nome da branch (o ponteiro), mas não o commit, como na imagem abaixo:

Caso haja algum commit sem branch, e quiser o head neste commit, basta dar um git checkout nos primeiro numeros (nesse caso c5cc).

As três principais estratégias de branch são:

  • Trunk-based development (Desenvolvimento baseado no tronco): Tem a sua base no ramo main/principal.
  • feature branch: Para cada nova modificação no sistema se cria uma branch separada, e após o termino dessa nova modificação é feito um merge para a branch principal. Ou seja, tudo que está na branch main está pronto para ser rodado em produção.
  • Git flow: Nesse modelo tudo começa no main, mas ninguem modifica, criação um ramo develop (clone da main inicialmente) e é modificado por feature branch. Em paralelo se é encontrado um bug critico na main é criado uma branch hotfix para ajustes e correções que é mescado na main e na development. Depois que a feature é concluida vai para development e para revisão (release), e assim que concluida vai para main novamente.

Uma Feature Flag é uma técnica que permite ativar ou desativar funcionalidades de um software sem precisar alterar o código ou fazer um novo deploy. O código da nova funcionalidade já está na aplicação, mas fica "escondido" atrás de uma flag (chave/variável - uma especie de condicional).

Comandos Git Branch

bash
$ # Mostra a Branch
$ git branch
$ # Cria uma nova branch
$ git branch nome-da-branch
$ # Mudar de Branch
$ git checkout nome-da-branch
$ git switch nome-da-branch
$ # mostra a branch atual
$ git branch --show-current
$ # Cria e seleciona a nova branch, ou anexa o ponteiro de uma nova branch contra um commit sem branch
$ git checkout -b nome-da-branch
$ # Faz a mesma coisa do comando acima, mas aponta um hash de um commit para ser a base do branch 
$ git checkout -b nome-da-branch c55cs
$ # Empurra manualmente a nova branch
$ git push origin nome-nova-branch
$ # Empurra a nova branch e configura para empurrar apenas com um push automaticamente. configura uma remote-tracking branch.
$ git push --set-upstream origin nome-nova-branch
$ # Apaga uma branch, se já estiver feito o merge. com -D apaga mesmo sem merge.
$ git branch -d nome-da-branch
$ # Exibe todas as referencias que aconteceram no repositório
$ git reflog

As duas Formas de Merge do git são fast forward (avanço rápido) e  3-way merge (Mesclagem de três vias). 

Existem duas branchs na hora de um merge a target branch e a source branch. Entre na branch alvo e depois faça um merge com a branch fonte. 

Comandos Git Merge

bash
$ # Estando na branch alvo faça um merge com a fonte
$ git merge nome-branch-fonte
.gitignore
# Django #
*.log
*.pot
*.pyc
__pycache__
db.sqlite3
media

# Backup files #
*.bak

# If you are using PyCharm #
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/dictionaries
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.xml
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
.idea/**/gradle.xml
.idea/**/libraries
*.iws /out/

# Python #
*.py[cod]
*$py.class

# Distribution / packaging
.Python build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
.pytest_cache/
nosetests.xml
coverage.xml
*.cover
.hypothesis/

# Jupyter Notebook
.ipynb_checkpoints

# pyenv
.python-version

# celery
celerybeat-schedule.*

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# mkdocs documentation
/site

# mypy
.mypy_cache/

# Sublime Text #
*.tmlanguage.cache
*.tmPreferences.cache
*.stTheme.cache
*.sublime-workspace
*.sublime-project

# sftp configuration file
sftp-config.json

# Package control specific files Package
Control.last-run
Control.ca-list
Control.ca-bundle
Control.system-ca-bundle
GitHub.sublime-settings

# Visual Studio Code #
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.history

# Personal additions
__pycache__/
*.pyc
__localcode
venv
env
.DS_Store
local_settings.py
_local_settings.py
gunicorn-error-log
db.sqlite3
db copy.sqlite3
static/

arquivo completo de git ignore.

Comandos Git Bare (Repositório remoto)

O repositório Bare é um repositório Git que não tem cópia dos arquivos do projeto, apenas os dados do Git, ou seja, não há pastas como src/, index.html, app.py... só o conteúdo da pasta .git. Ele é feito para não ser editado diretamente, É ideal para ser usado como destino de push/pull entre desenvolvedores. Usado para repositório remoto/central. 
A ideia base seria ter duas pasta no servidor uma para ser a pasta bare -> nome-do-repo.git/ (para onde o commit do computador de desenvolvimento seria enviado - para onde faço o push) e outra a do repositorio do codigo fonte original -> app_repo/ (que puxa da pasta bare - de onde faria o pull).
app_bare/ — Uma pasta "pai", apenas para organizar e centralizar os repositórios bare que você tiver no servidor.
nome-do-repo.git/ — O repositório bare em si, que será iniciado dentro dessa pasta.
bash
$ # -p cria os repositórios pais ainda que eles não existam.
$ # Criar um repositório Bare
$ mkdir -p app_bare nome-do-repo.git
$ cd app_bare
$ git init --bare
$ 
$ # Criando o repositório da aplicação
$ mkdir -p app_repo
$ cd app_repo
$ git init
$ git remote add origin /app_bare/nome-do-repo.git/
$ git add . && git commit -m 'Initial'
$ 
$ # Adicionar o bare como remoto no computador local (não usar o ~, usar o caminho absoluto)
$ git remote add nome-do-repo ssh://usuario@IP_DO_SERVIDOR:/caminho/para/repo_bare.git
$ # OU
$ git remote add app_bare nome-do-repo:~/app_bare
$ git push app_bare main

GitHub Actions

O GitHub Actions é uma ferramenta de CI/CD (Integração Contínua e Entrega Contínua) integrada ao GitHub. Ele permite automatizar fluxos de trabalho, como testes, builds e deploys, sempre que há alterações no repositório. O fluxo deve ser escrito em um arquivo yaml.

Os actions são rotinas do github actions pre-programadas que podem ser usadas para realizar ações especificas.

É necessário definir a proibição dos merges para branch principal, caso os testes não passem. No projeto entre em Settings -> rules -> new ruleset -> Dê um nome e em Enforcement status clique em enable. Mais abaixo em Target branches -> selecione include default branch.

Crie um diretório .github/workflows na raiz do projeto para colocar os fluxos. No caso do fluxo de testes (tests.yaml), ao criar um pull request do codigo.  Na sessão show all checks irá aparecerer a rotina do arquivo de teste.

tests.yaml
# Define o nome do fluxo
name: Automated Tests

# Qual Evento o workflow deve esperar acontecer, nesse caso quando um PR acontecer
on: pull_request

# Quando o evento for disparado, execute as ações/trabalhos abaixo
jobs:
  jest:
    # Nome do Job
    name: Jest Ubuntu
    # Qual ambiente o job deve ser executado. O runner que irá executar os comandos
    runs-on: ubuntu-latest
    # Comandos que irão ser executados
    steps:
      # Uma action que puxa o código do repositório
      - uses: actions/checkout@v4

      # Uma action que configura o Node.js do projeto
      - uses: actions/setup-node@v4
        with:
          node-version: "lts/hydrogen"

      # Instala as dependências do projeto
      - name: Instalar dependências
        run: npm ci

      # Executa os testes do projeto
      - name: Rodar os testes
        run: npm test

O uso do npm ci ao invés do npm install, se da ao fato de que o ci instala apenas dependencias especificas do package-lock.json e se houver alguma atualização dos pacotes das dependencias ele ignora e instala a versão especifica.

linting.yaml
# Define o nome do fluxo
name: Linting

# Qual Evento o workflow deve esperar acontecer, nesse caso quando um PR acontecer
on: pull_request

# Quando o evento for disparado, execute as ações/trabalhos abaixo
jobs:
  prettier:
    # Nome do Job
    name: Prettier
    # Qual ambiente o job deve ser executado. O runner que irá executar os comandos
    runs-on: ubuntu-latest
    # Comandos que irão ser executados
    steps:
      # Uma action que puxa o código do repositório
      - uses: actions/checkout@v4

      # Uma action que configura o Node.js do projeto
      - uses: actions/setup-node@v4
        with:
          node-version: "lts/hydrogen"

      # Instala as dependências do projeto
      - name: Instalar dependências
        run: npm ci

      # Executa o prettier
      - name: Roda o Prettier
        run: npm run lint:prettier:check

Criar uma rotina para linting de codigo.