Preserving co-authors when squashing Jump to heading
A commit has exactly one author field. When a branch with commits from three people is squashed into one commit, two of them vanish from the author field — and from git shortlog, contribution graphs, and the “who wrote this” answer that git blame gives. For pairing sessions, handed-over pull requests and reviewers who pushed fixes, that is a real loss: credit, but also the ability to ask the right person about the code later. The Co-authored-by trailer solves it. Forges display co-authors on the commit, count the contribution, and tools can read the trailer. The difficulty is remembering to add it at squash time, which is why it should be automatic. This page shows how, within squash and fixup strategies.
When to use this approach Jump to heading
- Pull requests are squash-merged, and more than one person sometimes commits to a branch.
- Your team pairs or mobs, so commits are written together even when one person types.
- Contribution metrics or open-source credit matter to the people involved.
- You squash locally before pushing, or squash on the forge with the merge button — both are covered.
Step 1 — Understand the trailer format Jump to heading
A trailer is a Key: value line in the last paragraph of a commit message. The co-author trailer uses the same name-and-email format as the author field. The email must match an address associated with the person’s forge account for the forge to link it.
Add per-account export scheduling
Co-authored-by: Priya Raman
Co-authored-by: Tom Okafor # Verification: Git parses it as a trailer
git log -1 --format='%(trailers:key=Co-authored-by)' Step 2 — Collect co-authors from the branch automatically Jump to heading
Every author and committer on the branch, other than the person squashing, is a candidate co-author. Collect them from the commits about to be squashed, deduplicate by email, and drop bots.
#!/bin/sh
# coauthors.sh <base> [<head>] — print Co-authored-by trailers for a range
set -eu
base=$1 head=${2:-HEAD}
me=$(git config user.email)
git log --format='%an <%ae>%n%cn <%ce>' "$base..$head" |
grep -v -e "<$me>" -e '[email protected]' -e '\[bot\]' |
sort -u | sed 's/^/Co-authored-by: /' Including committers as well as authors catches people who applied, rebased or amended others’ work, which matters in workflows where a maintainer finishes a contributor’s branch.
# Verification: list who would be credited for this branch
./coauthors.sh main feature/export-scheduling Step 3 — Add them when squashing locally Jump to heading
When you squash locally — with a soft reset, merge --squash or an interactive rebase — append the trailers to the final message.
base=$(git merge-base main HEAD)
trailers=$(./coauthors.sh "$base")
git reset --soft "$base"
git commit -m "feat(export): schedule CSV exports per account" -m "$trailers" Or with --trailer, which formats and deduplicates for you:
./coauthors.sh "$base" | while IFS= read -r line; do
git commit --amend --no-edit --trailer "$line"
done Step 4 — Make the forge’s squash button include them Jump to heading
Forges add co-author trailers automatically for commits authored by other people on the branch when you squash through the interface, but only if the commit authors are recognised accounts and the default message includes the commit list or co-author section. Check what your forge produces on a test pull request before relying on it.
# After a squash merge, verify the trailers landed on main
git fetch origin
git log -1 --format='%an%n%(trailers:key=Co-authored-by)' origin/main If the forge drops them — for instance when the default message is set to the pull request description only — add them to the description before merging, or use a merge-time script like the one in writing a good squash commit message.
Step 5 — Credit pairing partners at commit time Jump to heading
When two people pair at one keyboard, the commits on the branch have one author before any squash happens. Add the partner as a co-author on each commit, so the squash script has something to collect. A commit template makes that low effort.
# .gitmessage — prefilled when the pair starts, removed when they stop
# Co-authored-by: Priya Raman <[email protected]>
git config commit.template .gitmessage To include existing trailers in the collection, extend the script: git log --format='%(trailers:key=Co-authored-by,valueonly)' "$base..$head" prints them, ready to merge into the list.
Validation checklist Jump to heading
Frequently Asked Questions Jump to heading
Does the email have to match the person’s forge account? Jump to heading
For the forge to link the trailer to an account and show their avatar, yes — it must be an email on their account, including the forge’s private noreply address if they use one. The trailer is still recorded in history either way.
Is a co-author the same as a reviewer? Jump to heading
No. Use co-author for people who wrote code in the change. Reviewers can be recorded with a Reviewed-by trailer if your team values that, but forges do not treat it as authorship.
Can I add co-authors to a commit that is already on main? Jump to heading
Not without rewriting main, which is not worth it. Record the credit in the pull request instead, and fix the process so the next squash includes them.
Related Jump to heading
- Squash & Fixup Strategies — the parent topic.
- Adding Trailers Automatically with a commit-msg Hook — automating trailers on every commit.
- Squashing Without Interactive Rebase — the local squash techniques used in step 3.
- Measuring Review Latency from Git History — another use of commit metadata that squashing affects.