From 296fbb8b6955390f5784ceb5f02ece2b975bf462 Mon Sep 17 00:00:00 2001 From: Robby Russell Date: Sat, 5 Sep 2026 16:54:31 -0700 Subject: [PATCH] fix(installer): back up the history file when replacing .zshrc The .zshrc the installer moves aside is where the user's SAVEHIST lives. Once it is gone zsh falls back to a smaller value, lib/history.zsh raises that to 10000, and the next clean shell exit rewrites $HISTFILE with only the most recent 10000 entries. Anything older is gone, and unlike the .zshrc, the history file was never backed up. Copy the history alongside .zshrc.pre-oh-my-zsh at the moment the config is replaced, and say so in the overwrite prompt. $HISTFILE is a zsh variable the installer cannot read, so cover both locations it is commonly given: macOS /etc/zshrc sets ${ZDOTDIR:-$HOME}/.zsh_history, and lib/history.zsh falls back to $HOME/.zsh_history. This does not stop the trim itself, which is governed by SAVEHIST; it makes the lost history recoverable. Closes #10908 Co-Authored-By: Claude Opus 5 (1M context) --- tools/install.sh | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tools/install.sh b/tools/install.sh index 83ff0cab0..bdfb5c3b0 100755 --- a/tools/install.sh +++ b/tools/install.sh @@ -370,6 +370,7 @@ setup_zshrc() { # Ask user for confirmation before backing up and overwriting echo "${FMT_YELLOW}Found ${zdot}/.zshrc." echo "The existing .zshrc will be backed up to .zshrc.pre-oh-my-zsh if overwritten." + echo "Your command history will be backed up too, since replacing .zshrc drops any SAVEHIST you had set." echo "Make sure your .zshrc contains the following minimal configuration if you choose not to overwrite it:${FMT_RESET}" echo "----------------------------------------" cat "$ZSH/templates/minimal.zshrc" @@ -398,6 +399,34 @@ setup_zshrc() { fi echo "${FMT_GREEN}Backing up to ${OLD_ZSHRC}${FMT_RESET}" mv "$zdot/.zshrc" "$OLD_ZSHRC" + + # The .zshrc we just moved aside is where the user's SAVEHIST lived. Without + # it zsh trims $HISTFILE the next time a shell exits, so copy the history + # while it is still intact. $HISTFILE is a zsh variable we cannot read from + # here, so cover both locations it is commonly given: /etc/zshrc on macOS + # sets ${ZDOTDIR:-$HOME}/.zsh_history, and lib/history.zsh falls back to + # $HOME/.zsh_history. + hist_backed_up="" + for hist in "$zdot/.zsh_history" "$HOME/.zsh_history"; do + if [ ! -f "$hist" ]; then + continue + fi + case " $hist_backed_up " in + *" $hist "*) continue ;; + esac + hist_backup="${hist}.pre-oh-my-zsh" + if [ -e "$hist_backup" ]; then + hist_backup="${hist_backup}-$(date +%Y-%m-%d_%H-%M-%S)" + fi + if cp "$hist" "$hist_backup"; then + echo "${FMT_GREEN}Backing up your command history to ${hist_backup}${FMT_RESET}" + hist_backed_up="$hist_backed_up $hist" + else + # a half-written file would look like a usable backup + rm -f "$hist_backup" + fmt_error "could not back up $hist" + fi + done fi echo "${FMT_GREEN}Using the Oh My Zsh template file and adding it to $zdot/.zshrc.${FMT_RESET}"