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 endpointsauth— Authenticationdb— Databasemodels— Data modelsservices— 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:
- Go to the repository
- Click "New Pull Request"
- Set base branch:
develop(ormainfor hotfixes) - Compare to your feature branch
- 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:
- Get approval from at least one reviewer
- Ensure all CI checks pass
- Ensure branch is up to date with develop:
git pull origin develop - 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
Signed Commits (Optional but Recommended)
# 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