Per repository history in zsh
A month or two ago, I was working on multiple repositories at once and switching between the repositories way too often, and this was starting to get annoying... every time I relied on my bash history to do something specific to that repository, my shell activity in other project was getting in the way.
To solve this problem, I decided to take a radical approach. What if I was only storing my shell history per repository, not having access to global history, and only restricting myself to the commands I've already executed in my current repository.
At first, I thought it was a bad idea, and I was scared, but I decided to do it anyway and see how it turned out. And I feel no regret in making this decision; now, every time I switch between projects, I can see my shell history for that project, see the last steps I had taken, and have an idea of what I was doing.
I added the following script to my ~/.zshrc
file:
function _better_history_hook() {
# echo "Better history at work!"
local BETTER_ROOT=$(pwd)
if GPATH=`git rev-parse --show-toplevel --quiet 2>/dev/null`; then
# echo "repo: $GPATH"
BETTER_ROOT=$GPATH
else
# echo "not a repo"
fi
local BETTER_DIR="$HOME/.history$BETTER_ROOT"
local BETTER_FILE="$BETTER_DIR/history"
# make sure the directory exists.
mkdir -p $BETTER_DIR
export HISTFILE=$BETTER_FILE
#discard previous directory's history
local original_histsize=$HISTSIZE
export HISTSIZE=0
export HISTSIZE=$original_histsize
#read history in new file
if [[ -e $BETTER_FILE ]]; then
fc -R $BETTER_FILE
fi
}
add-zsh-hook chpwd _better_history_hook
_better_history_hook
This code uses the zsh hook to listen for whenever the cwd changes, for example when you start the terminal
or cd
to a directory. And then changes the history file (default to $HOME/.zsh_history
) to a file specific
to that repository or the cwd
if the cwd
is not within a git repository.
To do this, we first run a git command to get the root of the current repository. This command returns the most top-level directory within a git repository.
git rev-parse --show-toplevel --quiet 2>/dev/null
It then changes the history file to a file for that directory. I decided to store the history in a $HOME/.history
directory to do this. After using my terminal for a while, this is how my .history
directory looks like:
> tree ~/.history
/Users/parsa/.history
├── Users
│ ├── history
│ └── parsa
│ ├── Library
│ │ └── Messages
│ │ └── history
│ ├── Projects
│ │ ├── Crypto-Research
│ │ │ └── history
│ │ ├── aquascope
│ │ │ └── history
│ │ ├── benchmarks
│ │ │ └── history
│ │ ├── blog
│ │ │ └── history
│ │ ├── cargo
│ │ │ └── history
│ │ ├── tokio
│ │ │ └── history
│ │ ├── ursa
│ │ │ └── history
│ │ ├── ursa-fresh-clone
│ │ │ └── history
│ │ ├── ursa-hack
│ │ │ └── history
│ │ ├── ursa-hack-make-edited
│ │ │ └── history
│ │ ├── ursa-hack-make-edited-2
│ │ │ └── history
│ │ ├── ursa-hack-no-make
│ │ │ └── history
│ │ ├── ursa-make
│ │ │ └── history
│ │ ├── ursa-nodes
│ │ │ ├── history
│ │ │ ├── node-01
│ │ │ │ └── history
│ │ │ ├── node-02
│ │ │ │ └── history
│ │ │ └── node-03
│ │ │ └── history
│ │ └── ....
│ ├── history
│ └── notes
│ ├── Work
│ │ └── history
│ └── history
├── private
│ └── tmp
│ └── cli-space-invaders-rust
│ └── history
└── tmp
└── history
54 directories, 49 files
If you like content like this don't forget to follow me on Twitter :)