cdhist is a utility which
provides a Linux shell cd history directory stack. A shell cd
wrapper function calls cdhist to intercept your typed cd
command and
maintain an ordered stack of all directories you have previously visited
which can be listed and quickly navigated to.
cdhist can also be used with the
Command Line Fuzzy Finder fzf
to
fuzzy search and select on previously visited directories, and can be
used to easily cd
between git worktree
directories. See the sections below about FZF
Integration and Git Worktree
Integration.
The latest version and documentation is available at https://github.com/bulletmark/cdhist.
Use the cd
command to change directory as normal:
$ cd /tmp
$ cd /etc
$ cd /usr/share/doc
$ cd /boot/loader
$ cd ~/etc
$ cd
At any point you can use the cd --
command to list all your previously
visited directories and be prompted for one to select and cd
to:
$ cd --
6 ...
5 /tmp
4 /etc
3 /usr/share/doc
2 /boot/loader
1 ~/etc
0 ~
Select index [or <enter> to quit]: 3
$ pwd
/usr/share/doc
That's it! The above is all you really need to know. Instead of having to type the directory name you merely enter it's index. The directories are displayed most recently visited last, without duplicates. Index 0 is the current directory, index 1 is the previous, index 2 is the second previous, up to a user configurable number (default 50). Other available commands and options are:
List the current stack and its indices (without prompting):
$ cd -l
Change immediately to directory corresponding to stack index 4:
$ cd -4
Search back through stack for directory containing "string" and cd
there:
$ cd -/string
Note, you can also type string
at the cd --
prompt to search.
Show help/usage:
$ cd -h
Arch users can install cdhist from the AUR and skip to the next section.
Python 3.8 or later is required. Note cdhist is on
PyPI so just ensure that
pipx
is installed then type the
following:
$ pipx install cdhist
To upgrade:
$ pipx upgrade cdhist
A user who wants to use the cdhist facility should add the following
lines to their ~/.bashrc
or ~/.zshrc
file (after where your PATH is
set up so that the command cdhist
can be found). This creates the cd
wrapper command in your interactive shell session as a tiny function.
Note you can customize the command name if
you want.
if type cdhist &>/dev/null; then
. <(cdhist -i)
fi
Then log out and back in again.
The popular Command Line Fuzzy Finder
fzf
can easily be integrated with cdhist to provide fuzzy search
navigation over your directory history. Set the following in your
environment to have fzf
search the directories recorded by cdhist:
export FZF_ALT_C_COMMAND="cat $HOME/.cd_history"
You also should make a small change to the way you source the fzf
key-bindings and completions into your shell to ensure that the cd
command is not aliased to builtin cd
and instead invokes the cdhist
command.
E.g. for bash
, in your ~/.bashrc
, instead of eval "$(fzf --bash)"
as suggested by the fzf
documentation,
use:
eval "$(fzf --bash | sed 's/builtin cd/cd/g')"
E.g. for zsh
, in your ~/.zshrc
, instead of source <(fzf --zsh)
as suggested by the fzf
documentation,
use:
source <(fzf --zsh | sed 's/builtin cd/cd/g')
After doing this (and reloading your shell session), you can use the
fzf
key binding <ALT+C>
to have fzf
list all your previous
directories and fuzzy match on them for selection as you type. fzf
can
also provide fancy directory
previews
using tree
, etc. Of course the cdhist native command cd --
and
other cdhist commands described above are still available, in addition
to the fzf
key binding.
If you prefer that directories that do not exist are excluded from fzf
and your cd
history (i.e. exclude directories that have been deleted
since they were last visited), then you can define the fzf
command as:
export FZF_ALT_C_COMMAND="cdhist -p && cat $HOME/.cd_history"
An alternative is to always exclude non-existent directories from your
cd history by setting the --prune-always
as a default
option.
Some people may prefer not to alias their system cd
command to this
utility and just use an alternative unique command name. To do this,
simply add your desired command name as an extra argument to the
cdhist
command in your shell initialization code. E.g, to use the
command name xd
rather than cd
, use the following in
your ~/.bashrc
or ~/.zshrc
file:
if type cdhist &>/dev/null; then
. <(cdhist -i xd)
fi
Then log out/in, and then just type xd /tmp
to change dir, xd --
to see
and select directories, etc.
cdhist can be used to easily cd
between git worktree
directories. You use the cd -g
command to list all your worktrees and
be prompted for one to select, and then you will be switched to the
associated directory, and it will be added to your cd
history.
# Current directory:
$ pwd
/home/mark/src/myprog
# List worktrees using standard git command:
$ git worktree list
/home/mark/src/myprog f76b8e0 [main]
/home/mark/src/development 9796714 [development]
/home/mark/src/milestone1 bc921b8 [milestone1]
/home/mark/src/test e6d965a [test]
# Alternately, use cdhist to list worktrees and choose one to navigate to:
$ cd -g
3 ~/src/development 9796714 [development]
2 ~/src/milestone1 bc921b8 [milestone1]
1 ~/src/test e6d965a [test]
0 ~/src/myprog f76b8e0 [main]
Select index [or <enter> to quit]: 2
$ pwd
/home/mark/src/milestone1
# Or, use cdhist to navigate to worktree dir for given branch name or
# commit:
$ cd -g main
$ pwd
/home/mark/src/myprog
Instead of having to type the full git repository directory name you
merely are prompted with a list and enter it's index. Or just directly
enter the branch name (or commit hash). The directories are displayed in
the same order as the output of the git worktree list
command, except
that the git directory corresponding to the current working directory is
shown first (index 0) consistent with how the current directory is shown
at index 0 for normal cd history and thus conveniently showing you which
git worktree you are currently in which git worktree list
unfortunately does not show.
In you enter text instead of an index, you only need to enter as much of
the branch name, or commit hash, as needed to be unique. Note that cd -g
nicely presents paths based from your HOME directory with a tilde
(~
) unlike the longer full path displayed by git worktree list
(although you can change that with the -u/--no-user
option, likely set
as a default option).
The git worktree list
command displays absolute directory paths, and
cdhist does also by default, but many users prefer them displayed
as relative paths. The Git worktree command does not provide this but
you can enable it in cdhist by adding the -r/--relative
option, e.g:
$ cd -gr
3 ../development 9796714 [development]
2 ../milestone1 bc921b8 [milestone1]
1 ../test e6d965a [test]
0 . f76b8e0 [main]
Select index [or <enter> to quit]:
Most likely you will want to set this as your default so do that by
adding --relative
as a default option.
Some users may want the git worktree functionality provided by cdhist
but are not interested in the standard cd
history functionality, or
alternately, want to use a completely separate command for the git
worktree functionality. To do this, simply add your desired command name
and the git option as an extra argument to the cdhist
command in your
shell initialization code. E.g, to use the command name wt
for git
worktree functionality (only), add the following in your
~/.bashrc
or ~/.zshrc
file:
if type cdhist &>/dev/null; then
. <(cdhist -i "wt -g")
fi
Then log out/in, and then just type wt
to list the git worktrees and
be prompted to select the directory etc. Of course, you can define this
wt
command in parallel to using cdhist for your cd
command if
you want.
There are 2 alternatives to set default cdhist options:
- Set options in startup configuration file.
- Set options in shell initialization code.
It's largely personal preference which you choose.
Note if you set -r/--git-relative
or -u/--no-user
options as default
then options -R/--no-git-relative
and -U/--user
exist to
allow you to temporarily override those defaults.
You can add default options to a personal configuration file
~/.config/cdhist-flags.conf
. If that file exists then each line in
the file will be concatenated and automatically prepended to your command
line options. The following options are sensible candidates to set as
default options: --purge-always
, --git-relative
, --no-user
,
--size
. Comments on any line are excluded.
You are best to use the full/long name for options and to add them on individual lines in the file so they are easy to read and easy to comment out temporarily etc.
Alternately, just set your preferred default options in your shell initialization code, e.g:
if type cdhist &>/dev/null; then
. <(cdhist -i "cd -arm 200")
fi
The above sets -a (--purge-always)
, -r (--git-relative)
, and
-m (--size) 200
options as defaults for your cd
command. Best to use
the short option names to keep the imported shell function definition
concise.
An advantage of this 2nd approach to setting default options is that you
can create one alias for your cd
command, and another alias for your
git worktree command (e.g. wt
), and both can have different cdhist
options.
Type cdhist -h
to view the usage summary:
usage: cdhist [-i] [-h] [-p] [-a] [-g] [-r] [-R] [-u] [-U] [-l] [-m SIZE]
[-n NUM_LINES] [-L] [-P] [-V]
[directory]
A Linux shell directory stack "cd history" function.
positional arguments:
directory directory (or branch for git worktree) to cd to, or
"--" to list history and prompt, or "-n" for n'th
entry in list or "-/<string>" to match for "string" in
dir
options:
-i, --init output shell initialization code. Optionally specify
alternative command name as argument, default="cd"
-h, --help show help/usage
-p, --purge just purge non-existent directories from history
-a, --purge-always always purge non-existent directories every write
-g, --git show git worktree directories instead
-r, --git-relative show relative git worktree paths instead of absolute
-R, --no-git-relative
do not show relative git worktree paths (default)
-u, --no-user do not substitute "~" for home directory
-U, --user do substitute "~" for home directory (default)
-l, --list just list directory history
-m SIZE, --size SIZE maximum size of directory history (default=50)
-n NUM_LINES, --num-lines NUM_LINES
limit output to specified number of lines
-L, --follow-links follow symbolic links (default=true)
-P, --follow-physical
follow links to physical directory
-V, --version just output cdhist version
Note you can set default options in ~/.config/cdhist-flags.conf.
Regular cd
, e.g. as provided by the bash builtin, offers some esoteric
command line options such as -e
and -@
, and shell options such as
autocd
, cdspell
, cdable_vars
. These rarely used options are not
supported by cdhist.
Version 3.0 changes and new features:
-
Added function to
cd
betweengit worktrees
. Can configure this as separate command if preferred, with option to display relative paths. -
Cleaner installation using
-i
option so no need for separatecdhist.rc
file and can set arguments when installing to customise command name + options etc. -
Added
-L
/-P
standardcd
options. -
Added
-a/--purge-always
option to always prune history. -
Add
-n/--num-lines
to limit number of lines in output (for-l/--list
and--
commands). -
Added ability to set default options in
~/.config/cdhist-flags.conf
. -
Parses options/arguments using standard Python argparse.
-
Let setuptools build the main program stub rather than install our own.
-
Min Python version up from 3.4 to 3.7.
-
Now installed as a Python package (directory) rather than a module (single file).
-
Some of these changes slow the program down but architecture is changed so the program is run once only, not twice as it ran before. Second run was to save the new directory after
cd
had validated it, but now we validate it ourself before passing tocd
. So net performance is quicker than previous version, at least for the vanilla case of changing directory. This is not noticeable on normal PC's but is on constrained platforms like Raspberry Pi 2/3 using SD card. -
If you were previously setting
CDHISTSIZE
orCDHISTTILDE
settings via environment variables then you now need to set them using--size
and--no-user
in~/.config/cdhist-flags.conf
, or add those options in your shell initialization code. -
The
-s
option to return acdhist.rc
file name for initialisation is still currently supported for backwards-compatibility but is undocumented and depreciated (a temporary file is created and returned). It will likely eventually be removed.
Copyright (C) 2010 Mark Blakeney. This program is distributed under the terms of the GNU General Public License. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License at https://www.gnu.org/licenses/ for more details.