The essentials are already given in the other answers. Technically, the shell stores the location of a command in a hash table. In
bash you can view this table by the command
You can also modify this hash table, for details I quote the
bash man page:
hash [-lr] [-p filename] [-dt] [name]
For each name, the full file name of the command is determined by searching the directories in $PATH and remembered. If
the -p option is supplied, no path search is performed, and filename is used as the full file name of the command.
-r option causes the shell to forget all remembered locations. The -d option causes the shell to forget the remembered
location of each name. If the -t option is supplied, the full pathname to which each name corresponds is printed. If
multiple name arguments are supplied with -t, the name is printed before the hashed full pathname. The -l option causes
output to be displayed in a format that may be reused as input. If no arguments are given, or if only -l is supplied,
information about remembered commands is printed. The return status is true unless a name is not found or an invalid
option is supplied. Here you can see, which commands you already executed in this session.
Other shells can behave differently, in
zsh (and I think this was adapted from
csh) the shell gathers all command at startup or by invoking
rehash. Then you get a complete list of all available commands with
hash and you can search e.g. for all variants of
zsh$ hash | grep diff
man zshbuiltins for much more details.