Compare commits

...
Author SHA1 Message Date
copilot-swe-agent[bot]androbbyrussell ed01423b18 refactor(installer): reuse timestamp for backup naming loop
Co-authored-by: robbyrussell <257+robbyrussell@users.noreply.github.com>
2026-09-06 00:15:20 +00:00
copilot-swe-agent[bot]androbbyrussell bc6faea85b fix(installer): avoid history backup name collisions
Co-authored-by: robbyrussell <257+robbyrussell@users.noreply.github.com>
2026-09-06 00:15:00 +00:00
copilot-swe-agent[bot]androbbyrussell ce6ebd3d8d fix(installer): preserve history backup permissions
Co-authored-by: robbyrussell <257+robbyrussell@users.noreply.github.com>
2026-09-06 00:14:31 +00:00
copilot-swe-agent[bot]androbbyrussell 6749d0825b fix(installer): fail safely on history backup errors
Co-authored-by: robbyrussell <257+robbyrussell@users.noreply.github.com>
2026-09-06 00:14:09 +00:00
Robby RussellandClaude Opus 5 296fbb8b69 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) <noreply@anthropic.com>
2026-09-05 17:03:47 -07:00
+39
View File
@@ -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,44 @@ 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_base="${hist}.pre-oh-my-zsh"
hist_backup="$hist_backup_base"
if [ -e "$hist_backup" ]; then
hist_backup_ts="$(date +%Y-%m-%d_%H-%M-%S)"
hist_backup_i=0
while [ -e "$hist_backup" ]; do
hist_backup_i=$((hist_backup_i + 1))
hist_backup="${hist_backup_base}-${hist_backup_ts}-${hist_backup_i}"
done
fi
if cp -p "$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"
if ! mv "$OLD_ZSHRC" "$zdot/.zshrc"; then
fmt_error "could not restore $zdot/.zshrc from backup"
fi
exit 1
fi
done
fi
echo "${FMT_GREEN}Using the Oh My Zsh template file and adding it to $zdot/.zshrc.${FMT_RESET}"