Skip to content

Latest commit

 

History

5 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

gh-email-get

A GitHub CLI extension that surfaces the public email addresses behind GitHub commits. It runs in one of two modes depending on the argument shape:

  • User mode — given a username or profile URL, list every email the user has authored commits with across their public repositories, with the earliest and latest commit dates per email (YYYYMMDD, UTC).
  • Repo mode — given an owner/repo (or repo URL), list every contributor to that repository with the distinct emails they have authored commits with.

Output is JSON on stdout, so it pipes cleanly into jq and friends.

Installation

gh extension install th2ch-g/gh-email-get

To upgrade later:

gh extension upgrade email-get

Usage

gh email-get [flags] <username-or-url|owner/repo>

Accepted argument shapes:

Shape Mode
th2ch-g / github.com/th2ch-g / https://github.com/th2ch-g User mode
th2ch-g/dotfiles / github.com/th2ch-g/dotfiles / https://github.com/th2ch-g/dotfiles(.git) Repo mode

Trailing slashes and an optional .git suffix on repo URLs are stripped.

User-mode example

$ gh email-get th2ch-g
[
  {
    "email": "76892059+th2ch-g@users.noreply.github.com",
    "start_date": "20221005",
    "last_date":  "20260424"
  }
]

Pipe into jq to filter — e.g. drop noreply addresses:

gh email-get th2ch-g --quiet | jq '[.[] | select(.email | contains("noreply") | not)]'

Repo-mode example

$ gh email-get th2ch-g/dotfiles
[
  {
    "user": "th2ch-g",
    "emails": [
      "76892059+th2ch-g@users.noreply.github.com"
    ]
  }
]

Drop bots / noreply contributors:

gh email-get owner/repo --quiet \
  | jq '[.[] | select(.user | endswith("[bot]") | not)]'

Flags

Flag Default Mode Description
--quiet false both Suppress progress messages on stderr.
--include-fork true user only Include forked repositories owned by the user. Pass --include-fork=false to skip them.
--contributions false user only Also scan external repositories the user has authored commits in, discovered via the GitHub search/commits API. The search endpoint has a tighter rate limit (30 req/min when authenticated) and returns at most 1000 results.

--include-fork and --contributions only affect user mode; in repo mode the single specified repository is always scanned exactly once.

--help prints the usage and exits.

How it works

The argument is parsed into a Target{Kind, User, Repo} value. Two-segment inputs (owner/repo) become repo-mode targets; one-segment inputs become user-mode targets. Anything with three or more path segments is rejected.

User mode

  1. GET /users/{user}/repos?type=owner lists the user's owned public repos (paginated via the Link header). Forks are included unless --include-fork=false.
  2. With --contributions, GET /search/commits?q=author:{user} discovers external repos the user has committed to. Results are de-duplicated against the owned set.
  3. For each repo, GET /repos/{owner}/{repo}/commits?author={user} paginates through every commit authored by the user. Empty repositories return HTTP 409 from the API and are silently treated as having zero commits.
  4. Each commit's commit.author.email and commit.author.date is fed into an aggregator that keeps the earliest and latest date per email.
  5. The result is sorted by start_date ascending (email as tie-breaker) and printed as a pretty-printed JSON array.

Repo mode

  1. GET /repos/{owner}/{repo}/commits paginates through every commit in the repository (no ?author= filter).
  2. Each commit is grouped by its author — preferring the GitHub login (author.login, top-level on the payload) and falling back to the Git author name (commit.author.name) when the email isn't tied to a GitHub account.
  3. Per user, distinct emails are collected (case-sensitive de-duplication).
  4. Both users and the emails within each user are sorted alphabetically.

In both modes only commit.author.email is collected; commit.committer.email is intentionally ignored because rebase/squash flows on GitHub leak GitHub's own committer identity.

Authentication and rate limits

The extension uses the credentials gh is already authenticated with via go-gh — there is no separate token to configure. Make sure gh auth status succeeds before running.

The authenticated REST limit is 5000 req/h, enough for users with hundreds of repos and thousands of commits. The search/commits endpoint used by --contributions is limited to 30 req/min, so very active users may hit that ceiling.

Output contract

  • stdout: machine-readable pretty-printed JSON only. Suitable for piping into jq or other tools.
  • stderr: human-readable progress messages, warnings, and errors.

A commit with an empty author email or zero-value date is skipped with a warning on stderr; it does not cause the run to fail.

Development

Build and test from a checkout:

make build       # produces ./gh-email-get
make test        # go test ./...
make install     # (re)install as a gh extension from this checkout
make help        # list all targets

The CI workflow at .github/workflows/ci.yml runs go vet, go test, and go build on every push to main and every pull request.

Releasing

Release builds are produced by .github/workflows/release.yml using the cli/gh-extension-precompile action. Tag the commit and push the tag — the workflow builds per-platform binaries named gh-email-get_<os>_<arch> and attaches them to a GitHub Release. gh extension install automatically picks the matching asset.

git tag v0.1.0
git push origin v0.1.0

License

See repository for license details.

About

gh extension that lists every public email address a GitHub user has authored commits with, plus first/last seen dates, as JSON.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages