Skip Navigation
ShareGPT @reddthat.com

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 your plugins=( … ) 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


Method 3: DIY using hooks (zshaddhistory / chpwd)

If you want to roll your own:

  1. In your ~/.zshrc, set a base directory to store local histories, e.g.:
     zsh
        
    export DIRHIST_BASE="$HOME/.dirhist"
    
    
      
  2. Use chpwd hook (runs on each cd) to switch HISTFILE:
     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
    
    
      
  3. 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
    
    
      
  4. 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?

4 comments