A Practical Git Lunch-and-Learn: A Branch-First, Rebase-Driven Collaboration Workflow
A Practical Git Lunch-and-Learn: A Branch-First, Rebase-Driven Collaboration Workflow
If you’ve ever wrestled with merge conflicts at 4 a.m., you’re not alone. The truth is, most teams don’t need every feature Git offers; they need a workflow that reduces friction, preserves a clean history, and makes collaboration predictable. This guide presents a branch-first, rebase-driven workflow that works well for small-to-medium teams. It emphasizes clear branch semantics, lightweight rebasing for feature work, and a disciplined release cadence. You’ll find actionable steps, concrete commands, and a complete checklist you can adapt to your project.
Table of contents
- Why a branch-first workflow
- Core principles you’ll adopt
- Setting up repository conventions
- Branch model and naming
- Daily workflow: from kickoff to review
- Handling conflicts with rebase
- Integrating with CI/CD
- Release tagging and changelogs
- Common pitfalls and how to dodge them
- Example run-through: a feature in three commits
- Tooling you might add
Why a branch-first workflow
- Isolates work: Each feature or bug fix lives on its own branch, reducing risk to main.
- Lightweight history: Rebasing keeps a linear, readable history without the noise of too many merges.
- Predictable reviews: PRs or merge requests become focused on a single intent with a clear narrative.
- Safer rollbacks: You can revert a single branch’s changes without impacting others, provided you release via well-defined tags.
Core principles you’ll adopt
- Branch per feature or task: Each item on the to-do list gets a dedicated branch.
- Rebase over merge for feature commits: Rebase your feature branch onto the latest main before merging.
- Fast, small commits: Commit frequently with meaningful messages; avoid back-to-back “work in progress” commits.
- Continuous integration on short-lived branches: CI runs on pull requests to catch issues early.
- Immutable main in production cadence: Main (or master) reflects production-ready state only after a verified release.
Setting up repository conventions
- Require branch names that reflect the task type and a short description. Examples:
- feature/login-improvements
- fix/memory-leak-accounts
- chore/docs-update
- Ensure protected main branch:
- Require pull requests for changes
- Run CI on PRs
- Require at least one approved review
- Enforce linear history if your team prefers it (see rebasing section)
- Commit message guidelines:
- Use imperative mood: “Add,” “Fix,” “Refactor”
- Include a brief context: (e.g., “Add authentication retry on 503”)
- Optional footer: “Closes #123” or “Relates to #456”
Branch model and naming
- Main branch: main (or master)
- Feature branches: feature/-
- Bugfix branches: fix/-
- Chore/docs: chore/
- Release branches (optional for larger teams): release/v1.2.x
- Hotfix branches (emergency fixes on production): hotfix/
Daily workflow: from kickoff to review
1) Kickoff
- Create a new branch from main:
- git checkout main
- git pull rebase
- git checkout -b feature/user-auth-refresh
- Start with a clear objective in your branch’s first commit.
2) Work and commit
- Work in small, focused steps. Each commit should:
- Address one logical change
- Have a meaningful message
- Include tests or update tests when possible
- Example commits:
- Add JWT refresh flow to auth service
- Update unit tests for token expiry edge case
- Update API docs for new endpoint
- Regularly push to the remote feature branch to back up progress:
- git push -u origin feature/user-auth-refresh
3) Rebase regularly to keep history clean
- Before opening a PR, rebase your branch onto the latest main:
- git fetch origin
- git rebase origin/main
- If you encounter conflicts:
- Resolve them in your editor
- Continue with: git add and git rebase continue
- After rebasing, force-push your updated branch:
- git push force-with-lease
4) Review and refine
- Open a pull request against main.
- Address review comments with small, discrete commits (rebasing again is optional for small tweaks).
- If multiple people work on the same area, consider squashing minor fixups during the review to keep the mainline clean.
5) Merge strategy
- Use “squash and merge” or “rebase and merge” depending on your policy:
- Squash keeps a single, cohesive feature commit on main.
- Rebase and merge preserves individual commits but requires a clean history.
- If your policy is strictly linear history, use rebase and merge with a final rebase of the PR branch onto main before merging.
6) Release preparation
- After merging, update changelog and tags:
- git fetch tags
- Create a release branch if your process uses one, or tag the main directly:
- git tag -a v1.3.0 -m "Release notes for v1.3.0"
- git push origin v1.3.0
Handling conflicts with rebase
- Rebase strategy helps keep a linear history but makes conflicts more frequent on long-lived branches.
- Best practices:
- Rebase often during active work to minimize big merges later.
- When conflicts arise, pause, resolve, then continue with git rebase continue.
- If the branch has diverged too much, consider a fresh rebase onto main: git fetch origin; git rebase onto origin/main origin/feature/user-auth-refresh
- If you’re uncomfortable with rewriting public history, reserve rebasing for private branches or coordinate with your team.
Integrating with CI/CD
- Ensure CI runs for every PR:
- Lint, unit tests, and integration tests as appropriate.
- Optional: run a separate pipeline for releases:
- Build artifacts
- Run end-to-end tests in a staging environment
- Deploy to a preview environment for reviewer validation
- Use status checks to block merges until CI passes.
Release tagging and changelogs
- Maintain a lightweight CHANGELOG.md:
- Keep a section per release with bullet points of user-visible changes.
- Tagging recommendations:
- Use semantic versioning if you can: MAJOR.MINOR.PATCH
- Example: v2.1.0 with a tag message listing highlights
- Automation ideas:
- Create a script to extract merged PR titles since last tag to populate changelog automatically.
Common pitfalls and how to dodge them
- Pitfall: Long-lived feature branches that diverge from main
- Solution: Rebase weekly or more often; communicate when you plan to rebase.
- Pitfall: Large, unfocused commits
- Solution: Break work into small commits; use interactive rebase to squash or reorder.
- Pitfall: Inconsistent PR reviews
- Solution: Enforce a small, focused scope per PR; require at least one reviewer.
- Pitfall: Skipping tests on feature branches
- Solution: Run the full test suite in CI; consider lightweight tests for speed during development.
Example run-through: a feature in three commits
- Feature: Add “remember me” to login
- Branch: feature/remember-me
- Commits: 1) feat(auth): add remember-me flag to login API and DB schema 2) test(auth): cover remember-me flow and token expiration 3) feat(ui): expose remember-me checkbox on login form and update UI tests
- Workflow:
- Create branch from main, begin work, and commit as shown.
- Rebase onto latest main before opening PR.
- Open PR, pass CI, get one reviewer, address comments with a fourth small commit, then merge with squash.
- Tag release if this feature is part of a new version.
Tooling you might add
- Git clients and helpers
- CLI: Git, Git LFS for large binaries
- Diff tools: Meld, Beyond Compare, or VS Code’s built-in diff
- Git aliases to speed up rebases and cleanups
- PR workflow
- GitHub/GitLab/Bitbucket PRs with required reviews and status checks
- Templates for PRs to ensure consistent context and acceptance criteria
- Quality gates
- Pre-commit hooks for lint and unit tests
- CI that runs on PRs and on push to main
- Release automation
- A small script that aggregates merged PR titles since the last tag into a changelog and creates a new tag
Sample commands you’ll use
- Start a feature branch from main:
- git checkout main
- git pull rebase
- git checkout -b feature/example
- Rebase onto latest main before PR:
- git fetch origin
- git rebase origin/main
- Resolve conflicts, then:
- git add .
- git rebase continue
- git push force-with-lease origin feature/example
- Merge option choices:
- Squash merge via UI, or
- git checkout main; git pull rebase; git merge no-ff origin/feature/example
- git push origin main
- Tagging a release:
- git tag -a v1.3.0 -m "Release v1.3.0: remember-me feature and UI refinements"
- git push origin v1.3.0
Illustrative quick-start checklist
- [ ] Branch per task established
- [ ] Feature branch rebased onto latest main before PR
- [ ] CI configured to run on PRs
- [ ] PR reviews completed and approved
- [ ] Changes merged with chosen strategy (squash or rebase)
- [ ] Release notes and tag created for the release
If you want, I can tailor this workflow to your stack (e.g., GitLab CI, GitHub Actions, or Bitbucket Pipelines), your programming language, and your team size. Would you like a version tailored to a Node.js project with GitHub Actions and a formal release cadence, or a Python project with GitLab CI and a weekly release train?
-
Rizwan Saleem | https://rizwansaleem.co
Top comments (0)