Git Methodology
Project: Open Source Languages · Team Size: 6 · Repository: Gitea · Versioning: Sprint-based major releases
1. Purpose
This document defines the Git workflow that every team member must follow throughout the project.
- Maintain a stable and functional codebase
- Minimise merge conflicts
- Ensure code is reviewed before integration
- Keep Git history clean and easy to understand
- Make changes traceable and accountable
- Standardise the team's development workflow
All members are expected to follow this methodology consistently from kickoff until final submission.
2. Repository Structure
The repository contains two long-lived branches.
| Branch | Purpose |
|---|---|
| main | Contains only stable, tested releases. Tagged with version numbers. Never used for day-to-day development. |
| develop | Primary development branch where completed features are integrated. Deployed to staging. |
- Never commit directly to main.
- Never commit directly to develop.
- All work must be completed on feature branches.
- All merges into develop must be done through Pull Requests.
- Only the lead merges develop → main at release time.
3. Branching Strategy
Every task should have its own branch, created from the latest version of develop.
Branch from develop, never from main. Merge back to develop via Pull Request. Only the lead promotes develop → main at release time.
4. Branch Naming Convention
| Prefix | When to Use | Example |
|---|---|---|
feature/ | Developing a new feature | feature/login-page |
bugfix/ | Fixing a bug | bugfix/login-validation |
refactor/ | Improving code without changing behaviour | refactor/auth-service |
docs/ | Documentation only | docs/setup-guide |
test/ | Writing or updating tests | test/login-api |
hotfix/ | Urgent fix to main (rare) | hotfix/security-patch |
chore/ | Configuration, tooling, or maintenance | chore/update-eslint |
Rules: lowercase only · hyphens between words · short but descriptive · no spaces · one branch = one task/story.
- ✅ Good examples
- ❌ Bad examples
feature/user-profile
feature/course-crud
bugfix/navbar-overflow
test/assessment-marking
docs/api-reference
refactor/database-layer
login
mybranch
Stuff
Fix
feature/new thing
FEATURE-EVERYTHING
5. Creating a Branch
# Always start from the latest develop
git checkout develop
git pull origin develop
# Create your branch
git checkout -b feature/your-feature-name
Never create branches from main or old commits. Always pull the latest develop first.
6. Commit Guidelines
Each commit should represent one logical change — e.g. complete login form, add API endpoint, fix validation bug, update documentation. Avoid combining unrelated work into a single commit.
A commit should be small enough to understand in 30 seconds by reading the title and message, but large enough that the project still builds and tests pass.
7. Commit Message Convention
Use Conventional Commits — a simple format that makes history readable and lets tooling (changelog generation, version bumping) work automatically.
| Prefix | When to Use | Example |
|---|---|---|
feature: | New feature | feature: implement login page |
fix: | Bug fix | fix: prevent duplicate bookings |
refactor: | Internal improvements (no behavior change) | refactor: simplify auth logic |
docs: | Documentation changes | docs: update api reference |
test: | Add or update tests | test: add login integration tests |
chore: | Maintenance, config, tooling | chore: update eslint config |
perf: | Performance improvements | perf: optimize course search query |
Rules:
- Present tense ("add" not "added")
- Lowercase after the colon
- Under 72 characters
- Describe what, not how long it took
- ✅ Good examples
- ❌ Bad examples
feature: add clinic search page
fix: prevent duplicate bookings
docs: update api documentation
refactor: split booking service
test: add login integration tests
chore: update prettier config
Updated code
Working
Changes
asdf
Final commit
WIP
7a. AI Usage Attribution
Per the course's AI policy, any commit that used AI assistance for code generation, editing, debugging, or tests must include an Assisted-by: trailer — a separate line at the end of the commit message, not folded into the subject line.
feat: add lesson CRUD and reorder endpoints
Assisted-by: Claude-Code[Claude Sonnet 5]
If multiple tools/models were used on the same commit, list them all:
Assisted-by: Claude-Code[Claude Sonnet 5], GitHub-Copilot[GPT-5.6-Sol]
Rules:
- The trailer goes on its own line, formatted exactly as
Assisted-by: <tool>[<model>]— not appended to the subject line with a hyphen or in parentheses. - Every repository must also declare, in its own
README.md, whether it uses AI code generation, AI inline editing, and AI code review — even if the answer is "no" for one of them. See the course's AI policy document for the exact required wording. - This applies regardless of how small the AI-assisted change was. If a commit had no AI involvement at all, no trailer is needed — don't add one speculatively.
- Commits missing this trailer, where AI assistance was actually used, are a violation of the course's academic integrity policy — this isn't optional stylistic guidance.
Every commit made with AI assistance across every service must include this trailer. Reviewers should check for it as part of PR review (Section 13), the same way they check for tests and lint.
8. When to Commit
Commit whenever a logical piece of work is complete:
- Feature implemented
- Bug fixed
- Tests written
- Component finished
- API endpoint completed
- Documentation updated
A teammate should always be able to pull your commit and successfully build the project.
- Broken code
- Unfinished features
- Temporary debugging code (console.logs, commented-out code)
- Large unrelated changes
.envfiles or secrets
9. Pushing Changes
git push origin feature/your-feature-name
Push regularly — don't wait several days before sharing your work. Pushing frequently reduces merge conflict risk.
10. Keeping Your Branch Updated
Before starting work each day or before opening a PR:
git checkout develop
git pull origin develop
git checkout feature/your-feature-name
git merge develop
Resolve any merge conflicts before continuing development. If conflicts are complex, ask a teammate for help — don't struggle alone.
11. Pull Request Workflow
Every completed feature must be merged using a Pull Request. No direct merges are permitted.
Opening a PR
- Push your branch:
git push origin feature/your-feature-name - Go to Gitea → Pull Requests → New Pull Request
- Set:
- Base branch:
develop - Compare branch:
feature/your-feature-name
- Base branch:
- Verify only intended changes appear
- Give the PR a descriptive title (should match your commit message)
- Write a short description using the template below
- Assign at least one reviewer
- Submit
PR Description Template
## Summary
Brief explanation of what this PR does.
## Changes
- Added login page
- Added auth middleware
- Added validation schemas
## Testing
- Tested locally with Vitest
- No known issues
- [Optional] Link to test results
## Related Issues
Closes #123
12. Pull Request Requirements
Before requesting a review, ensure:
- Project builds successfully (
npm run build) - All tests pass locally (
npm run test) - Linter passes (
npm run lint) - No merge conflicts exist
- Code is formatted (
npm run format) - No commented-out code remains
- No debugging statements remain
- Documentation updated (if needed)
-
.envfiles not committed
Husky will catch many of these automatically on commit, but check manually too.
13. Code Review
Every Pull Request requires at least one approval before merging.
Reviewers check:
- Code correctness and logic
- Readability and naming
- Adherence to coding standards
- Test coverage and quality
- No duplicate code
- No obvious performance issues
- Compliance with API conventions
As an author:
- Respond to comments respectfully
- Explain your reasoning if you disagree
- Push fixes and re-request review
- Don't merge until approved
Per the Project Plan, a PR touching schema.prisma or backend/shared (used by every service) should get review from whoever owns that file/service specifically, not just any available teammate — a mistake here affects everyone, not just one feature.
14. Merging Strategy
The team uses Squash and Merge — combining all commits into a single clean commit when merging into develop.
- Before squash
- After squash
c3a9f2: Added button
e1b4d8: Oops typo
f2c6a1: Fixed CSS
a7d9e2: Another fix
b8e3c4: Final fix
9k2m4p: feat: implement login page
Why squash merge?
- Cleaner Git history — easier to read and understand
- Easier to bisect bugs (
git bisectfinds the commit that broke something) - Cleaner release notes — one logical change = one line in the changelog
- Easier to revert — reverting one commit vs. reverting five
Most platforms default to allowing all merge types. Set branch protection rules to require squash merge and prevent direct pushes.
15. Deleting Branches
Once merged, delete the branch immediately:
# Delete locally
git branch -d feature/your-feature-name
# Delete on Gitea
git push origin --delete feature/your-feature-name
Stale branches clutter the repository and confuse new team members.
16. Versioning — Sprint-based Major Releases
Format: MAJOR.MINOR.PATCH, but simplified for this project: MAJOR is tied directly to sprint number, not to "breaking changes" in the traditional SemVer sense. This is a deliberate deviation from strict SemVer, chosen because it maps cleanly onto the brief's own milestone structure and is easy for the whole team (and a marking tutor) to reason about at a glance.
| Version | Meaning |
|---|---|
1.0.0 | Tagged at the end of Sprint 1 (Basic tier submission) |
2.0.0 | Tagged at the end of Sprint 2 (Intermediate tier, part 1) |
3.0.0 | Tagged at the end of Sprint 3 (Intermediate tier, part 2) |
4.0.0 | Tagged at the end of Sprint 4 (Advanced tier, final submission) |
MINOR and PATCH still follow standard SemVer meaning within a sprint, if tagging becomes useful at a finer grain than once-per-sprint:
- MINOR — a new backwards-compatible feature landing mid-sprint (e.g.
1.1.0) - PATCH — a bug fix landing mid-sprint (e.g.
1.0.1)
In practice, the team has only tagged at sprint boundaries so far — MINOR/PATCH tags are optional, not required.
Examples
1.0.0— Sprint 1 submission: auth, course/lesson CRUD, publish/unpublish, corrections, Browse2.0.0— Sprint 2 submission: assessments, forking, reputation, moderation basics3.0.0— Sprint 3 submission: full moderation workflow, discovery/notifications4.0.0— Final submission: selected Advanced-tier features, hardening
Traditional SemVer ties MAJOR to breaking API changes, which doesn't map naturally onto a course project graded by sprint milestone. Tying MAJOR to sprint number instead gives an immediate, unambiguous answer to "what state was the project in at each graded checkpoint" — which is what actually matters here.
17. Git Tags
Each official release receives a Git tag, created only for stable milestone releases (roughly at sprint ends).
# Create and push a tag
git tag -a v1.0.0 -m "Basic tier complete"
git push origin v1.0.0
Tags should match your version numbers. The lead creates tags at release time.
18. Daily Workflow
- Start your day: Pull the latest
develop - Pick a task: Choose a story from the sprint board
- Create a branch:
git checkout -b feature/story-id-description - Implement: Write code, tests, docs
- Commit regularly: Small, logical commits
- Push:
git push origin feature/your-branch - Open a PR: Describe the changes, request review
- Address feedback: Respond to review comments, push fixes
- Merge: Once approved and CI passes, merge via squash
- Delete branch: Clean up after yourself
19. Team Responsibilities
- Every Team Member
- Project Lead
- Follow this Git methodology strictly
- Work only on assigned tasks
- Keep commits small and meaningful
- Push changes at least daily
- Review teammates' PRs when requested
- Resolve merge conflicts promptly
- Delete branches after merging
- Write descriptive commit messages
- Protect the
mainanddevelopbranches - Enforce this Git methodology
- Approve releases (only lead can merge develop → main)
- Create release tags
- Coordinate development milestones
- Resolve escalated conflicts
- Update version numbers and CHANGELOG
20. Summary of Rules
| Rule | Policy |
|---|---|
Direct commits to main | ❌ Never |
Direct commits to develop | ❌ Never |
| Feature branches required | ✅ Yes |
| Pull Requests required | ✅ Yes, even for small fixes |
| Code review required | ✅ Minimum one approval |
| Squash merge | ✅ Always |
| Delete merged branches | ✅ Immediately |
| Sprint-based major releases | ✅ Yes |
| Tag official releases | ✅ Yes |
Keep main stable | ✅ Always |
21. Troubleshooting common Git situations
Real issues this team has actually hit — worth knowing before you hit them too.
"Your local changes would be overwritten by checkout" when switching branches
If the file is modified and tracked, git stash alone works. If the file is new/untracked (e.g. a work-in-progress file you haven't committed yet), plain git stash won't touch it and the checkout will still fail or silently carry the file onto the wrong branch. Use:
git stash -u
to stash untracked files too. Restore with git stash pop once you're back on the right branch.
package-lock.json merge conflicts
Don't try to hand-resolve this file — it's generated, not authored. Accept either side, then regenerate it properly:
git checkout --theirs package-lock.json
npm install
git add package-lock.json
A branch was created before develop moved on, and now has conflicts
Pull develop into your branch before opening (or before finishing) a PR that's been open a while:
git checkout your-branch
git pull origin develop
Resolve any conflicts that come up, same as any merge.
A folder won't delete ("EPERM: operation not permitted") Usually means something still has a file open inside it — another terminal, an editor, or (on Windows) antivirus real-time scanning. Close other processes, add a Windows Defender exclusion for the repo folder if this keeps happening, and retry. As a last resort, restart your machine to clear lingering file handles.
"Cannot checkout, would overwrite..." after git checkout <branch> with no local branch of that name
git checkout <branch-name> only works if a local branch by that name already exists. If it doesn't, create one tracking the remote explicitly:
git checkout -b <branch-name> origin/<branch-name>
Using the plain form on a branch that only exists remotely can silently do something other than what you expect (e.g. run the next command against whatever branch you were already on).
22. Appendix — Example Workflow
# Start the day
git checkout develop
git pull origin develop
# Create a feature branch
git checkout -b feature/write-1-create-course
# Implement, commit
git add src/course.model.ts src/course.controller.ts
git commit -m "feat: implement course creation endpoint" -m "Assisted-by: Claude-Code[Claude Sonnet 5]"
git add tests/course.test.ts
git commit -m "test: add course creation tests"
# Push
git push origin feature/write-1-create-course
# [Open PR on Gitea]
# [Wait for CI to pass and review]
# [Address feedback if needed]
# [Merge via Gitea UI — select "Squash and merge"]
# Clean up
git checkout develop
git pull origin develop
git branch -d feature/write-1-create-course
git push origin --delete feature/write-1-create-course
Following this methodology ensures the repository stays organised, development is predictable, and collaboration across 6 people stays efficient.