How to keep per-directory command history in Zsh
How to keep per-directory command history in Zsh
You can approximate per-directory history in zsh using plugins or custom hooks. The shell itself doesn’t support this natively (though patches have been proposed). (zsh.org)
Here are viable methods:
Method 1: Use the “per-directory-history” plugin (Oh My Zsh or standalone)
- Oh My Zsh includes a plugin called
per-directory-history
. (GitHub) - To enable it, add
per-directory-history
to yourplugins=( … )
in~/.zshrc
. (Unix & Linux Stack Exchange) - The plugin arranges that commands are saved to both a global history file and to per-directory-history files (mirroring the directory tree under a base history directory). (Jim Hester)
- There is a toggle (default key binding
Ctrl-G
) to switch between viewing global history and directory-specific history. (GitHub) - You can configure base dir for per-directory history via a variable like
HISTORY_BASE
. (GitHub)
Method 2: Use another plugin or custom “cwd-history” approach
- The plugin zsh-cwd-history stores separate
HISTFILE
per directory and uses thechpwd
hook to change history file when youcd
. (Unix & Linux Stack Exchange) - Another project: ericfreese/zsh-cwd-history (mentioned in StackOverflow answers) (Unix & Linux Stack Exchange)
- You can bind a key to toggle between directory history vs global history in such plugins. (Unix & Linux Stack Exchange)
Method 3: DIY using hooks (zshaddhistory / chpwd)
If you want to roll your own:
- In your
~/.zshrc
, set a base directory to store local histories, e.g.:zsh
export DIRHIST_BASE="$HOME/.dirhist"
- Use
chpwd
hook (runs on eachcd
) to switchHISTFILE
:zsh
function chpwd_set_histfile() { local dir_rel="${PWD/#$HOME\//}" # directory relative to home local histf="${DIRHIST_BASE}/${dir_rel}/.zsh_history" mkdir -p "$(dirname "$histf")" HISTFILE="$histf" } autoload -U add-zsh-hook add-zsh-hook chpwd chpwd_set_histfile
- Optionally, when starting the shell (at prompt or init), you may want to load the relevant directory history:
zsh
if [[ -n $PWD ]]; then chpwd_set_histfile fc -R # read history from the new HISTFILE fi
- You may also want to duplicate commands into a global history file (so you don’t lose cross-dir commands). You can use the
zshaddhistory
function to append each new command to a global log as well. Example:zsh
function zshaddhistory() { local cmd=${1%%$'\n'} # strip newline print -sr -- "$cmd" # to current HISTFILE print -s -- "$cmd" >> "$HOME/.zsh_global_history" return 1 # prevent double logging by default handler }
Caveats:
- You must manage
HISTSIZE
,SAVEHIST
, trimming, etc. - If you have concurrent shells in the same directory, they write to the same file.
- Performance may degrade if you have many directories with deep trees.
- Some plugins limit history size per directory.
If you like, I can generate a ready-to-use .zshrc
snippet (or plugin setup) for your environment (Linux/macOS). Do you prefer plugin-based or DIY?