A tool for generative artists to automatically record ephemeral image sources.
This tool watches a specified directory for the creation of files with names that match a specified pattern, and then automatically creates a git commit in a source repository that represents the code that created that file.
I use this while creating generative art projects so that each output created during the development process can be tracked back to a specific code/hash combination, allowing me to easily recreate them as needed.
NOTE: Since this only uses the filename as the commit message, be sure to put the random number seed (and anything else you need to retain) into the filename so that it's automatically included in the commit message.
This is a very basic set of shell scripts, but it solves my specific problem. YMMV.
- This has only been tested on MacOS! Other platforms may require changes.
- This also assumes that you don't have more than two git worktree branches for a specific repository.
- git - Source code version control system
- fswatch - Cross-platform filesystem change watcher
- rsync - Synchronizes different directories
If you're on MacOS, you can use homebrew
to easily get
these via brew install git fswatch rsync
.
-
Clone this repository onto your machine.
-
Create a git worktree branch of your in-development repository that will be used to record snapshots. (A worktree makes it easy to have another branch checked out in a different directory, while still sharing the version control history.) All commits made to this worktree version will be reflected in the original repository, so you won't have to push changes from two locations.
I typically create a directory that contains all such repositories, so that they're out of my way when I'm doing other work.
For example, if I have a development repository at
~/src/genart/my-new-project
, I create a directory called~/src/autocommit-repos
that I use to store all of my active autocommit worktrees.Once you have a place to create your autocommit worktree, create it like this:
cd ~/src/genart/my-new-project git worktree add ~/src/autocommit-repos/my-new-project-autocommits -b autocommits
This command creates an active git worktree for your current repository in the directory
~/src/autocommit-repos/my-new-project-autocommits
and checks out the branchautocommits
in that repository. (You can name the branch whatever you want - just be sure that it's different from your active branch name.) -
Go into this new directory and run the watcher script, providing a regular expression that will match the files that you want to trigger the autocommit snapshot process.
The command format is
watch.sh -r <regex> -b <branch> <directory to watch>
. For example:cd ~/src/autocommit-repos/my-new-project-autocommits ~/src/git-autocommit-bot/watch.sh -r 'wip-.*.png$' ~/Downloads
(Note that the regular expression format is best handled by a single-quoted string specification.)
Specifying the -b option will tell the script to use the worktree associated with that branch as the source repository. If not specified, the the source branch will default to "main".
When you run the watch.sh
script:
- An
fswatch
process is created that will watch for the creation of files that match the regular expression specified. - When a matching file is created, an
rsync
process is spawned that will copy everything that isn't ignored by the.gitignore
file in original repository into your autocommits worktree. - A (potentially empty) commit will be created with the name of the file that was created as the commit message.
That's it.
Because all of these commits are on a separate branch, be sure to include them when you push to your remote repository. I typically push all of my local commits and branches via the following git command.
git push origin --all
I created this instead of using an existing tool like dura for two reasons:
- I wanted a specific type of git history to be created for snapshots that was separate from my actual development commit history.
- I like to tinker, and I had a feeling that this was possible with some simple shell script glue.
fswatch
requires you to exclude everything (via -e '.*'
), and then specify the specific
pattern that should be matched (via -i '<pattern>'
). This will only match files that have this naming
scheme, and ignore everything else.
fswatch --event Created -e '.*' -i 'wip-.*.png$' ~/Downloads | xargs -I{} echo TEST: {}
The --exclude='.git/
will exclude the git repository data from the copy, since
that's not needed.
The --filter=':- .gitignore'
flag will parse the contents of a .gitignore
file and exclude them from the transfer, avoiding things like copying the
node_modules
directory, etc.
Don't use a bare repository with worktrees inside of them, as that comes with some unexpected issues regarding fetching (see this blog post).
Create a (possibly empty) commit on the current branch by automatically committing all changes.
git add --all
git commit --allow-empty --message 'message'
Maybe add support for notifications?
A simple notification can be send from MacOS by running the following command:
osascript -e 'display notification "notification message text"'