From Contributor Graph to Ranked Hiring Shortlist
You can take one technical role, mine the right repositories, and finish with a deduplicated, bot-free, evidence-ranked shortlist inside a two-hour time box.
You have one technical role to fill and a hunch that the right people are already contributing to two or three open-source projects in your stack. This guide is for in-house sourcers, recruiters, and founders doing their own hiring who want to turn a project's contributor list into a deduplicated, ranked, reachable shortlist - with bots, drive-by contributors, and off-target committers already stripped out. It is a fixed-time-box procedure you run start to finish, not a framework you improvise around.
The promise is specific: a two-hour sprint that ends in a tiered shortlist with a one-line evidence note per name, instead of the hour-per-person triage that makes repo sourcing feel like a punishment.
Why repo mining beats keyword search for one role
Repo mining wins when the pool is thin or when quality, not quantity, is the bottleneck. A contributor graph is a list of people who have already proven they can work with your technology, which is a stronger starting signal than a profile that merely mentions it.
Two numbers from Refolk's index set the strategy. When a skill is scarce, the graph stops being a sample and becomes the pool itself.
| Market | People | Share of US pool |
|---|---|---|
| United States | 3,500 | 1.00x |
| Germany | 966 | 0.28x |
| US-to-Germany multiple | 3.62x | - |
Counts from Refolk's index; the multiple is 3,500 divided by 966.
Germany has 966 Rust engineers against 3,500 in the US, a market 3.62x thinner. In a pool that small, the GitHub Search API's 1,000-result cap rarely binds, and the contributors to the two or three canonical Rust projects are close to the whole addressable market. Mining the graph directly is not a shortcut here; it is the correct method.
The opposite case is abundance. Go's US pool is 4.62x the size of Rust's.
| Skill | People | Multiple vs Rust |
|---|---|---|
| Rust | 3,500 | 1.00x |
| Go | 16,168 | 4.62x |
Counts from Refolk's index; the multiple is 16,168 divided by 3,500.
For an abundant skill like Go, finding people is trivial and filtering is everything. That is exactly where the bot-stripping and depth-ranking steps below pay for themselves, because the raw contributor list is enormous and mostly noise.
What the contributor graph actually tells you, and what it hides
The graph is a ranked list of who committed to a repo, and it is more honest about volume than about quality or completeness. Treat it as a lead list, not a verdict.
Three structural limits shape everything downstream. First, the GitHub Search API returns a maximum of 1,000 results per query, at 100 items per page across ten pages, and gives no error when you hit the cap. Second, the native contributor graph claims to exclude bot accounts but only strips logins recognised as GitHub Apps, meaning those with a [bot] suffix. Third, 82% of GitHub contributions happen in private repositories, so the public graph under-counts senior engineers who ship privately.
That last figure changes how you read a quiet profile. If someone's public window is thin, that is not proof they are inactive; it is proof they may work somewhere that keeps its code private. Rank on the depth you can see and never disqualify on the absence of what you cannot.
Pick the right projects before you pull a single name
Choose repos that match your exact stack, and prefer strong mid-size projects over the largest ones. The mega-repos concentrate stars on a handful of maintainers who are already over-contacted and least likely to reply.
If you find a popular project matching your stack, its contributor list is a goldmine, because those developers have proven they can work with your technology. For a Kubernetes role you look at contributors to the Kubernetes repo. But the biggest project in a language is rarely the best hunting ground for outreach, because the visible top contributors there get bombarded. Aim for the second tier: projects with real adoption and 20-plus stars on original work, where a strong contributor is not yet drowning in recruiter messages.
The judgement call is a two-variable one. Match against your stack on one axis, and contact saturation on the other.
Which projects to mine
Reading order runs top-left, top-right, bottom-left, bottom-right. The bottom-left quadrant - high stack fit, low saturation - is where a Tuesday sprint should spend most of its time.
The two-hour procedure, stage by stage
Run these eight stages in order. Each has an owner, a time budget, and a definition of done, so you can stop when a stage is finished rather than polishing forever. The whole sprint fits in roughly two hours.
Role brief to ranked shortlist
- Write the brief into query termsConvert the role into language, topic, star, and pushed-date qualifiers. Done: 3 to 5 target repos and a query string like language:rust stars:>20 pushed:>2025-01-01. (15 min)
- Pick the right projects, not the biggestPrefer repos matching your exact stack; avoid mega-repos where stars concentrate over-contacted people. Done: a repo list with owner, language, and star count. (15 min)
- Pull the contributor setClone and run git shortlog -sn -e --no-merges per repo, or page the API at 100 per page within the 1,000 cap. Done: one CSV of name, email, and commit count per repo. (20 min)
- Deduplicate by identityMerge rows sharing an email or a noreply ID and collapse alias names. Done: one row per person. (15 min)
- Strip bots and automationRemove every [bot]-suffixed login, then pattern-match snyk-bot, dependabot, pre-commit, and release accounts by name. Done: zero machine accounts remain. (10 min)
- Separate core from drive-byRe-run the shortlog with --since="6 months ago" and drop one-commit contributors unless the commit is substantial. Done: a ranked list tagged core, recent, or drive-by. (15 min)
- Resolve to reachable peopleMap each commit email to a profile; where masked, use the profile link, org, and location. Done: each survivor has a live GitHub profile URL and at least one reach path. (20 min)
- Score and rank into tiersApply the rubric of windowed rank, original-vs-fork ratio, merged PRs, and 20-plus stars on original repos. Done: a shortlist sorted into tiers with a one-line evidence note each. (20 min)
The commands that carry the middle stages
The canonical per-author count that excludes merge commits is one line. Clone the repo, then run it.
# Full history, one row per author, with email, merges excluded git shortlog -sn -e --no-merges # Group by email to collapse alias names into one person git shortlog -e -s # Re-run over the last six months to separate core from drive-by git shortlog -sn --no-merges --since="6 months ago"
Run the first command per repo to build your CSV; run the second to tag core versus drive-by. --max-parents=1 is identical to --no-merges.
Prefer cloning over the API when you can. The full local history lets you exclude merges, group by email, and inspect merge strategy - none of which the API contributor graph gives you cleanly, and it arrives bot-polluted. Use the API only when cloning is impractical, and remember the 1,000-result cap and the separate 10-requests-per-minute limit on code search.
When the manual pull is the wrong use of two hours - because the skill is abundant and filtering, not finding, is the whole job - Refolk runs the same intent in plain English and hands back the filtered set. The stages below still matter; you are just skipping the parts a machine does faster.
Strip the bots, or your ranking is fiction
Filtering only [bot] logins is the single most common way a "ranked" list ends up polluted. The native graph strips GitHub Apps and nothing else, so every unsuffixed machine account survives - and a release bot can sit at the very top of your commit count.
Work in two passes. First remove every login ending in [bot], such as dependabot[bot] and github-actions[bot]. Then sort by commit count and inspect your top few names by hand, because the dangerous ones - snyk-bot, pre-commit, all-contributors, and various release accounts - carry no suffix and hide in plain sight near the top of the list.
From raw contributors to a ranked shortlist
- 1,000Raw contributor list
Search API ceiling per query
- 100After dedupe and bot strip
One row per real person
- 40Core plus recent (6-month window)
Drive-by contributors dropped
- 15Reachable and on-target
Ranked into tiers for outreach
The volumes in that funnel are illustrative of the shape, not fixed counts; the ceiling of 1,000 is the real cap. What matters is that per-person time only gets spent at the narrow end, after three cheap filters have done their work.
Rank on depth, not on green squares
Rank contributors by evidence of real work, not by the density of their contribution graph. Green squares are easy to manufacture and popularity is a poor predictor of reply rate, so both mislead if you rank on them.
Contribution graphs can be backdated or auto-generated, and a dense graph with no original repos behind it is theater. Read the commits rather than counting them: check whether a person writes original code or just forks, and look for meaningful pull requests, issues, and community engagement. Depth matters more than daily consistency.
Use a four-signal rubric. For each signal, know what it proves and what it looks like when it lies.
| Signal | What it proves | When it lies |
|---|---|---|
| 6-month windowed commit rank | Current, sustained activity | Under-counts private-repo work (82% is private) |
| Original-vs-fork ratio | They write code, not just clone it | Backdated or auto-generated green squares |
| Merged PR count | Their work was accepted by maintainers | Squash merges credit the merger, not the author |
| 20+ stars on original repos | Independent, recognised output | Star-buying and over-contacted popular accounts |
The bus factor is a useful cross-check. If one person accounts for 60% or more of a repo's commits, that concentration flags them as the load-bearing maintainer - valuable to know, and also a person who is probably stretched. And contributors with 3 or more weekly commits have been linked to 68% higher retention when hired, so sustained depth in your window is worth weighting.
The ranking you trust most is the one squash merges break first, so confirm the merge strategy before you believe the top of the list.
How this goes wrong
Most of the damage happens silently: the list looks finished and clean while measuring the wrong thing. Here are the seven failure modes to check for, each with a concrete test.
Silent 1,000-result truncation. A full last page looks complete but can hide more results, and GitHub raises no error. Check: if total_count exceeds 1,000, split the query into progressive date ranges and merge the pages.
Bot leakage. Filtering only [bot] logins leaves snyk-bot, pre-commit, and release accounts, none of which carry the suffix. The false positive is a "top contributor" that is a release bot. Check: sort by commit count and inspect the number-one entry by name.
Squash-merge distortion. When a team squashes every PR into one commit, the top of git shortlog is the merge account, not the strongest author. The output can show a merge identity as the most-committed contributor, which is not what you want. Check: confirm the repo's merge strategy and group by author, not committer.
Green-square theater. Contribution graphs can be backdated or auto-generated, so a dense graph is not proof of skill. The false positive is a busy-looking profile with no original repos. Check: the original-vs-fork ratio and merged-PR count.
Masked emails. A privacy-masked address of the form ID+username@users.noreply.github.com blocks direct email but not the person. The false negative is discarding someone as unreachable when the profile links out. Check: open the profile before dropping anyone.
Over-contacted stars. High-follower contributors rarely reply because they are already saturated with outreach. The false positive is ranking the most famous name first. Check: rank by depth, not follower count.
Drive-by inflation. A one-typo-fix contributor ranks as a "contributor" in the all-time list. Check: the 6-month windowed re-run drops them automatically.
Resolving contributors to reachable people
A shortlist is only useful if you can contact the people on it, so resolve every survivor to a live profile and at least one reach path before you rank. Reachability, not ranking, is where most repo-sourcing sprints quietly fail.
By default a commit holds the contributor's email as well as their username, and grouping by email with git shortlog -e -s collapses aliases into one person. But many emails are privacy-masked. GitHub only associates a commit with a profile when the commit email matches a verified account email, so a masked noreply address will not link cleanly. That does not make the person unreachable. Open the profile: it often lists an org, a location, a personal site, or a linked account, any of which is a reach path.
Seniority is the other reason to finish the resolution and scoring rather than stopping at a raw list.
| Band | People | Share of all US Rust |
|---|---|---|
| All Rust | 3,500 | 100% |
| Senior-tagged | 1,234 | 35.3% |
Counts from Refolk's index; the share is 1,234 divided by 3,500.
Only 35.3% of US Rust engineers carry a senior tag, so a specialist pool is still mostly not senior. A shortlist that skips the windowed depth score will over-represent junior drive-by contributors and bury the seniors you actually want, because juniors often out-commit seniors on public repos while seniors ship privately.
Verify before you call it done
Before you hand the shortlist to outreach, run this checklist. It maps directly onto the failure modes above, so a clean pass means the list is measuring what you think it measures.
Shortlist sign-off
- Every [bot]-suffixed login is removed and the top committers were inspected by name for unsuffixed bots
- The list is deduplicated so each person appears once, with aliases merged by email
- A six-month windowed shortlog was run and one-commit drive-by contributors are dropped or tagged
- The merge strategy of each repo was confirmed, and ranking is by author rather than merge account
- Any query that returned a full last page was checked against total_count and split by date if over 1,000
- Every survivor has a live GitHub profile URL and at least one reach path, including those with masked emails
- Ranking is by depth signals, not follower count, and each name carries a one-line evidence note
Keeping the method current
Two things in this procedure will drift, so build a habit of re-checking them rather than trusting a value you cached. The API limits and the bot landscape are both moving targets.
Rate limits and caps change by era and by tier. Enterprise docs currently list 30 requests per minute authenticated and 10 unauthenticated for the Search API, code search sits at a separate 10 per minute, and older mirrors quote different numbers. Before a large pull, re-read the current changelog for the endpoint you are using rather than assuming last quarter's figure. The 1,000-result-per-query cap has been stable, but the throughput around it has not.
The bot list also grows. New automation accounts appear constantly, and few of them adopt the [bot] suffix that the native graph filters. Keep a running pattern list of the machine accounts you have caught - snyk-bot, pre-commit, all-contributors, common release bots - and add to it every time your top-committer inspection turns up a new one. That habit is the difference between a ranking that measures engineers and one that measures automation.
Finally, re-run the whole sprint against a repo you already know well once in a while. If the shortlist it produces matches your intuition about who the real contributors are, your filters are calibrated. If a release bot or a one-commit typo fixer survives to a top tier, one of the cheap filters has slipped, and you will find it faster on a repo where you already know the right answer.
Questions practitioners ask
How do I source developers from a GitHub repo without spending an hour per candidate?
Work at the set level, not the person level. Pull the whole contributor list once with git shortlog, deduplicate by email, strip bots, and drop drive-by contributors before you ever open a profile. You only spend per-person time on the survivors that have already passed windowed rank and depth checks. That is how a two-hour sprint replaces the 13 hours a role can otherwise consume.
Why does the GitHub contributor graph still show bots when it says it excludes them?
The graph only excludes accounts recognised as GitHub Apps, meaning logins with a [bot] suffix like dependabot[bot]. Machine accounts without that suffix, such as snyk-bot, pre-commit, and various release bots, are not caught. There is no built-in way to exclude a specific user, so you must filter [bot] logins and then pattern-match the rest by name, inspecting your top committers first.
How many results can I get out of the GitHub Search API?
The Search API returns a maximum of 1,000 results per query, at 100 items per page across ten pages, and gives no error when you hit the cap. If total_count exceeds 1,000, split the query by progressive date ranges to recover the rest. Code search has a separate rate limit of 10 requests per minute; an authenticated token raises repo-search throughput to about 30 per minute.
A contributor uses a noreply email. Can I still reach them?
Often yes. A privacy-masked address in the form ID+username@users.noreply.github.com blocks direct email, but it does not block the person. Open the profile before discarding them; many list an org, a location, a personal site, or a linked account. Assuming someone is unreachable because the commit email is masked is a common false negative.
How do I tell a core contributor from a drive-by?
Re-run git shortlog -sn --no-merges --since="6 months ago" and compare against the all-time list. A one-commit typo fixer disappears in the window. Watch the bus factor too: if one person holds 60% or more of commits, that is a concentration flag. Contributors with 3 or more weekly commits have been linked to 68% higher retention, so depth in the window is worth ranking on.
Should I clone the repo or use the API?
Clone when you can. The full local history lets you run git shortlog with --no-merges and -e, group by email, and inspect merge strategy, which the API contributor graph does not expose cleanly and which arrives bot-polluted. Use the API when cloning is impractical, but page at 100 per item and remember the 1,000-result cap and the separate code-search rate limit.
Try it on the search you came here for
Stop building boolean strings. Just describe the person.
Type one sentence. I plan the search, read GitHub, public LinkedIn and Crunchbase records, and the open web as it is right now, and hand back a ranked list with the reason next to every name.
01Describe them
One plain sentence. Role, city, stack, stage, whatever matters to you.
02I read the web live
GitHub, public LinkedIn and Crunchbase records, the open web. Not a database that went stale last quarter.
03You read the shortlist
Ranked, with the reasoning under every name. Open a profile, ask a follow-up, narrow it down.
- Staff backend engineers in NYC who shipped Rust in production
- Series A fintechs in SF under 50 people, growing headcount this year
- Maintainers of fast-growing Rust web frameworks on GitHub
- No boolean, no filters, no seat to buy. One box.
- Read at search time, so a profile updated yesterday counts today.
- Every step visible as it runs, every name with its reason.
500 free credits on sign-up. No card, no demo call. See real searches.