Skip to content

Git Workflow

This guide covers the Git workflow and best practices for the MenoTime project.

Branch Structure

MenoTime uses a modified Git Flow with three long-lived branches:

main (production)
  ↑
  └─ Merge from release/vX.X.X branches

staging (staging environment)
  ↑
  └─ Merge from develop branch

develop (integration branch)
  ↑
  └─ Merge from feature/bugfix/hotfix branches

Branch Naming Conventions

Use these prefixes for feature branches:

Type Prefix Example Purpose
Feature feature/ feature/add-patient-endpoints New functionality
Bug Fix bugfix/ bugfix/fix-auth-token-validation Fix a non-critical bug
Hotfix hotfix/ hotfix/fix-database-connection Critical production bug
Release release/ release/v1.2.0 Prepare a release
Chore chore/ chore/update-dependencies Maintenance tasks

Branch naming rules: - Use lowercase letters and numbers - Separate words with hyphens (kebab-case) - Be descriptive but concise - Reference issue numbers when applicable: feature/add-symptoms-#234

Creating a Feature Branch

From Develop (for features)

git checkout develop
git pull origin develop
git checkout -b feature/your-feature-name

From Main (for hotfixes)

git checkout main
git pull origin main
git checkout -b hotfix/fix-critical-bug

Commit Message Conventions

Follow the Conventional Commits standard:

<type>(<scope>): <subject>

<body>

<footer>

Types

  • feat — A new feature
  • fix — A bug fix
  • docs — Documentation changes
  • style — Code style changes (formatting, missing semicolons, etc.)
  • refactor — Code refactoring without feature or bug changes
  • perf — Performance improvements
  • test — Adding or updating tests
  • chore — Dependency updates, tool configuration

Scope (Optional)

The scope specifies what part of the codebase is affected:

  • api — API endpoints
  • auth — Authentication
  • db — Database
  • models — Data models
  • services — Business logic services

Examples

# Good feature commit
git commit -m "feat(api): add patient symptom tracking endpoint"

# Good bug fix
git commit -m "fix(auth): resolve JWT token expiration bug"

# Good documentation update
git commit -m "docs: update deployment instructions"

# Good test addition
git commit -m "test(api): add unit tests for patient creation"

# Good refactoring
git commit -m "refactor(services): simplify patient service logic"

# Good chore
git commit -m "chore: update FastAPI to 0.104.0"

Bad Commit Messages

# ❌ Too vague
git commit -m "fix stuff"

# ❌ Too long without breaking into body
git commit -m "Add patient endpoint and update models and fix database query and add tests"

# ❌ No type prefix
git commit -m "Added new feature for patient tracking"

# ❌ Using capital letters
git commit -m "FEAT(API): Add patient endpoint"

Pull Request Workflow

Step 1: Create the Pull Request

Push your branch to GitHub:

git push origin feature/your-feature-name

On GitHub, create a new PR:

  1. Go to the repository
  2. Click "New Pull Request"
  3. Set base branch: develop (or main for hotfixes)
  4. Compare to your feature branch
  5. Click "Create Pull Request"

Step 2: PR Title and Description

Use this template:

## Description
Brief description of the changes. What problem does this solve?

## Type of Change
- [ ] New feature (non-breaking change)
- [ ] Bug fix (non-breaking change)
- [ ] Breaking change (requires documentation update)
- [ ] Documentation update

## Related Issue
Closes #123

## Changes Made
- Change 1
- Change 2
- Change 3

## How to Test
1. Step 1
2. Step 2
3. Expected result

## Screenshots (if applicable)
[Add screenshots of UI changes]

## Checklist
- [ ] Tests added/updated
- [ ] Documentation updated
- [ ] No hardcoded secrets or sensitive data
- [ ] Code follows project style guide
- [ ] Self-review completed
- [ ] Migrations (if applicable) tested

## Notes
Any additional context for reviewers

Step 3: Code Review

Address feedback from reviewers:

# Make the requested changes
# ... edit files ...

git add .
git commit -m "refactor: address review feedback"
git push origin feature/your-feature-name

Don't force-push after review started, as it can hide discussion history.

Step 4: Approval and Merge

Once approved:

  1. Get approval from at least one reviewer
  2. Ensure all CI checks pass
  3. Ensure branch is up to date with develop: git pull origin develop
  4. Merge the PR on GitHub

Merge strategy: "Create a merge commit" (preserve full history)

# Alternative: merge locally
git checkout develop
git pull origin develop
git merge --no-ff feature/your-feature-name
git push origin develop

# Delete the feature branch
git push origin --delete feature/your-feature-name
git branch -d feature/your-feature-name

Keeping Your Branch Updated

Before submitting a PR, ensure your branch is up to date:

# Fetch latest changes
git fetch origin

# Rebase on develop (keeps history clean)
git rebase origin/develop

# Or merge (if you prefer explicit merge commits)
git merge origin/develop

# Push the updated branch
git push origin feature/your-feature-name

If there are conflicts:

# Resolve conflicts in your editor
# Then continue rebase
git add .
git rebase --continue

# Or abort if something goes wrong
git rebase --abort

Handling Merge Conflicts

If your branch has conflicts with develop:

# Fetch and rebase
git fetch origin
git rebase origin/develop

# You'll see conflict markers in affected files:
<<<<<<< HEAD
Your changes
=======
Incoming changes
>>>>>>> develop

# Edit files to resolve conflicts
# Then mark as resolved
git add .
git rebase --continue

# Push the updated branch
git push origin feature/your-feature-name --force-with-lease

Code Review Guidelines

As an Author

  • Keep PRs focused (one feature per PR)
  • Keep PRs small (under 400 lines changed)
  • Write clear commit messages
  • Respond to feedback promptly
  • Ask questions if unclear

As a Reviewer

  • Review for correctness and style
  • Check tests are comprehensive
  • Ensure database migrations are reversible
  • Verify no secrets are hardcoded
  • Be constructive in feedback
  • Approve when satisfied

What to Look For

# ✅ Good: Clear intent, tested
def create_patient(db: Session, patient_data: PatientCreate) -> Patient:
    """Create a new patient with validation."""
    if db.query(Patient).filter_by(email=patient_data.email).first():
        raise HTTPException(status_code=409, detail="Email already exists")
    patient = Patient(**patient_data.dict())
    db.add(patient)
    db.commit()
    db.refresh(patient)
    return patient

# ❌ Bad: No error handling, unclear logic, untested
def create_patient(db, data):
    p = Patient(email=data['email'], name=data['name'])
    db.add(p)
    db.commit()
    return p

Branch Protection Rules

The repository has these protection rules for main and develop:

  • Require pull request reviews before merging
  • Require status checks to pass (tests, linting)
  • Require branches to be up to date before merging
  • Require signed commits
  • Dismiss stale PR approvals
  • Restrict who can push to branch

Dealing with Mistakes

Uncommitted Changes

# See what changed
git status

# See the changes
git diff

# Discard changes
git checkout .

# Or save changes temporarily
git stash
git stash pop  # Restore later

Committed Changes (Not Pushed)

# Undo last commit, keep changes
git reset --soft HEAD~1

# Undo last commit, discard changes
git reset --hard HEAD~1

# Amend last commit
git add .
git commit --amend
git push origin feature/name --force-with-lease  # Only after amend

Committed Changes (Already Pushed)

# For feature branches, use revert (creates new commit)
git revert HEAD  # Reverts the last commit
git push origin feature/name

# For released code (main/develop), never force-push
# Always use revert to preserve history

Accidentally Pushed to Wrong Branch

# If you pushed to develop instead of feature branch:

# 1. Revert the commit on develop
git checkout develop
git pull origin develop
git revert COMMIT_SHA
git push origin develop

# 2. Create the feature branch from before the revert
git checkout -b feature/correct-name
git revert REVERT_COMMIT_SHA  # Undo the revert
git push origin feature/correct-name

Syncing with Upstream

If the repository is forked:

# Add upstream remote
git remote add upstream https://github.com/original-org/menotime-api.git

# Fetch upstream changes
git fetch upstream

# Update your develop branch
git checkout develop
git rebase upstream/develop
git push origin develop

Release Workflow

Creating a Release

# Create release branch from develop
git checkout -b release/v1.2.0

# Update version numbers
# Edit pyproject.toml or app/__init__.py
# Update CHANGELOG.md

git add .
git commit -m "chore: prepare release v1.2.0"
git push origin release/v1.2.0

# Create PR to main
# Get approval, then merge

Tagging a Release

# On main branch after merge
git checkout main
git pull origin main

# Create an annotated tag
git tag -a v1.2.0 -m "Release version 1.2.0"

# Push the tag
git push origin v1.2.0

# View the tag
git tag -l -n1 v1.2.0

Hotfix Workflow

# For critical production bugs

# Create hotfix from main
git checkout main
git pull origin main
git checkout -b hotfix/fix-critical-issue

# Fix the bug
# Test locally
# Commit

git add .
git commit -m "fix: resolve critical production issue"
git push origin hotfix/fix-critical-issue

# Create PR to main
# Get quick approval (target: 30 min)
# Merge to main

# Also merge back to develop
git checkout develop
git pull origin develop
git merge hotfix/fix-critical-issue
git push origin develop

# Delete hotfix branch
git push origin --delete hotfix/fix-critical-issue
git branch -d hotfix/fix-critical-issue

Best Practices

✅ DO

  • ✅ Pull before you push: git pull --rebase
  • ✅ Write meaningful commit messages
  • ✅ Keep branches up to date with develop
  • ✅ Test locally before pushing
  • ✅ Create small, focused PRs
  • ✅ Review other people's code
  • ✅ Use merge commits to preserve history
  • ✅ Sign commits with GPG (if configured)
  • ✅ Delete branches after merge
  • ✅ Use feature flags for incomplete work

❌ DON'T

  • ❌ Commit secrets or API keys
  • ❌ Force-push to main or develop
  • ❌ Merge without tests passing
  • ❌ Merge your own PR (get someone else to approve)
  • ❌ Make large commits with multiple unrelated changes
  • ❌ Commit commented-out code
  • ❌ Use generic messages like "fix bug" or "update code"
  • ❌ Rewrite published history
  • ❌ Leave stale branches

Useful Git Commands

# Show commits on your branch not in develop
git log develop..feature/your-branch --oneline

# Show what you've changed
git diff develop

# Show commits with more detail
git log --stat develop..HEAD

# Find which branch a commit is on
git branch --contains COMMIT_SHA

# Clean up deleted remote branches locally
git fetch -p
git remote prune origin

# Interactive rebase to clean up commits
git rebase -i develop

# Squash last 3 commits
git rebase -i HEAD~3
# Mark 2nd and 3rd commit as 'squash'

# View unpushed commits
git log origin/feature/name..feature/name

# View unmerged branches
git branch --no-merged develop

# Find commit that introduced a bug
git bisect start
git bisect bad  # Current commit is bad
git bisect good v1.1.0  # Last good version
# ... repeat until found ...

# Create a patch to share
git format-patch develop..feature/name
git apply fix.patch
# Generate a GPG key (one time)
gpg --gen-key

# Tell git to sign commits
git config --global user.signingkey YOUR_KEY_ID
git config --global commit.gpgsign true

# Sign a commit
git commit -S -m "feat: add feature"

# Verify a commit is signed
git log --show-signature

# Verify all commits in a branch are signed
git log --pretty=format:"%h %G? %s" develop..feature/name