I think people trip on these potential foot guns in part because a lot of git commands are long and annoying to type, so you end up working more based on your mental model of the state of the working copy and less based on the actual state of it.

I am not so fond of analogies but I would like to offer up an analogy here anyway. I think for a lot of people, the way that they are using git is akin to utilizing a sharp knife with your hands while your hands are obstructed from your view. You have a certain amount of feeling for what is going on but you are bound to cut yourself now and then if your view of what you are doing is obstructed. In this analogy, your reliance on your mental model of the state of the working copy is obstructing your view of the reality of the state that it is in.

Several years ago I defined a few two-letter shell aliases for the git commands that I use the most.

Maintaining my .bashrc across different systems became a drag though, so I simplified my setup even more.

I wrote two-letter “shell scripts” that just wrap the commands, and just put those in my ~/bin/. This makes it very fast and simple to get up and running on a new laptop, desktop or server.

https://github.com/ctsrc/shell-command-aliases

Said two-letter shell scripts can be found in that repo. There’s a README too, which tells you what each of them do.

My git workflow is simple, efficient and ensures that my view of what I am doing is not obstructed.

I can proudly say that the last time I did something unintended with git that resulted in lost work was long ago that I can’t even remember when. And it all boils down to these two-letter aliases.

When there is friction, identify the friction and remove it. That is what I have done here. Hopefully it might be of use to others too.

Here are some consecutive entries from my bash history that are representative of how I use my aliases while working on something.

mv ~/tmp/index.htm dimensions.htm
st
ls
dp
git checkout -- src/
st
mv dimensions.htm src/
st
mv src/dimensions.htm src/draft.htm
di
st
aa
cm "Draft."
le
le
vim src/draft.htm
st
vim src/draft.htm
aa
di
cm "Mirrored, dark/light."
vim src/draft.htm
aa
di
vim src/draft.htm
aa
di
cm "Remove unneccessary declaration."
vim src/draft.htm
aa
di
cm "Organize and restructure classes in draft."
vim src/draft.htm
aa
di
cm "Increase height of placeholder."
pu
le
st
st
dp
vim src/draft.htm

I keep a few terminal windows open when I work on a project, and often use one or two of them for git operations, and smaller edits to some files, while also having my IDE open, web browser, etc.

Notably, these two-letter commands make it very fast to remind myself of what the current state of the repository is whenever I've looked something up on the Internet for example, or after I have run tests in another terminal or made multiple different edits in different files in the IDE window, etc.

And I always check the diff before I commit. It's amazing how often you think you are about to commit just one change but when you look at the diff you realize that there are some other smaller changes that you made as well. By always reviewing your diff before you commit, you ensure that you don't commit something that would be better committed separately, and that your commit messages accurately describe the actual changes that you are committing.