Skip to content

Instantly share code, notes, and snippets.

@codemedic
Created May 14, 2025 14:16
Show Gist options
  • Select an option

  • Save codemedic/b2cb583973f8dd3a291c56c1f5348efa to your computer and use it in GitHub Desktop.

Select an option

Save codemedic/b2cb583973f8dd3a291c56c1f5348efa to your computer and use it in GitHub Desktop.

Revisions

  1. codemedic created this gist May 14, 2025.
    3 changes: 3 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,3 @@
    # Change History

    A helper for the Bash shell that allows you to manage individual history files for specific directories.
    76 changes: 76 additions & 0 deletions ch.bash
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,76 @@
    # The base path for the history files created by ch
    ch_history_base_path="$HOME/.bash_history.d"

    # ch_hist_file is a helper function to get the history file for a given directory.
    # If no directory is given, it will use the current directory.
    ch_hist_file() {
    local dir
    dir=$(realpath "${1:-.}")

    # Check if the directory is under the home directory using a prefix match
    if [[ "$dir" != "$HOME"* ]]; then
    echo "ch: Directory is not under the home directory" 1>&2
    return 1
    fi

    local history_file="${ch_history_base_path}/${dir#"$HOME"}.bash_history"
    echo "$history_file"
    }

    # ch is a function to change the current directory and load the history file for that directory.
    ch() {
    # Check if we are already in a ch shell
    if [[ "${__ch_load_history:-0}" == "1" ]]; then
    echo "ch: Already in a ch shell" 1>&2
    return 0
    fi

    local dir
    dir=$(realpath "${1:-.}")

    local history_file
    if ! history_file="$(ch_hist_file "$dir")"; then
    return 1
    fi

    echo "ch: Loading history file $history_file" 1>&2

    # Make directory if it does not exist
    mkdir -p "$(dirname "$history_file")"
    # Create the history file if it does not exist
    touch "$history_file"
    # Set the history file for the new shell
    export HISTFILE="$history_file"
    # Set the history size for the new shell
    export HISTSIZE=${HISTSIZE:-1000}
    export HISTFILESIZE=${HISTFILESIZE:-2000}

    # Open a new shell with the history file set to the current directory
    # Use the --rcfile option to set the history file for the new shell.
    exec bash --rcfile <(
    echo ". ~/.bashrc"
    echo "export HISTFILE='$history_file'"
    echo "export HISTSIZE=$HISTSIZE"
    echo "export HISTFILESIZE=$HISTFILESIZE"
    echo "export __ch_load_history=1"
    echo "builtin cd \"$dir\""
    )
    }

    # ch_autoload is a helper function to check if the history file exists and run `ch` if it does.
    ch_autoload() {
    local history_file
    if history_file="$(ch_hist_file)" && [[ -f "$history_file" ]]; then
    ch .
    fi
    }

    # auto_ch is a wrapper function for the builtin cd command that autoloads the history file. Intended to be used as an alias for cd.
    auto_ch() {
    # Run the builtin cd command first
    builtin cd "$@" || return $?
    # Autoload the history file if it exists
    ch_autoload
    }

    alias cd=auto_ch