How to delete a secret from fish shell history on Mac
You typed set -x GITHUB_TOKEN ghp_… or pasted a curl -H "Authorization: Bearer sk-…" into fish, and now the full token sits in your history, one up-arrow away and in plain text on disk. fish does not use .zsh_history or HISTFILE, so the zsh and bash recipes do not apply. Its history lives in its own file, in its own format, and fish has a built-in command to delete entries from it.
First, rotate the key if it went anywhere else. Deleting it from history protects the copy on your Mac. If the command also reached a shared terminal recording, a screen share or a log, revoke the key at the provider: see what to do when you leak an API key.
1. Find where fish keeps history
By default, fish writes history to ~/.local/share/fish/fish_history (or $XDG_DATA_HOME/fish/fish_history if you set that variable). Each entry is a small YAML-like block:
- cmd: set -x GITHUB_TOKEN ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
when: 1791173800
If you set fish_history to another session name, the file is ~/.local/share/fish/NAME_history instead. ls ~/.local/share/fish/ shows which ones exist.
2. Find the entry without typing the secret again
Search by something that identifies the command, such as the variable name or the token prefix (ghp_, AKIA, sk-, xoxb-), not by the full value. Whatever you type is itself saved as a new history entry, so searching for the whole token creates another copy. Starting the line with a space keeps it out of history (see step 6).
history search --contains GITHUB_TOKEN
Or look at the file directly, with line numbers:
grep -n 'ghp_' ~/.local/share/fish/fish_history
3. Delete it with history delete
Run history delete with a search string. With no other flag it matches entries that contain the string, lists them and asks which ones to remove:
history delete --contains GITHUB_TOKEN
[1] set -x GITHUB_TOKEN ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Enter nothing to cancel the delete, or
Enter one or more of the entry IDs or ranges like '5..12', separated by a space.
For example '7 10..15 35 788..812'.
Enter 'all' to delete all the matching entries.
Type an ID such as 1, a range, or all, and press Return. fish removes the entries and saves the history file immediately; you do not need to run history save. Pressing Return on its own cancels.
To delete one exact command without the prompt, for example in a script, pass the whole command line. The builtin needs both flags; --exact on its own fails with builtin history delete --exact requires --case-sensitive:
history delete --exact --case-sensitive 'set -x GITHUB_TOKEN ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
Then confirm it is gone from the file:
grep -c 'ghp_' ~/.local/share/fish/fish_history
Why not sed? You can edit the file by hand, but each entry spans several lines (- cmd:, when:, sometimes paths:), so a one-line sed '/ghp_/d' leaves the rest of the entry behind, and you have to remember that BSD sed on macOS needs -i ''. history delete rewrites the file in fish’s own format. In our test on fish 4.0, another fish session that saved its own history after the delete did not write the deleted entry back. Windows that were already open can still offer it on up-arrow from memory, so close them once you are done.
4. Check fish_variables for set -U
If you ever stored the key as a universal variable, with set -U or set -Ux, fish saved the value in plain text in ~/.config/fish/fish_variables, as a line like SETUVAR GITHUB_TOKEN:ghp_…. It survives restarts and is copied by anything that syncs or backs up your dotfiles. Check for it and erase it the fish way:
grep -n 'GITHUB_TOKEN' ~/.config/fish/fish_variables
set -Ue GITHUB_TOKEN
Also look for a hard-coded set -gx line in ~/.config/fish/config.fish or ~/.config/fish/conf.d/, especially if your fish config lives in a public dotfiles repository.
5. Backups still have the old file
Time Machine and any dotfile sync keep earlier copies of fish_history. Deleting the entry does not reach those. That is the main reason rotating a real key beats cleaning up after it.
6. Keep the next one out of history
- Start the command with a space. fish does not store a command line that begins with a space. It stays available for up-arrow until you run the next command and is never written to disk.
- Use private mode for a session.
fish --private(orfish -P) starts a shell that neither reads old history nor writes new history. In a shell that is already open,set fish_private_mode 1stops it writing history to disk. - Type the secret into read instead of the command line.
read -sgx GITHUB_TOKENprompts for the value without echoing it and exports it as a global variable. Only thereadcommand goes into history, not what you typed. - Undo a whole session.
history clear-sessionremoves everything the current session has added to the history file.