Git Best Practices for Development Teams
Git is an essential tool for collaborative software development. Establishing clear best practices helps maintain a clean, consistent, and efficient workflow for teams. This document outlines common practices for feature branching, integration, and pull requests.
1. Feature Branch Workflow
Always work on dedicated feature branches. This isolates development efforts, prevents conflicts in the main codebase, and simplifies code reviews.
Creating a Feature Branch
Before starting new work, always create a new branch from the latest main (or master, develop) branch.
# First, ensure your main branch is up-to-date
git checkout main
git pull origin main
# Then, create and switch to your new feature branch
git checkout -b feature/my-new-feature-nameNaming Conventions: Use clear, descriptive names. Common patterns include feature/<feature-name>, bugfix/<bug-description>, or chore/<task-description>.
2. Keeping Your Branch Up-to-Date (Fetch and Rebase)
Before pushing your feature branch for review, it’s crucial to integrate the latest changes from the main branch. Rebasing is generally preferred over merging for feature branches as it creates a cleaner, linear history.
Fetch Latest Changes from Origin
Regularly fetch the latest changes from the remote repository.
git fetch originRebase Your Feature Branch
Before pushing, rebase your feature branch onto the main branch. This rewrites your branch’s history, placing your commits after the latest commits from main.
# First, ensure you are on your feature branch
git checkout feature/my-new-feature-name
# Rebase onto the main branch
git rebase origin/mainIf conflicts occur during rebase, resolve them, git add the resolved files, and then continue the rebase with git rebase --continue. If you get into trouble, you can always abort with git rebase --abort.
Force Push After Rebase (Use with Caution!)
After a successful rebase, you’ve rewritten your branch’s history. If you’ve already pushed your branch to the remote, you’ll need to force push. Only force push branches that you are exclusively working on. Never force push to shared branches (like main).
git push --force-with-lease origin feature/my-new-feature-name--force-with-lease is safer than --force as it prevents overwriting work on the remote if others have pushed changes to the same branch in the meantime.
3. Pull Requests (PRs)
Once your feature is complete and rebased, create a Pull Request to merge your changes into the main branch.
Create a Pull Request
- Push your feature branch to the remote:
git push origin feature/my-new-feature-name - Go to your Git hosting platform (GitHub, GitLab, Bitbucket) and create a new Pull Request from your
feature/my-new-feature-namebranch tomain.
Best Practices for PRs:
- Descriptive Title and Description: Clearly explain what the PR does, why it was needed, and any relevant context.
- Link Issues/Tasks: Reference any related issue trackers (e.g., Jira tickets, GitHub issues).
- Code Review: Engage in constructive code reviews. Provide clear feedback and respond to comments promptly.
- Squash and Merge/Rebase Merge: After review and approval, the team should decide on a merge strategy (e.g., squash commits into a single commit for a cleaner
mainhistory, or rebase merge to preserve a linear history without an extra merge commit).
4. Example Workflow Summary
- Start New Work:
git checkout main git pull origin main git checkout -b feature/my-new-feature - Develop and Commit Locally:
# Make changes git add . git commit -m "feat: implement part of feature X" # Repeat as needed - Update and Prepare for PR:
git fetch origin git rebase origin/main # Resolve conflicts if any git push --force-with-lease origin feature/my-new-feature - Create Pull Request:
- Open PR from
feature/my-new-featuretomainon your Git platform.
- Open PR from
- Review, Approve, and Merge.
5. Git Tagging for Releases
Tags are used to mark specific points in a repository’s history as being important, typically for marking release versions (e.g., v1.0.0, v2.1.3).
There are two main types of tags in Git:
- Lightweight Tags: A simple pointer to a specific commit. It’s just a name for a commit, with no other information stored.
- Annotated Tags: A full object in the Git database. They are checksummed; contain the tagger’s name, email, and date; have a tagging message; and can be signed and verified with GNU Privacy Guard (GPG). It is recommended to use annotated tags for releases.
Creating an Annotated Tag
For releases, always use an annotated tag.
# Syntax: git tag -a <tagname> -m "<tag_message>"
git tag -a v1.0.0 -m "Initial release of version 1.0.0"Creating a Lightweight Tag
If you want a temporary tag or don’t need the extra information, you can use a lightweight tag.
# Syntax: git tag <tagname>
git tag v1.0.0-rc1Pushing Tags to Remote
By default, git push does not push tags. You need to explicitly push them.
# Push a single tag
git push origin v1.0.0
# Push all tags at once
git push origin --tagsListing Tags
You can list all existing tags.
git tagYou can also search for tags that match a particular pattern.
# List all tags starting with v1.
git tag -l "v1.*"Deleting Tags
If you need to delete a tag, you can do so locally and remotely.
# Delete a local tag
git tag -d v1.0.0-rc1
# Delete a remote tag
git push origin --delete v1.0.0-rc16. Example Workflow Summary
- Start New Work:
git checkout main git pull origin main git checkout -b feature/my-new-feature - Develop and Commit Locally:
# Make changes git add . git commit -m "feat: implement part of feature X" # Repeat as needed - Update and Prepare for PR:
git fetch origin git rebase origin/main # Resolve conflicts if any git push --force-with-lease origin feature/my-new-feature - Create Pull Request:
- Open PR from
feature/my-new-featuretomainon your Git platform.
- Open PR from
- Review, Approve, and Merge.
- Tag Release (on
mainafter merge):# Ensure you are on the main branch and have the latest changes git checkout main git pull origin main # Create and push the tag git tag -a v1.1.0 -m "Release version 1.1.0" git push origin v1.1.0
By following these practices, teams can maintain a robust, collaborative, and easy-to-understand Git history.