Ficha 01 · Git fundamentos
- Commands
- Branches
- Merge
- Gitignore
Parte I · Comandos básicos
Exercício 1 · Setup (10 pts)
Listar comandos para: a) Configurar nome e email. b) Iniciar repo num projecto novo. c) Ver estado dos ficheiros. d) Adicionar ficheiro ao staging. e) Criar commit.
a) Configurar identidade:
git config --global user.name "Joana Silva"
git config --global user.email "joana@email.com"
b) Iniciar repo novo:
mkdir meu-projecto
cd meu-projecto
git init
c) Ver estado:
git status
Output exemplo:
On branch main
No commits yet
Untracked files:
ficheiro1.txt
ficheiro2.txt
d) Adicionar ao staging:
git add ficheiro.txt # específico
git add . # tudo na pasta actual
git add -A # tudo no repo
e) Commit:
git commit -m "Mensagem descritiva no imperativo"
# Ex: git commit -m "Add login page"
Exercício 2 · Workflow básico (15 pts)
Descreve passos para:
- Criar projecto novo "meu-site".
- Adicionar index.html e style.css.
- Fazer primeiro commit.
- Ver histórico.
# 1. Criar pasta e iniciar repo
mkdir meu-site
cd meu-site
git init
# 2. Criar ficheiros (no editor)
# Criar index.html com:
echo "<h1>Olá mundo</h1>" > index.html
# Criar style.css com:
echo "h1 { color: blue; }" > style.css
# 3. Verificar estado
git status
# Untracked: index.html, style.css
# 4. Adicionar ao staging
git add .
# 5. Verificar staging
git status
# Changes to be committed: index.html, style.css
# 6. Primeiro commit
git commit -m "Initial commit: add HTML and CSS"
# 7. Ver histórico
git log
# commit abc123...
# Author: Joana Silva
# Date: ...
# Message: Initial commit: add HTML and CSS
# 8. Versão compacta
git log --oneline
# abc123 Initial commit: add HTML and CSS
Notas:
- Mensagem em inglês é norma profissional.
- Imperativo presente: "Add" não "Added".
- Primeiro commit geralmente "Initial commit" ou similar.
- -m permite passar mensagem inline; sem ele, abre editor.
Parte II · Branches
Exercício 3 · Branches (15 pts)
Comandos para:
a) Criar branch feature/login.
b) Mudar para essa branch.
c) Criar branch + mudar de uma vez.
d) Fundir feature/login em main.
e) Apagar branch após merge.
a) Criar branch:
git branch feature/login
(Cria mas não muda — ainda estás em main.)
b) Mudar para a branch:
git checkout feature/login
# Ou (moderno):
git switch feature/login
c) Criar + mudar de uma vez (mais comum):
git checkout -b feature/login
# Ou:
git switch -c feature/login
d) Fundir em main:
# Mudar para main primeiro
git checkout main
# Trazer mudanças da feature
git merge feature/login
# Se tudo correr bem:
# "Fast-forward" ou
# "Merge made by the 'recursive' strategy"
e) Apagar após merge:
git branch -d feature/login
# -d é "safe delete" (só apaga se já merged)
# Forçar:
git branch -D feature/login
Workflow completo exemplo:
# Estás em main
git checkout -b feature/login
# Editar ficheiros...
git add .
git commit -m "feat(auth): add login form"
# Mais trabalho...
git commit -am "feat(auth): add login validation"
# Acabou a feature
git checkout main
git pull # actualizar main se trabalho em equipa
git merge feature/login
git push # publicar
git branch -d feature/login
Por que branches: - Experimentar sem afectar main. - Várias features paralelas sem conflito. - Histórico organizado.
Exercício 4 · .gitignore (10 pts)
Escreve .gitignore apropriado para projecto Node.js + React.
# === Node.js / npm / yarn ===
node_modules/
npm-debug.log*
yarn-debug.log*
yarn-error.log*
package-lock.json.bak
# === React build ===
build/
dist/
# === Environment variables (CRÍTICO) ===
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
# === IDE / Editor ===
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
.idea/
*.swp
*.swo
*~
# === OS ===
.DS_Store
Thumbs.db
desktop.ini
# === Logs ===
logs/
*.log
# === Testing ===
coverage/
.nyc_output/
# === Cache ===
.cache/
.eslintcache
.parcel-cache/
# === Temporary ===
*.tmp
*.temp
.tmp/
# === Optional npm cache directory ===
.npm
# === Optional eslint cache ===
.eslintcache
# === Microbundle cache ===
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# === Optional REPL history ===
.node_repl_history
# === Output of 'npm pack' ===
*.tgz
# === Yarn Integrity file ===
.yarn-integrity
# === Production build ===
build/
public/build/
# === Vercel / Netlify / etc ===
.vercel/
.netlify/
# === Local databases ===
*.sqlite
*.db
Princípios:
node_modules/OBRIGATÓRIO ignorar (pode ter milhões de ficheiros)..envOBRIGATÓRIO ignorar (passwords, API keys).build//dist/ignorar (são gerados, não fonte)..DS_Store(Mac),Thumbs.db(Windows) ignorar (lixo do OS).- Logs ignorar.
Template oficial GitHub: - github.com/github/gitignore/blob/main/Node.gitignore
Adicionar a repo existente:
Se já commitaste ficheiros que agora estão no .gitignore:
git rm --cached -r node_modules/
git rm --cached .env
git commit -m "chore: remove ignored files from tracking"
--cached remove do tracking mas mantém localmente.
⚠️ ATENÇÃO: se já commitaste .env com password real:
1. Revogar password imediatamente.
2. Mudar para nova.
3. Limpar histórico com git filter-branch ou BFG.
Parte III · GitHub
Exercício 5 · Conectar a GitHub (15 pts)
Tens projecto local. Quais os passos para o colocar no GitHub?
Passos: Local Project → GitHub
Pré-requisitos:
- Conta GitHub criada.
- Git instalado localmente.
- Repo local já inicializado (git init) com commits.
Passo 1 — Criar repo no GitHub:
- Login em github.com.
- New repository (botão verde).
- Preencher:
- Name:
meu-projecto(kebab-case). - Description: descrição curta.
- Public ou Private.
- NÃO "Initialize with README" (já temos código local).
- Sem .gitignore (já temos).
- Sem licença (adiciona depois).
- Create repository.
Passo 2 — Copiar URL:
GitHub mostra instruções:
- HTTPS: https://github.com/teu-utilizador/meu-projecto.git
- SSH: git@github.com:teu-utilizador/meu-projecto.git (preferível)
Passo 3 — Conectar local ao remote:
No directório do projecto local:
# Adicionar remote
git remote add origin git@github.com:teu-utilizador/meu-projecto.git
# Verificar
git remote -v
# origin git@github.com:teu-utilizador/meu-projecto.git (fetch)
# origin git@github.com:teu-utilizador/meu-projecto.git (push)
Passo 4 — Push inicial:
# Renomear branch master para main se necessário
git branch -M main
# Push pela primeira vez (-u define upstream)
git push -u origin main
Output:
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
...
To github.com:teu-utilizador/meu-projecto.git
* [new branch] main -> main
Branch 'main' set up to track remote branch 'main' from 'origin'.
Passo 5 — Verificar no GitHub:
Refresh página do repo no GitHub → código visível.
Passo 6 — Pushes seguintes (workflow normal):
# Editar ficheiros
# ...
git add .
git commit -m "feat: add new feature"
git push # já sabe push para origin/main (configurado com -u)
Setup SSH (se ainda não fez):
# 1. Gerar chave
ssh-keygen -t ed25519 -C "teu.email@example.com"
# (Premir Enter para path default)
# (Opcional: passphrase)
# 2. Iniciar ssh-agent
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
# 3. Copiar chave pública
cat ~/.ssh/id_ed25519.pub
# Copiar todo o output (começa com ssh-ed25519...)
# 4. No GitHub:
# Settings → SSH and GPG keys → New SSH key
# Title: "Laptop pessoal"
# Key: colar
# Add SSH key
# 5. Testar
ssh -T git@github.com
# Hi teu-utilizador! You've successfully authenticated...
Cenário alternativo — clone repo existente:
Se ainda não tens código local:
git clone git@github.com:teu-utilizador/meu-projecto.git
cd meu-projecto
# Trabalhar normalmente
Notas:
- Default branch: GitHub usa
main(antesmaster). - HTTPS vs SSH: SSH preferível (sem password a cada push).
- Personal Access Token: se usar HTTPS, GitHub requer PAT em vez de password desde 2021.
Exercício 6 · README profissional (10 pts)
Escreve template README.md para projecto de calculadora em Python.
# Calculator


A simple yet powerful command-line calculator built in Python, supporting basic arithmetic and advanced functions.
## Features
- ✅ Basic arithmetic: addition, subtraction, multiplication, division
- ✅ Advanced operations: powers, roots, percentages
- ✅ Memory functions: M+, M-, MR, MC
- ✅ History of last 100 operations
- ✅ Interactive mode and one-shot mode
- ✅ Configurable decimal precision
- ✅ Comprehensive error handling
## Installation
### From PyPI (recommended)
```bash
pip install simple-calculator
From source
git clone https://github.com/user/calculator.git
cd calculator
pip install -e .
Quick Start
Interactive mode
$ calc
Welcome to Calculator v1.0
> 5 + 3
8
> 10 * 7
70
> exit
One-shot mode
$ calc "5 + 3"
8
$ calc "sqrt(16)"
4
Usage
As a Python library
from calculator import Calculator
calc = Calculator()
result = calc.add(5, 3) # 8
result = calc.multiply(2, 7) # 14
result = calc.sqrt(16) # 4.0
# Chain operations
calc.add(5, 3).multiply(2) # 16
Configuration
Set precision (decimal places):
calc --precision 4 "1/3"
# 0.3333
Documentation
Full documentation available at docs/.
Development
Setup
git clone https://github.com/user/calculator.git
cd calculator
python -m venv venv
source venv/bin/activate # Linux/Mac
# venv\Scripts\activate # Windows
pip install -e ".[dev]"
Run tests
pytest
# With coverage
pytest --cov=calculator
# Specific test
pytest tests/test_calculator.py::test_addition
Code style
# Format
black calculator/
# Lint
flake8 calculator/
# Type check
mypy calculator/
Contributing
Contributions are welcome! Please read CONTRIBUTING.md for guidelines.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
This project is licensed under the MIT License — see the LICENSE file for details.
Acknowledgments
- Inspired by the original Unix
bccalculator - Thanks to all contributors
Contact
João Silva — @joaosilva
Project Link: https://github.com/joaosilva/calculator
**Princípios de bom README**:
1. **Nome + descrição** clara no topo.
2. **Badges**: build status, license (visual).
3. **Features** principais (bullet list).
4. **Installation** clara.
5. **Quick Start** mostra como usar imediatamente.
6. **Usage** detalhado com exemplos de código.
7. **Documentation** link para mais info.
8. **Development** secção para contribuidores.
9. **Contributing** convite explícito.
10. **License** clara.
11. **Contact** opcional.
**Markdown features úteis**:
- `# H1`, `## H2`, `### H3` headers.
- `**bold**`, `*italic*`.
- `` `code` `` inline.
- `[link](url)`.
- ``.
- Code blocks com ``` ```.
- Listas com `-` ou `1.`.
- Tabelas com `|`.
- Blockquotes com `>`.
**README é a primeira coisa que utilizadores vêem** — investir tempo nele.
</div>
## Parte IV · Pull Requests
### Exercício 7 · Criar PR (15 pts)
Descreve workflow completo para criar Pull Request.
<div class="resposta"></div>
<div class="solucao" markdown="1">
**Workflow Completo: Criar Pull Request**
**Cenário**: vais adicionar feature de "Esqueci password" ao site.
**Passo 1 — Sincronizar main**:
```bash
git checkout main
git pull origin main
Garante que tens versão mais recente antes de criar branch.
Passo 2 — Criar feature branch:
git checkout -b feature/forgot-password
Nomes: descritivo, kebab-case, prefixo de tipo.
Passo 3 — Trabalhar com commits frequentes:
# Editar ficheiros do formulário
# ...
git add src/components/ForgotPassword.jsx
git commit -m "feat(auth): add forgot password form component"
# Adicionar endpoint backend
# ...
git add src/api/auth.js
git commit -m "feat(auth): add forgot password API endpoint"
# Adicionar email service
# ...
git add src/services/email.js
git commit -m "feat(auth): integrate email service for password reset"
# Adicionar testes
# ...
git add tests/
git commit -m "test(auth): add tests for forgot password flow"
# Actualizar documentação
# ...
git add docs/
git commit -m "docs: document forgot password feature"
Princípios: - 1 propósito por commit. - Atomic (cada commit funciona sozinho). - Mensagens claras seguindo conventional commits.
Passo 4 — Push (regularmente):
# Primeira vez (define upstream)
git push -u origin feature/forgot-password
# Pushes seguintes
git push
GitHub mostra:
remote: Create a pull request for 'feature/forgot-password' on GitHub by visiting:
remote: https://github.com/org/repo/pull/new/feature/forgot-password
Passo 5 — Sincronizar com main (antes de PR):
git fetch origin
git checkout main
git pull
git checkout feature/forgot-password
git merge main
# Resolver conflitos se houver
git push
Garante que PR não vai ter conflitos.
Passo 6 — Abrir PR no GitHub:
- Ir para repo no GitHub.
- Aparece banner "Compare & pull request" — clicar.
Ou:
1. Pull requests tab.
2. New pull request.
3. base: main, compare: feature/forgot-password.
Passo 7 — Preencher PR:
Title (claro e descritivo):
feat(auth): Add forgot password flow
Description (completa):
## Description
Implements the forgot password feature, allowing users to reset their password via email.
## Changes
- Added `ForgotPassword` component with form validation
- Added `POST /api/auth/forgot-password` endpoint
- Integrated SendGrid for email delivery
- Added unit tests (95% coverage on new code)
- Updated user documentation
## Screenshots

## How to test
1. Go to login page
2. Click "Forgot password?"
3. Enter email
4. Check email for reset link
5. Click link → enter new password
6. Login with new password
## Checklist
- [x] Code follows project style (passes lint)
- [x] Tests added (95% coverage)
- [x] Documentation updated
- [x] Self-review done
- [x] No console.log left
- [x] No secrets in code
- [x] Manual testing done
## Related issues
Closes #123 (Forgot password feature request)
Related to #145 (Email service integration)
Reviewers (atribuir): - Tech lead. - Outro developer da equipa.
Labels:
- feature
- auth
Milestone (se aplicável): - v2.5.0
Linked issues:
- Closes #123
Passo 8 — CI corre automaticamente:
GitHub Actions executa: - Linter - Tests - Build - Security scan
Resultados aparecem no PR. Esperar passar antes de pedir review.
Passo 9 — Review process:
Reviewers comentam in-line ou no PR:
Exemplos: - "Suggestion: extract this logic to separate function for testability" - "Question: what happens if email service is down?" - "Nit: typo in comment" - "Blocker: missing input validation here"
Como autor:
Para cada comentário:
# Fazer mudanças localmente
git add fixes/
git commit -m "fix: address review comments — extract validation"
git push
Cada push actualiza PR automaticamente.
Responder a cada comentário: - "Fixed in [commit hash]" - "Good point, addressed" - "Discussion: I think the current approach is better because..."
Marcar conversation como resolved quando atendido.
Passo 10 — Iterar até aprovação:
- Pode demorar 1-2 dias com várias rondas.
- Não desistir.
- Não levar pessoal.
Passo 11 — Merge:
Quando: - Reviewers aprovam ✅ - CI passa ✅ - Conflitos resolvidos ✅
Merge button activo. Escolher strategy:
- Squash and merge: combina todos commits em um (limpo).
- Merge commit: mantém histórico individual.
- Rebase and merge: linear, sem merge commit.
Geralmente Squash para features pequenas (1 commit final por feature).
Clicar Squash and merge → confirmar mensagem → done.
Passo 12 — Limpar:
# Localmente
git checkout main
git pull
git branch -d feature/forgot-password
# A branch no GitHub é apagada automaticamente (se opção habilitada)
Passo 13 — Deploy (se CI/CD configurado):
Merge para main triggers deployment automático para staging/production.
Cenário alternativo — PR não aprovado:
Se reviewer pede changes major: 1. Discutir (talvez reunião curta). 2. Acordar abordagem. 3. Implementar. 4. Re-push. 5. Re-request review.
Se PR é rejeitado: - Abandonar (close PR). - Apagar branch. - Considerar abordagem diferente.
Tempos típicos: - PR pequeno (< 100 linhas): review em horas, merge em 1 dia. - PR médio (100-400 linhas): review em 1-2 dias, merge em 2-3 dias. - PR grande (> 400 linhas): review em dias, considerar dividir.
Princípio: PR pequenos são reviewed mais rapidamente.
Exercício 8 · Resolução de conflito (10 pts)
Estás a fazer merge e aparece conflito. Como resolver?
Resolver Conflito de Merge
Cenário:
git checkout main
git merge feature/x
Output:
Auto-merging app.js
CONFLICT (content): Merge conflict in app.js
Automatic merge failed; fix conflicts and then commit the result.
Passo 1 — Identificar ficheiros em conflito:
git status
Output:
On branch main
You have unmerged paths.
(fix conflicts and run "git commit")
Unmerged paths:
(use "git add <file>..." to mark resolution)
both modified: app.js
both modified: src/utils.js
Passo 2 — Abrir ficheiro em conflito:
code app.js # ou vim, nano, qualquer editor
Verás secções como:
function calculatePrice(items) {
<<<<<<< HEAD
// Versão da branch actual (main)
let total = 0;
for (let item of items) {
total += item.price;
}
return total;
=======
// Versão da branch a fundir (feature/x)
return items.reduce((sum, item) => sum + item.price, 0);
>>>>>>> feature/x
}
Marcadores:
- <<<<<<< HEAD: início do código da branch actual.
- =======: separador.
- >>>>>>> feature/x: fim do código da branch a fundir.
Passo 3 — Decidir resolução:
Opções:
Opção A — Manter versão actual (HEAD):
function calculatePrice(items) {
let total = 0;
for (let item of items) {
total += item.price;
}
return total;
}
Opção B — Manter versão da feature:
function calculatePrice(items) {
return items.reduce((sum, item) => sum + item.price, 0);
}
Opção C — Combinar / criar nova versão:
function calculatePrice(items) {
// Better: use reduce for cleaner code, with type check
if (!Array.isArray(items)) return 0;
return items.reduce((sum, item) => sum + (item.price || 0), 0);
}
Passo 4 — Editar manualmente:
- Remover marcadores (
<<<<<<<,=======,>>>>>>>). - Escolher / combinar código.
- Verificar que código compila / funciona.
- Guardar ficheiro.
Resultado final (escolhendo Opção C):
function calculatePrice(items) {
if (!Array.isArray(items)) return 0;
return items.reduce((sum, item) => sum + (item.price || 0), 0);
}
Passo 5 — Marcar como resolvido:
git add app.js
Passo 6 — Repetir para outros ficheiros em conflito:
code src/utils.js
# Resolver conflito
git add src/utils.js
Passo 7 — Verificar tudo resolvido:
git status
Output:
On branch main
All conflicts fixed but you are still merging.
(use "git commit" to conclude merge)
Changes to be committed:
modified: app.js
modified: src/utils.js
Passo 8 — Commit do merge:
git commit
Abre editor com mensagem pré-preenchida:
Merge branch 'feature/x' into main
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
Aceitar (geralmente) ou editar para clarificar.
Sair do editor = commit feito.
Passo 9 — Push:
git push
Cenários especiais:
Cenário A — Preferir totalmente uma versão:
# Manter versão actual (descartar feature)
git checkout --ours app.js
git add app.js
# Manter versão da feature (descartar actual)
git checkout --theirs app.js
git add app.js
Útil quando uma versão é claramente melhor sem necessidade de editar.
Cenário B — Conflito complexo, quero abortar:
git merge --abort
Volta ao estado anterior ao merge. Pode tentar novamente depois.
Cenário C — Ferramentas visuais:
VSCode (popular): - Abre ficheiro com conflito. - Mostra: - Botões "Accept Current Change" / "Accept Incoming Change" / "Accept Both Changes" / "Compare Changes". - Visual clara entre versões. - Click → resolve.
GitKraken / SourceTree: GUI completo com merge tool integrado.
Cenário D — Usar git mergetool:
git mergetool
# Lança ferramenta configurada (vimdiff, meld, kdiff3, etc.)
Configurável:
git config --global merge.tool meld
Cenário E — Conflito durante rebase:
Similar mas:
# Após resolver conflito
git add file.js
git rebase --continue
# Ou abortar
git rebase --abort
Prevenção de conflitos:
- Branches curtas (< 1 semana).
- Sync com main regularmente:
bash git fetch git merge origin/main # ou git rebase origin/main - Coordenar com equipa (não trabalhar todos no mesmo ficheiro).
- Estrutura modular do código.
- Style guide consistente (linter automático).
O que NÃO fazer:
❌ Ignorar conflito e commit com marcadores ainda lá:
<<<<<<< HEAD
// código quebrado
=======
Vai partir tudo.
❌ Eliminar mudanças ao calhar: - Antes de descartar, pensar por que essa mudança foi feita. - Talvez seja importante.
❌ Force push após resolver conflito em branch partilhada: - Pode estragar trabalho de outros.
❌ Apavorar-se: - Conflitos são normais em desenvolvimento colaborativo. - Resolver com calma. - Pedir ajuda se complicado.
Princípio fundamental: conflitos são oportunidade de revisar o código cuidadosamente e combinar o melhor de ambas as branches. Não é falha, é parte natural do processo colaborativo.