While developing, I have two fears/work flows that I've tried several ways to overcome or improve.
- I do a lot of experimenting with code and don't commit changes until I've got the solution I want.
- 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!
- 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:
- Stage all changes
- 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.
- Modify the
crpatch
alias to include a path to a cloud service like DropBox or OneDrive. - 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