This will undoubtedly go down as one of those things that is unsearchable on the larger internet. So if somehow you have stumbled onto this, congratulations on also being interested in really esoteric things.
git has a thing inside of it called snapshots that are fundamental to how git works. This has nothing to do with that.
I find that when I am working in a git repository, I want to make commits where I am confident with my changes wherever possible. I don’t like doing X, undoing X, trying something else, oops, try again.
I will happily make multiple, frequent commits, but only if I like the change. If I’m on the fence, or if I feel its incomplete, then I’ll want to continue on until I get something i’m more confident with.
Because of this, I found myself with the desire to do a snapshot of my changes as they currently are.
Traditionally, I achieved this by doing a git stash; git stash apply
but particularly if I am doing the stash and apply in source tree or some other gui, I find myself just unhappy with the time spent. So I put together some scripts to help with this process, and do it a little faster.
Snapshot the current changes
fundamentally this comes down to a single command with a bunch of stuff to go with it.
1 |
git stash store $(git stash create) -m "message" |
git stash create
will create a stash, but won’t actually save it. Meanwhile git stash store
will store a stash that has been created. But this combination of creating and storing the stash is not the same is if you just run a normal git stash
which would create the stash, and roll your current changes back to head.
So this combination will create a stash, store it, but leave all the changes exactly as they are.
Unfortunately, new files in git are kind of always treated a little odd. It sort of makes sense, but basically new files will pretty much be ignored by git unless you stage them for commit. The part that makes sense is because you don’t want things like your build artifacts to get caught up in stashes. But the part that makes it go back to not making sense is that’s what the git ignore is for.
If you stick with a traditional git stash push && git stash apply
then you can use the --include-untracked
or -u
flag to include untracked files. But I’ve never had any success getting this to work the way I expected it to. eg, stash unstaged and untracked new files that aren’t ignored by the git ignore.
So I have the best success staging new files in the state I want snapshot, and then doing the snapshot.
Auto snapshot script
auto snapshot – this script will make an automated message. I find I prefer this over the “WIP on …” messages that get auto created by a normal git stash.
1 2 3 4 5 6 7 8 9 10 |
#! /bin/bash suffix=`date '+%m/%d %H-%M'`__$((RANDOM%99)) branch=`git branch --show-current | sed -e 's/.*\///g'` message="$branch - $suffix" echo $message git stash store $(git stash create) -m "$message" |
the message will ultimately loo something like main - 05/15 13:40__82
So the suffix will be a timestamp so you know when you made the snapshot, and then its got 4 random garbage characters just to make sure if you do multiple snapshots in a single minute you’ve got some kind of uniqueness.
There are lots of alternatives to $RANDOM
if you want something that is always the exact same number of charafters, you could do something like uuidgen | md5 | head-c 4
. But I chose to go with $RANDOM
because it works in both mac and windows git bash.
Snapshot with manual message from MacVim
This script is intended to let you type in a message for the snapshot instead of just making an automated message. The script only works with MacVim, and I don’t now how to do it with something else, because I use MacVim, so its the only thing I care to make it work with
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#! /bin/bash file=~/`date '+%m-%d-%H-%M'`-`uuidgen | md5 | head -c 8` message1=`git branch --show-current | sed -e 's/.*\///g' -e 's/$/ - /' ` echo "$message1" > "$file" mvim -f -c 'startinsert!' $file message2=`cat $file` rm $file if [[ "$message1" != "$message2" ]]; then git stash store $(git stash create) -m "$message2" else echo "cancelled" exit 1 fi |
In this script we start by making a temporary file we can use to write the message.
We put the branch name into that file, and then launch MacVim, telling it to start in insert mode with -c "startinsert!"
so that we can just get to typing.
MacVim will block until it is closed, and then we will read the file, compare it against the original in case we just went “oops” <esc>:q!
and then we close make the snapshot.
Sourcetree Integration
I have not tested this in sourcetree for windows. I know the UI is slightly different, but in theory, it should be similar
Save the script to a .sh
file, and make sure you chmod +x
the file
In Sourcetree you can go settings -> custom actions
and add an action with the script to run set to the script.
Now in the menu bar you can go Actions -> Custom Actions
and it will show up. Or if you right click on a file in sourcetree, you can go Custom Actions -> Repository Actions
and it will show up.