Partilhar: WhatsApp
aulify
UC UC00617 · T. Desenv. Software

Ficha 01 · Git fundamentos

Comandos, branches, merge, .gitignore
Versão · Aluno
Tempo · 60 minutos
Cotação · 100 pontos
Aluno(a)
Turma
Data
Objectivos da ficha

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:

  1. node_modules/ OBRIGATÓRIO ignorar (pode ter milhões de ficheiros).
  2. .env OBRIGATÓRIO ignorar (passwords, API keys).
  3. build/ / dist/ ignorar (são gerados, não fonte).
  4. .DS_Store (Mac), Thumbs.db (Windows) ignorar (lixo do OS).
  5. 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:

  1. Login em github.com.
  2. New repository (botão verde).
  3. Preencher:
  4. Name: meu-projecto (kebab-case).
  5. Description: descrição curta.
  6. Public ou Private.
  7. NÃO "Initialize with README" (já temos código local).
  8. Sem .gitignore (já temos).
  9. Sem licença (adiciona depois).
  10. 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:

Exercício 6 · README profissional (10 pts)

Escreve template README.md para projecto de calculadora em Python.

# Calculator

![Tests](https://github.com/user/calculator/actions/workflows/tests.yml/badge.svg)
![License](https://img.shields.io/badge/license-MIT-blue.svg)

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.

  1. Fork the repository
  2. Create a feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

This project is licensed under the MIT License — see the LICENSE file for details.

Acknowledgments

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)`.
- `![alt](image-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:

  1. Ir para repo no GitHub.
  2. 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

![Forgot password form](url-to-screenshot.png)

## 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:

Passo 11 — Merge:

Quando: - Reviewers aprovam ✅ - CI passa ✅ - Conflitos resolvidos ✅

Merge button activo. Escolher strategy:

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:

  1. Remover marcadores (<<<<<<<, =======, >>>>>>>).
  2. Escolher / combinar código.
  3. Verificar que código compila / funciona.
  4. 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:

  1. Branches curtas (< 1 semana).
  2. Sync com main regularmente: bash git fetch git merge origin/main # ou git rebase origin/main
  3. Coordenar com equipa (não trabalhar todos no mesmo ficheiro).
  4. Estrutura modular do código.
  5. 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.