As a developer, keeping track of code changes and synchronizing them across teams is critical when collaborating on large projects. Git enables developers to make local commits before pushing them to a remote shared repository like GitHub. However, at times you may want to review commits made locally before pushing them. This allows you to ensure your changes are correct, fix any issues, or even squash multiple commits into one cleaner commit.
In this comprehensive guide, we will cover:
- Why Review Local Commits Before Pushing?
- Listing Unpushed Commits on Current Branch
- Viewing Unpushed Commits on All Branches
- Using Flags for Readability
- Automate Commit Policy Enforcement with Git Hooks
- Coordinating Unpushed Commits on Teams
- Pushing Commits After Review
- Best Practices for Team Collaboration
Understanding these concepts will help you efficiently coordinate code changes when working on team projects with Git.
Why Review Local Commits Before Pushing?
Here are some key reasons why reviewing local unpushed Git commits is beneficial:
1. Catch mistakes – By checking commits locally first, you can spot errors, debug issues, and fix them before sharing code with others. Finding bugs after pushing can lead to problems for teammates.
2. Improve commit quality – Reviewing allows you to rewrite commit messages for clarity, split changes into separate commits, or squash together related commits. This keeps project history clean.
3. Avoid merge conflicts -Checking other teammate‘s recent commits and pulls lets you handle rebasing and merge conflicts locally before pushing. This avoids creating issues for others.
4. Test properly – Verifying commits yourself first by testing locally ensures changes don‘t break the codebase for everyone else.
5. Limit broken builds – Pushing code that doesn‘t build or pass tests can prevent teammates from integrating properly. Reviewing first prevents this.
Catching issues early by reviewing local unpushed commits makes life easier for your whole team!
Listing Unpushed Commits on Current Branch
When working on a feature branch, you want to see which commits have not yet been pushed to the remote origin
to share with others. Let‘s go over how to do this.
Using git log origin/<branch>..HEAD
The easiest way is by using git log
to show a list of commits that exist on HEAD (your local branch) but not on the origin/<branch>
:
git log origin/main..HEAD
This will display details for all commits you have locally since you last pulled from or pushed to origin.
For example:
commit a13c123e3c204e17aeb96c584f3eac8f14bb9032
Author: John <john@example.com>
Date: Tue Feb 21 12:32:11 2023 -0500
Implement login form handler
* Add login POST endpoint
* Validate input data
* Return auth token on success
commit 85935bc63f912022812e0c39a3828f87ca70e80e
Author: Mary <mary@example.com>
Date: Mon Feb 20 10:53:41 2023 -0500
Create reusable Button component
This shows two unpushed commits by different authors.
You can also substitute main
for any other branch names you might have.
Using git log @{u}..
You can also use the @{u}
annotation instead of referencing a remote tracking branch:
git log @{u}..
This generates the same output, showing all commits that only exist locally and not on upstream origin
.
Viewing Unpushed Commits on All Branches
The above commands show unpushed commits for the currently checked out branch. What about seeing unpushed commits across all Git branches simultaneously?
Using --branches
and --not
Flags
To view commits on all branches not pushed remotely, there is a flag combination you can pass to git log
:
git log --branches --not --remotes
This will display commits on current branch, plus any other local branches you have commits on not up on origin:
commit a13c123 main
...
Implement login form handler
commit 4e17483 feature/profile
...
Add user profiles section
Now you can easily check if you have unpushed work on multiple branches before pushing them up.
Using the @{u}
Annotation
You can also use the @{u}
shortcut we mentioned earlier combined with the --branches
flag:
git log --branches @{u}..
This accomplishes the same task of showing commits on all local branches not pushed remotely.
Using Flags for Readability
The default git log
output shows lots of commit details. To simplify this view, there are some flags you can use.
One Line Per Commit with --oneline
This condenses commit info to the hash and message on one line:
git log --oneline @{u}
a13c123 Implement login form handler
85935bc Create reusable Button component
Much easier to skim through what is unpushed.
Commit Count with --count
You can also get just a total number of unpushed commits using --count
:
git log --count @{u}
2
This gives you a quick idea of how many commits would be pushed up if you chose to do so.
Automate Commit Policy Enforcement with Git Hooks
Manually reviewing all local commits before pushing can be tedious. Luckily, Git offers hooks – scripts triggering custom actions during the commit process.
Hooks like pre-commit
and commit-msg
execute checks before a commit is created. This enables automatically blocking bad commits per your team‘s policy.
For example, invoking tests or linting before commit:
// .git/hooks/pre-commit
console.log("Running tests...")
// Run tests & linting
try {
await runTests()
runLinter()
console.log("Checks passed, ready to commit!")
} catch {
console.log("Commit blocked due to test failure(s)")
process.exit(1)
}
Now only passing commits can be created!
Common use cases for commit hooks:
- Block commits without issue ticket references
- Enforce conventions via linting (formatting, commit message structure)
- Prevent failing test cases from being committed
- Reject attempted pushes with policy violations
Automating policy enforcement leads to higher quality, compliant commit histories.
Coordinating Unpushed Commits on Teams
When collaborating across developer teams, there needs to be coordination around everyone‘s local in-progress work.
Limit WIP Commits
Avoid having too many locally commits in progress (WIP) before pushing. Try to review and push changes frequently in small increments. This helps minimize merge issues that can occur the longer features diverge.
For example, push completed functionality instead of waiting for entire components to be built end-to-end.
Communicate Intent
If you have a long-running feature branch, communicate this to teammates along with rough expectations of the changes so no one else conflicts. But limit relying on large feature branches.
Separate Experimental Work
Use separate feature
branches or user/
namespaced branches for major changes that take time rather than piling up WIP commits on main
. This avoids polluting central branches.
Linearize Shared History
Rebase your local work onto the latest from origin/main
before pushing to keep project commit history linear versus tangled merges.
For example:
git fetch origin
git rebase origin/main
git push
vs merging which leads to divergent branch graphs.
Flag Work in Progress
Prefix incomplete work or experimental commits with wip
or [WIP]
to signify the commit should not be depended on. For example:
[WIP] Start payment integration
Partial implementation, do not merge!
This signals the changes are not ready for use yet.
Pushing Commits After Review
Once you have reviewed your local unpushed commits and are satisfied with them, you can go ahead and push to the shared remote repository:
git push origin main
Or specify another branch name instead of main
.
This will push all the commits you have locally that don‘t exist on origin yet.
An alternative is to rebase your work onto the latest from origin before pushing:
# Fetch latest changes from origin
git fetch origin
# Rebase current branch onto origin version
git rebase origin/main
# Push rebased branch
git push origin main
Rebasing replays your commits after the newest ones from origin/main
. This keeps project history linear for readability.
Best Practices for Team Collaboration
Here are some best practices around unpushed local commits when collaborating across developer teams:
Review regularly – Don‘t amass too many unpushed commits. Review and push smaller changesets incrementally.
Communicate intent – If holding off pushing for a while, let teammates know what types of changes you‘re working on to avoid conflicts.
Separate experimental work – Use feature branches or other branching strategies for major changes that take time rather than piling up WIP commits on main branch.
Automate policies – Implement Git hooks to automatically enforce commit message formats, tests, linting standards, etc.
Craft clear commit messages– Write clear, atomic commit messages explaining why a change was made to keep context around changes as you review locally and push up.
Rebase over merge – Rebase branches onto the latest origin/main
instead of merging to keep a linear project history.
According to GitLab‘s 2021 Global Developer Report which surveyed over 6,000 developers, the top benefits reported from practicing Git rebase workflow were:
- Cleaner commit history: 62%
- Easier to revert changes: 55%
- Better teamwork: 51%
Following these practices helps reduce frictions working with Git when collaborating with multiple developers!
Summary
Here is a quick overview of what we covered on reviewing local unpushed Git commits:
- Use
git log origin/<branch>..HEAD
orgit log @{u}..
to view current branch commits not on remote origin - Pass
--branches
and--not
flags to see unpushed commits from all local branches - Simplify commit list output with
--oneline
and--count
- Implement Git hooks to enforce policies automatically on commit
- Rebase over merge when pushing to keep history linearized
- Review commits locally first before pushing to catch issues early
Properly coordinating around unpushed local work minimizes integration headaches at scale when developers collaborate on shared repositories.
Implementing workflows promoting visibility into each other‘s changes coupled with automated policy enforcement enables high-performance teams to build faster and ship more reliably!
These Git commit best practices empower developers to increase output on shared codebases while reducing disruptions from avoidable mistakes or downstream breaking changes. Master these workflows and take your team‘s DevOps practices to the next level!