Git Worktree vs Git Savepoints

The official Git documentation presents the following example as a valid use-case for the worktree command:

You are in the middle of a refactoring session and your boss comes in and demands that you fix something immediately. You might typically use git-stash1 to store your changes away temporarily. However, your working tree is in such a state of disarray (with new, moved, and removed files and other bits and pieces strewn around) that you don’t want to risk disturbing any of it. (source)

If you don’t know about worktree, you should check it out. It is a handy, powerful yet little known command. I don’t use it, however. It will check out a new branch to a new directory, and I don’t like that. I prefer to keep the simple, default 1:1 relationship between the repository and the file system. Managing multiple working trees seems like an unnecessary complication when similar results can be achieved with a few aliases.

Indeed, for the use-case above, my workflow revolves around three git-aliases. Over the years, I collected many. Most of them (like the ones mentioned here) are not my doing. I stumbled upon them somewhere, tinkered as needed, and then incorporated them into my daily workflow.

git save

This adds all changes, including untracked files, to the staging area and then commits with a SAVEPOINT message. When an emergency hits and I need to quickly switch context, I’ll just git save and check out to a new branch to do whatever I am tasked to do. When I’m done, I’ll switch back to my original branch, git undo(see below), and resume work. It’s easily configured with:

$ git config --global alias.save '!git add -A && git commit -m "SAVEPOINT"'

git wip

wip is similar to save. It stages all tracked changes and then commits with a WIP message. So yes, it offers the same features as above but leaves untracked files unstaged, a significant difference. Like above, when done with the extra work, I’ll switch back, git undo, and resume. Set it up with:

$ git config --global alias.wip '!git add -u && git commit -m "WIP"'

git undo

This alias allows me to quickly resume work after a save or wip. It undoes the last commit but keeps its changes, with files unstaged. It can also be used in other circumstances (for those, however, I have a functionally identical r1 alias at hand). Configure with:

$ git config —-global alias.undo 'reset HEAD^ —-mixed'

git wipe

This is a special, use-with-caution one. It adds changes in the working tree to a WIPE SAVEPOINT commit, then it wipes the commit. At that point, the working tree is clean, but I can still go back to that work if the need arises (via reflog). Seldom used, this wipe comes in handy when I have some experimental code that is not going into production and yet, I want to keep it around. Set it up with:

$ git config --global alias.wipe \
    '!git add -A && git commit -qm "WIPE SAVEPOINT" && git reset HEAD~1 --hard'

If you are not familiar with the git reflog, you might want to stay clear from wipe, though.

One advantage of this workflow is that saved changes will stay with their relevant branch. When you get back to it, git log will hint at what happened when you left. Assuming it is a private branch, you might even decide to push it for backup before starting the hotfix work.

Subscribe to the newsletter, the RSS feed, or follow @nicolaiarocci on Twitter