Skip to content

credit: publish only the names you chose

The problem

A commit's author, committer and trailers go public the moment it is pushed, and mirrors and forks keep them. A repo that started private carries a work email on every commit; a tool added a Co-authored-by: line you did not want.

Checking the whole repo blocks every push forever once old history is public under another name. Checking @{u}..HEAD misses new branches and first pushes, which publish everything.

The method

Git's pre-push hook gets one line per ref: local ref, local commit, remote ref, remote commit. What this push publishes is exactly:

git log "$local_commit" --not --remotes="$remote"

Everything reachable from what you push that the remote does not have. A first push checks all history; a branch made from pushed work checks nothing.

Each commit is checked on its author, committer, and Co-authored-by: and Signed-off-by: trailers; a pushed annotated tag on its tagger.

When it blocks, it offers a fix only when the fix is safe. The boundary of the unpushed set says where a rewrite may start:

git rev-list --boundary "$local_commit" --not --remotes="$remote" | sed -n 's/^-//p'

One boundary commit: rebase from it, and only unpushed commits change. None: a first push, rewrite from --root. Two or more (merged with pushed work): a rebase would rewrite public commits, so it says to do it by hand.

Sample

git config --global --add credit.allow 'A N Author'          # shell globs
git config --global --add credit.host '*github.com[:/]*'     # optional
git config --global credit.name 'A N Author'                 # identity for the
git config --global credit.email [email protected]          # rewrite line
printf '#!/bin/sh\nexec /path/to/credit "$@"\n' > .git/hooks/pre-push
chmod +x .git/hooks/pre-push   # or drop it in a shared pre-push.d/ (githooks)
credit                      # what would pushing this branch publish?
CREDIT_SKIP=1 git push      # once, anyway

Limits

  • It compares with your remote-tracking refs, which can only be behind the server: it may check more, never less. Fetch first if it flags others' work.
  • Raw names are checked, not .mailmap, because raw names are published.
  • The trailer rewrite drops all Co-authored-by: and Signed-off-by: lines.
  • Names inside messages or files are a different job (a pre-commit scanner).

Code

methods/credit/ in the methods repository: the script, a README and a 27-check test that pushes to real bare remotes through the hook, runs the printed rewrite line, and proves already-pushed commits keep their ids.