Commit syncing across hosted GIT instances
/* How I keep my commit graph alive */
Since September of 2018 (3 and a half years ago) I have been roughly holding a streak of going no more than three days without making a commit to some project on GitHub.
This is not entirely intentional, and I have broken it a few times:
- June 7, 2019
- August 8, 2019
- September 27, 2019
- November 3, 2021
..but a streak is a streak. A few of my friends know about this and keep an eye on my commit graph and I do too. Recently, with most of my programming time allocated to work, my graph started looking like weeks of empty cells, implying I broke my streak for good.
In reality, that couldn't be farther from the truth. I have been writing quite a lot of code actually, its just all tracked in a company GIT instance with a separate account.
Time for some trickery
I happened to remember a little trick I used in a CI pipeline for Raider Robotics where you can backdate empty commits with arbitrary authors. I recall using this for some kind of version tagging system at some point.. idk.. the important part being it is possible to make "fake" commits with the right command-line flags.
The game plan
My idea was as follows:
- Scrape all work repos for commits authored by one of my email addresses
- Keep track of the commit timestamps
- Make empty commits to a GitHub repo and backdate them to the timestamps from the last step
- Enjoy having my GitHub contributor graph synced to my work account
For anyone concerned with the security issue of leaking commit data, In my real implementation, dates are shuffled a bit. This also all happens in a private repo, so the public can only ever see its affect on my commit graph, and can't actually see the commits themselves.
Scraping commits from repos
git command has a
log subcommand for querying info about commits. In its simplest form, you can dump all commits for a repo with:
git -C /path/to/repo log --pretty=format:"%H"
An example output for the repo behind this website:
... 62d0c4833766671182ed0aeeb76bb16cc3f35174 420b3cc4a9d61024e0dd6c32deafb57244d09433 fed6fc374d02c2ae8f67bff837c8c8334760b303 5a64788339afd750c3853468f89d275cf8fa49cd 01992912951d80631fa5069fce7d9a3593bbcd39 d894387400158d231ed6559636169f1464bb630d 4a68456c7a5df699bc7620c9250b7a04aac5bd3c ff87809b9c14c5132ecd5a39921b1cf2118b12cc 2b8797bbdcec61654540d995aaae67bcab8dc1c1 c4d978c5d098846b8a0105c5b6d3f42b389c6ea7 9791cdd979a17f0d5ebf9028d4778152ca07ae1d dda08261872d3c2301cc02108c0f466dedaacaca f408c1fa9785a40038e04b0ef017bd8d2897cdd6 ...
Its just a bunch of hashes.
As a side note, if you are trying to replicate my work and also commit with multiple email addresses, you can chain
--author flags together.
git -C /path/to/repo log --pretty=format:"%H" --author[email protected] --author[email protected]
If we iterate over our list of hashes, we can perform the rest of the steps. The main data point we care about is the timestamp.
To fetch a commit timestamp from a repo, use the following, replacing
$COMMIT_HASH with the hash in question:
git -C /path/to/repo show -s --format=%ci $COMMIT_HASH
And finally, with our timestamp (stored as
$DATE) a new commit can be written to a target repo:
git -C /path/to/public/repo commit -m "A message." --date="$DATE" --no-edit --allow-empty
--allow-empty flag removes the requirement for any files to be contained in the commit, essentially allowing you to have a "zero size" repository.
Uh, ya. Cool. With your scripting language of choice, you can chain these commands together, toss a
git push in there, stick this in a cron job, and have yourself a nice, healthy commit graph.