While developing, I have two fears/work flows that I've tried several ways to overcome or improve.

  1. I do a lot of experimenting with code and don't commit changes until I've got the solution I want.
  2. I'm afraid I'll lose my changes due to Visual Studio Code's ability to undo even after saving "feature" 😠, a mistake in my rough git knowledge, or losing my computer due to a crash, theft or the zombie 🧟 apocalypse. It could happen!
  3. Sometimes, I really like a solution or the ideas currently in code but don't actually use them in the final commit. So, I want to be able to easily references them sometime down the road even on a different project.

For #2, you might suggest git stash.  I do use stash some, but I'm not really a big fan of it - mostly because it doesn't solve problem #2 or #3.  Additionally, I don't like the fact that stashes are ephemeral.  They can easily be accidentally deleted - looking 👀 at you git stash pop.

I think I've finally come up with a solution I like.  The general flow:

  1. Stage all changes
  2. Create a patch file with something like git diff --patch --staged

Seems pretty simple, right?  However, I may want to create several patch files and don't want all the bother of renaming files after they are created.  Enter some handy aliases:

# Print the current branch.  Not really needed in zsh, but handy to have
alias gitcb='git rev-parse --abbrev-ref HEAD'

# Replace any forward slashes in the branch name with a reverse slash
# feat/improve-all-the-codez becomes feat\improve-all-the-codes 
alias gitcbs='git rev-parse --abbrev-ref HEAD | sed "s/\//\\\/g"'

# This command can be broken into steps on the ";"
# Step 1: Stage all the changes
# Step 2: Create a patch of all the changes and send the output to a file.  
# The file name will be the name of the current branch 
# (with forward slashes replaced) and the current datetime.
alias crpatch='git add .; git diff --patch --staged > $(gitcbs)_`date +"%Y%m%d_%H%M"`.patch'

IMPORTANT: The aliases above have been modified from the original due to a bug.  The original crpatch alias was always creating patch files with the same branch and time in the file name.  This was due to using double quotes instead of single quotes 🤦‍♂️!

FYI: You should probably add all those aliases to your .bashrc , .bashprofile, .zshrc, or whatever so they'll be around next time you open the terminal.

Finally, to create my patch, I just do crpatch (short for "create patch").  Tada!  Everything is in one nice neat patch file ready to be restored if needed.

diff --git a/file1.txt b/file1.txt
index 5c1170f..16cd50e 100644
--- a/file1.txt
+++ b/file1.txt
@@ -1 +1 @@
-This is file 1.
+This is file #1.
diff --git a/file2.txt b/file2.txt
index 3eac351..8f243e7 100644
--- a/file2.txt
+++ b/file2.txt
@@ -1 +1 @@
-This is file 2.
+This is file #2.

Wait a minute!  That doesn't solve #2 or #3, right?  Well, I have some hacks for that as well.

  1. Modify the crpatch alias to include a path to a cloud service like DropBox or OneDrive.
  2. If #1 is not an option, use my current hack: I drag them into a personal Slack channel. Now, they are all backed up!

What do you think?  Is this a good approach?  If you have suggestions or even an entirely different approach, please let me know on Twitter.

UPDATE 1: David Dal Busco pointed out that WebStorm has patching integrated into the IDE.  So, I found something similar for Visual Studio Code.  The Git Patch extension allows you to create patches.  However, the process is slower and doesn't automatically name the files the way I like.

UPDATE 2: Since I'm putting all my patch files in a specific location, they are going to become hard to distinguish.  Is this a patch file for Project X or Project Y?  So, I've modified my crpatch alias to also include the current directory name (project name).

alias crpatch='git add .; git diff --patch --staged > ${PWD##*/}___$(gitcbs)___`date +"%Y%m%d_%H%M"`.patch'

Now, my output looks like this:

Update 3:  It turns out that Dropbox will not upload a file with a backslash in the name.  So, I've modified replaced the gitcbs (git current branch with a slash) to gitcbp (git current branch with a parenthesis).  Now my files look like

Original with gitcbs :
patch-demo___feat\update-text-in-files___20190906_0744.patch

New with gitcbp:
patch-demo___feat)update-text-in-files___20190906_0755 copy.patch