Should I trust the GitHub activity summary ?

This was a very simple proof of concept done at 33C3 with nbornand. After an initial verification that GitHub does not (and cannot, in fact) perform sanity check on the commits, we realized that it would be easy to look like a very active developer by pushing commits with a random date. Then, we wrote a little script that writes a punchline on the GitHub activity panel.

[...]
dateTopLeftCorner = dateTopLeftCorner - DD_year
# word to print
letters = [P,R,O,B,A,B,L,Y, space, N,O,T];
#compose the list
grid = [];
[...]

Introduction. git is a distributed version control system, and GitHub.com is probably the most well-known way to host a git repository on the Internet. It has this fancy colored grid on your profile, the true expert's way of passively bragging about how productive your are.

Motivation. This grid is usually filled every time you commit some code; the more you work, the more little green squares you earn (a great way to keep your employees productive). Yet as a developer, one may wonder if we can earn more squares while doing less work.

Why it should work. As mentioned, git is distributed. You can sync everything with GitHub.com, but you could also keep everything local, or even sync with another computer, without going through GitHub. You can work without Internet for a few days, then sync all the commits afterward. Do you see where we are headed ? GitHub is forced to trust what you send, as you can do commits and resets locally. Sure, it's unlikely that you worked for a year before syncing with GitHub, but where to draw the line ?

We will explore how to rewrite the past with git, with the challenge of writing arbitrary words on GitHub's graph.

Hello world (GitHub version)

Rewriting the date of a commit. Most people are familiar with rewriting the message of a commit, using the git commit --amend command. Yet, we can rewrite the commit date too ! It relies on git filter-branch, which allows rewriting the history in arbitrary ways by applying a script to every commit. A simple example would be :

git filter-branch --env-filter \
    'if [ $GIT_COMMIT = 119f9ecf58069b265ab22f1f97d2b648faf932e0 ]
     then
         export GIT_AUTHOR_DATE="Fri Jan 2 00:10:20 2010 +0100"
         export GIT_COMMITTER_DATE="Fri Jan 2 00:10:20 2010 +0100"
     fi'
which applies the script starting with if to every commit, and changes the GIT_AUTHOR_DATE when the commit is 119f9ecf58069b265ab22f1f97d2b648faf932e0.

We use a slightly enhanced version, which has an optional force parameters that ignores deleting backups, and performs additional sanity checks (thanks peel for the script).

Writing a commit for a specific date. Once we have the ability to rewrite the date of a commit, the rest is simple automation. We first create a simple wrapper that creates a commit given a date :

#!/bin/bash
newDate="$1"
echo "$newDate" > date.log # so we have a file that changed
git add date.log
git commit -m "Commit for $newDate"
lastCommitHash=$(git log --format="%H" -n 1)
./change-git-commit-date.sh -f "$lastCommitHash" master "$newDate"

Writing letters. Then, we use a python script to find the date on the top-left corner of the GitHub activity map :

# finds the date x=0,y=0 on GitHub grid
today = datetime.datetime.now()
dayOfTheWeek = datetime.datetime.today().weekday()
DD_day = datetime.timedelta(days=dayOfTheWeek+1) # GitHub's grid starts on sunday,
                                                 # yet dayOfTheWeek=0 is monday in python
DD_year = datetime.timedelta(weeks=52)
dateTopLeftCorner = today - DD_day
dateTopLeftCorner = dateTopLeftCorner - DD_year

We (manually) design the letters :


A = [[0,0,0,0],
     [0,0,1,0],
     [0,1,0,1],
     [0,1,1,1],
     [0,1,0,1],
     [0,1,0,1],
     [0,0,0,0]];
Of course, doing this 26 times is really lame. We tried parsing the .TTF of a pixel font, but then we remembered that the goal of a proof of concept is to have the simplest, quickest version first, and we skipped it.

Then, we loop on the letters we want to print, flatten the two-dimensional array, and loop for every day since dateTopLeftCorner. It is rather straightforward and uninteresting; the code is there.

The final touch. We simply set letters = [H,E,L,L,O,space,W,O,R,L,D], run the script (rather long, in O(n^2), n the number of green cubes), and appreciate the result (a marvel of typography) :

(Source discarded)
VoilĂ  !

Extras

Changing authorship. You used the script on a fresh GitHub account (so your project's contribution wouldn't overlap with your letters), and git push -f'ed it. Yet the grid remains desperately empty : that's probably because your git software is configured to create commits with your real identity, not the fresh one. This is set in ~/.gitconfig :


[user]
   name = Ludovic Barman
   email = #SPAMBOTS_WILL_NOT_HAVE_THIS
Solution : recall that git filter-branch solves every single problem, and rewrite the author information.

Changing the message. Did you write HI MICROSOFT, but didn't get the job ? Here's the clean slate program, if there was an initial commit in your repo :

initial_commit=$(git log | tail -n 5 | head -n 1 | sed -e "s/commit //"  )
git reset --hard "$initial_commit"
git push -f

Ludovic Barman
Ludovic Barman
written on :
28 / 12 / 2016