Git is designed to support a wide variety of development workflows. This guide covers recommended workflow patterns and strategies for using Git effectively in team environments.
Separate Changes into Logical Commits
As a general rule, you should try to split your changes into small logical steps, and commit each of them. This makes the review process much easier and the history much more useful for later inspection.
Make small, focused commits
Each commit should represent a single logical change that passes tests and works independently of later commits.
Split work from the beginning
It’s always easier to squash a few commits together than to split one big commit into several. Don’t be afraid of making too small or imperfect steps along the way.
Use interactive rebase to refine
You can always go back and edit commits with git rebase --interactive before you publish them:git rebase -i HEAD~3 # Edit last 3 commits
Use git stash push --keep-index to run the test suite independent of other uncommitted changes. This helps verify that each commit works in isolation.
Managing Branches
Branches are the foundation of effective Git workflows. Understanding how to manage them properly is crucial for team collaboration.
Topic Branches
Use topic branches for every feature, bugfix, or experiment:
Create a branch for each topic
Make a side branch for every topic (feature, bugfix, refactoring). Fork it off from the oldest integration branch that you will eventually want to merge it into.git switch -c feature/user-authentication main
Work independently
Develop your changes on the topic branch without affecting the main branches.# Make changes
git add .
git commit -m "Add user login functionality"
Merge when ready
To get the feature into an integration branch, simply merge it:git switch main
git merge feature/user-authentication
Branch Management Rules
Merge upwards: Always commit your fixes to the oldest supported branch that requires them, then periodically merge the integration branches upwards into each other.
# Fix in maintenance branch
git switch maint
git commit -m "Fix critical bug"
# Merge upwards
git switch main
git merge maint
Do not merge to downstream except with a good reason: upstream API changes affect your branch, your branch no longer merges to upstream cleanly, etc. Habitually merging an integration branch into your topics clutters history.
Avoid rebasing merged branches: Once a topic has been merged elsewhere, it should not be rebased. Rebasing published history can cause significant problems for collaborators.
Common Workflow Patterns
Feature Branch Workflow
The feature branch workflow is ideal for teams of any size:
Create a feature branch
git switch -c feature/new-feature main
Develop and commit changes
# Work on your feature
git add file1.js file2.js
git commit -m "Implement first part of feature"
# Continue working
git add file3.js
git commit -m "Complete feature implementation"
Keep branch updated (optional)
If main has moved forward and you need recent changes:git switch main
git pull
git switch feature/new-feature
git merge main # Or: git rebase main
Push and create pull request
git push -u origin feature/new-feature
# Then create a pull request through your Git hosting service
GitFlow Workflow
GitFlow uses multiple long-lived branches with specific roles:
- main: Production-ready code
- develop: Integration branch for features
- feature/*: New features (branch from develop)
- release/*: Release preparation (branch from develop)
- hotfix/*: Emergency fixes (branch from main)
# Start a new feature
git switch -c feature/user-profile develop
# Work on feature
git commit -am "Add profile page"
# Finish feature
git switch develop
git merge --no-ff feature/user-profile
git branch -d feature/user-profile
# Create a release
git switch -c release/1.2.0 develop
# ... make release-specific changes
git switch main
git merge --no-ff release/1.2.0
git tag -a v1.2.0
git switch develop
git merge --no-ff release/1.2.0
git branch -d release/1.2.0
Forking Workflow
Common in open-source projects where contributors don’t have direct push access:
Fork the repository
Create a personal copy of the repository through your Git hosting service.
Clone your fork
git clone https://github.com/your-username/project.git
cd project
git remote add upstream https://github.com/original/project.git
Create a feature branch
git switch -c feature/my-contribution
# Make changes and commit
Keep your fork synchronized
git fetch upstream
git switch main
git merge upstream/main
git push origin main
Submit a pull request
Push your feature branch to your fork and create a pull request to the upstream repository.git push origin feature/my-contribution
Integration Branches
Larger projects often use multiple integration branches for staged feature graduation:
- maint: Maintenance releases for the last stable version
- main/master: The next release
- next: Testing branch for topics being tested for stability
- seen: Integration branch for things not quite ready yet
Each branch is usually a direct descendant of the one above it. Features enter at an unstable branch and “graduate” to main once considered stable.
Throw-away Integration
To test the interaction of several topics without committing to the merge:
git switch -c test-integration main
git merge topic1
git merge topic2
git merge topic3
# Test the combined changes
# If satisfied, merge topics individually into main
git switch main
git merge topic1
git merge topic2
Never base any work on throw-away integration branches! These branches should be deleted after testing.
Distributed Workflows
Merge Workflow
The merge workflow uses branches to share complete history between repositories:
# Publishing changes
git push origin feature-branch
# Staying up to date
git fetch origin
git merge origin/main
# Pulling others' changes (as maintainer)
git pull https://github.com/contributor/repo feature-branch
Patch Workflow
The patch workflow uses email to share changes:
Create patches from commits
git format-patch -M upstream..topic
Send patches via email
git send-email --to=maintainer@project.org *.patch
Apply received patches (as maintainer)
git am < 0001-patch-file.patch
Use git am -3 for three-way merge if conflicts occur.Update patches when requested
git pull --rebase upstream main
git format-patch -M upstream..topic
Release Management
Creating a Release
Verify main is a superset of maint
git log main..maint # Should show no commits
Tag the release
git tag -s -m "Version 1.0.0" v1.0.0 main
Maintenance Branch Management
After a feature release, update maintenance branches:
# Create maintenance branch for previous release
git branch maint-1.0 maint
# Fast-forward maint to new release
git switch maint
git merge --ff-only main
Consider using git request-pull to create formatted pull request summaries:git request-pull upstream/main origin feature-branch
Choosing the Right Workflow
Consider these factors when selecting a workflow:
- Team size: Smaller teams can use simpler workflows
- Release cadence: Frequent releases benefit from streamlined processes
- Collaboration model: Centralized vs. distributed
- Project maturity: Established projects may need more structure
- Deployment strategy: Continuous deployment vs. scheduled releases
Don’t blindly follow any workflow. Value good reasons for your actions higher than rigid rules. Adapt workflows to your team’s needs.