GitHub's contribution graph is a bad metric, and most developers know it. It still gets a glance: after a break, after a job in private repos, after a year that looks quieter than it felt.

The usual response is a script. Clone gitfiti or github-activity-generator, paste a personal token, wait, and hope the dates land on the right day. Some of those scripts are genuinely fun — pixel art on a calendar is a hacker classic. A lot of them also paint a barcode over days you actually worked, leave you with no preview, and make undo a problem for future-you.

We wanted the other version of that tool. So we built RetroFill.

You can load any public profile and preview a fill on the real graph, with no sign-in. You can paint days by hand, or let a realism engine propose a year. When you execute, RetroFill creates one new repository with the name you choose and pushes real backdated commits with real diffs. Gap-only is on by default, so days you already contributed are skipped. History keeps every job, and one click deletes the repo.

It is still generated activity. Anyone can open the repository and see that it was created on one day, with earlier author dates. We think that is the right amount of visible. A green graph is not a résumé.

What actually gets pushed

A fill is a small git repository whose commits carry the dates you chose, pushed once to a new repo on your account. There is no magic API for "paint this square." GitHub counts the commits the same way it counts any other commits on a default branch.

The pipeline has five stages. The first two run in your browser while you preview; the last three run on our server and stream back as a live log.

1. Plan. The realism engine is a pure, deterministic function. Give it a seed, a date range, and a persona, and it returns { date, commits } pairs. The same seed produces the same plan in the browser and on the server, which is why the preview matches the push.

It models the unevenness of a real year: weekday versus weekend weighting, an energy curve so some months are busy and some are quiet, streak momentum, vacations, a late-December dip, optional public holidays, and heavy-tailed daily counts (mostly a few commits, occasionally a crunch). "Match my rhythm" can infer your weekday/weekend ratio and burstiness from a real graph and continue that pattern. "Respect existing" is on by default.

2. Timestamps. A day with n commits becomes one to three work sessions, at human hours in your timezone, with gaps of roughly ninety seconds to fifty-five minutes. We only pick wall-clock times whose UTC date equals the local date, so the square lands on the day you painted whether GitHub files it by the timestamp's timezone or by UTC.

3. Build. The repository is built with isomorphic-git — a git implementation in JavaScript. There is no git binary involved. Each commit writes real files, not an activity log. You pick one of three templates: a "Today I Learned" notebook, a small TypeScript utility library with tests, or a dev journal. Commit messages come from template-specific pools. Author and committer are your display name and your GitHub noreply address, id+login@users.noreply.github.com.

4. Push. We create a brand-new repository with the name you typed and refuse to continue if that name already exists. Then main is pushed once. Sign-in is read-only. Writes go through a GitHub App you install on the repositories you choose; GitHub refuses a write anywhere else, and a private repository you did not pick is invisible.

5. Verify. A commit counts when the author email is linked to your account, the commit is on the default branch, the repository is not a fork, and (for private repos) "Include private contributions" is on. The pipeline is built so those are true by construction. GitHub usually redraws the graph within minutes, and documents up to 24 hours.

Before execute, a preflight we call the Contribution Doctor checks access, attribution, account age, name collisions, and the private-contributions switch. Accounts under 30 days old get a warning and a suggestion to start small. Volumes are capped at a human scale.

Undo is deleting the repo, not rewriting your history

Every fill is a job with an Undo button. Undo deletes the repositories that job created — and only those. Because undo is repository deletion rather than a force-push, it cannot touch anything that existed before RetroFill.

If you have used the script-and-hope path, that is the part we cared about most.

What this is for, and what it isn't

People use a tool like this for pixel art across a year, for gaps GitHub never counted (a wrong email, a squashed history, work that lived in a private account), for keeping a streak through a rough month, or because a less abandoned-looking graph makes them happy. All of that is fine.

Do not present the squares as evidence of specific work. Not to an interviewer, not to a client, not on a résumé line. They will click the repo, and they should be able to.

If your graph went empty after leaving a job, start with GitHub's actual rules: add the email you committed with, and turn on "Include private contributions." That is how real work gets counted. A generated repo will not bring back an employer's private history after your access was revoked, and we will not pretend otherwise.

The longer version of all of this lives on our transparency page, and the pipeline is written up in how it works.

Preview is free and needs no sign-in. The first fill is free too, if it stays within 7 days and 20 commits — enough to watch a real push land, and enough to undo it.

If you try it, I would love feedback on whether the realism engine looks like a person, and on anything that feels unclear about what it does to your account.

Preview a graph on RetroFill