Srcsnap — Screenshot-Driven Version Tracking


Ask Zach Lieberman

Zach Lieberman 

 Do you work with graphics? Do you often find that an earlier version of your sketch looked more appealing? But then there's no way to go back because you made too many changes since? You didn't think you need a version control but now regret it? Do you like taking screenshots?

Then maybe srcsnap is a tool for you.

Every time you take a screenshot of your project, srcsnap takes a snapshot of all your code too, and associates it with the screenshot. It organizes your screenshots in a nice list in the menubar: Your code can "time travel" back to the very moment when you took each of the screenshots.

Here at Future Sketches group, we make images with code. Also, we take screenshots from time to time as we make progress. Now sometimes it turns out that we prefer a previous version of the program, at the moment of a certain screenshot; but we've since tweaked the code so much that there's no going back! That's why Prof. Zach Lieberman tasked me with the task of creating an app, which performs version control in your stead when you take screenshots.

There're perhaps several ways to implement the version control part. The simplest would be to duplicate your entire project folder whenever you take a screenshot. It would also be necessary to weed out the large files such as binaries so that it wouldn't be a disaster for your disk space. The way I decided go with was to leverage the power of git. The reasoning is that git seems to be very good at version control. We need version control functionality. So just use git.

Many people are scared of git. But fear not! I took care so that the user never need to know that it is git that got them covered behind the scenes. All they need to do is take screenshots and click some buttons when they want to revert.

We thought about two ways to do git. The first is to turn the user's project folder into a git repo, and directly issue git commands there. I thought there're a few problems with this approach. First, the user's project folder might already be a git repo. Maybe because they want their project to be on GitHub. Maybe they're already doing version control themselves, just not as frequently as they're taking screenshots, which they aim to remedy by using our app. Therefore, we wouldn't want to mess with their original git. Secondly, it is very easy to screw up in git. Many times my own git repos end up in strange limbo states that I no longer know how to fix, so I simply delete it and pull a fresh copy. We wouldn't want that to happen to our customer's projects!

Therefore, I went with the second approach, which is to have a secret copy of the original project folder which we do git on. When user takes a screenshot, we overwrite the content of this secret copy using the current content of the original project folder, and do a git commit. This way the original project folder is left intact, and the user can safely delete the secret copy entirely in case they decide that they hate our app.

A person might have different projects of the same folder name. Though the practice is questionable, the situation is still possible. When we make secret copies of their projects, how do we identify which is which? My solution was to partially reconstruct the folder structure of the user's disk in the app's secret folder, with only the necessary paths of course. This way not only is there no way to confuse, the git commands are also easy to generate.

Another technical question is how do we know when the user has taken a screenshot, and what project is that screenshot of. For the former, we decided to simply check files of a certain naming convention in a certain folder, as specified by the user. On macs, by defulat, this would be "Screen Shot ....png" in the Desktop folder. We look at that folder every few seconds or so to see if there's a new image added. For the latter, we reasoned that there's doesn't seem to be an automatic and reliable way to know, so we simply ask the user to tell the app where there project folder is. The user needs to remember to quit or disable the app when they're taking screenshots not for the purpose of documenting their project, and to respecify the project folder when they switch projects.

For the GUI, I decided to use Electron. Though Electron apps tend to generate much bloat, consume too much resources, sometimes janky, and are way overkill for the simple tasks they do, (and universally loathed by users), I used Electron anyways since it's fast for prototyping. I figured I could pick up Swift and write a native app should such need arise later.

The GUI went through several iterations (and perhaps many more iterations to come!) Currently, it resides as a little icon in your menubar. When first expanded, you're prompted to select your screenshot folder and project folder. The next screen shows all your screenshots for the current project. Upon hovering over each image, more details and options are shown: the date and time of the screenshot, as well as three buttons, image, code, and delete. Hovering over the image button shows a larger in-app preview of the screenshot on the side, while clicking it opens the image in the macOS Preview app. Clicking the code button will do a git checkout in the background, and, in case the project folder is of a familiar format (e.g. openFrameworks project), the secret copy of the project at the moment of the screenshot is opened directly with the appropriate editor (e.g. Xcode), or otherwise, the secret copy of the project folder at the moment of the screenshot is opened in Finder. Pressing delete button deletes the screenshot and the associated ability to go back to that point in time. The git commit is not deleted, since it would be a tricky thing to do; The user doesn't need to know about the git anyways.

There's also a config button allowing the user to tweak with more advanced settings. They could specify what files to ignore, filtering by size or file format. They could also see the amount of disk space the secret copy is costing them, as well as a list of git commands performed on their stead in the background.

The project website is here, while development of this project is tracked here on GitHub. As it is being continously developed, feel free to post any Issues!