#!/usr/bin/python3 """Print out all commits made a power-of-3 days ago. Run this every day to refresh your memory of what you’ve done in the past. It will show you your commits from 1 day ago, 3 days ago, 9 days ago, 27 days ago, 81 days ago, 243 days ago, 729 days ago, 2187 days ago, etc. My dev3 repository has 2479 commits in it over 11 years, which is about 4000 days, so it shows me stuff from just those 8 days. In effect I’m shadowing myself on 8 of those 4000 days. If I keep using the repo for another 7 years, it'll start showing me stuff from 6561 days ago too. The idea is that when you do a commit, it will remind you about it one day later, 3 days later, 9 days later, etc., in an exponentially decreasing fashion. Reviewing the commits from 4–9 previous days is a reasonably small workload. It takes about 300 milliseconds on my MicroPC to filter through those 2479 commits. """ import os, subprocess, time class Commit: def __init__(self, hash, text): self.hash = hash self.text = text self.parents = [] self.time = None for line in text.split(b'\n'): words = line.split() if not words: break if words[0] == b'parent': self.parents.append(words[1].decode('utf-8')) elif words[0] == b'committer': self.time = int(words[-2].decode('utf-8')) class Gread: def __init__(self): self.git = 'git' cmd = [self.git, 'cat-file', '--batch'] self.kid = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE) def read_commit_raw(self, hash): self.kid.stdin.write(hash.encode('utf-8') + b'\n') self.kid.stdin.flush() result = self.kid.stdout.readline().split() if result[1] != b'commit': raise OSError(result) length = int(result[2].decode('utf-8')) text = self.kid.stdout.read(length) nl = self.kid.stdout.read(1) if nl != b'\n': raise IOError(result, text, nl) return hash, text def read_commit(self, hash): hash, text = self.read_commit_raw(hash) return Commit(hash, text) def walk(self, start): "Yield all commits ancestral to start." stack = [start] seen = set() while stack: hash = stack.pop() if hash in seen: continue seen.add(hash) commit = self.read_commit(hash) yield commit for parent in commit.parents: stack.append(parent) def day_of(time_t): "Counts days from the epoch in UTC." return time_t // 86400 def power_of(base, n): "Return true iff n is a power of base." while n and 0 == n % base: n //= base return n == 1 if __name__ == '__main__': today = day_of(time.time()) g = Gread() n = 0 for commit in g.walk('HEAD'): n += 1 delta = today - day_of(commit.time) if power_of(3, delta): #print(commit.hash) subprocess.run([g.git, 'show', '-s', commit.hash]) print(f"processed {n} commits")