The SSH protocol creates a secure tunnel through which you can transfer a bidirectional stream, and you can use that stream to connect any two processes you like.
The most familiar two processes would be a shell (at the server) and an interactive terminal emulator (at the client). That's what you're using when you ssh to a server and type commands at the remote shell's prompt.
SCP is file transfer done using only that shell and a remote command. In SCP, once the client is connected to the server, and all the authentication and authorization has been done, the client sends the remote shell a command like
scp -f myfile.txt, which just writes the contents of the file myfile.txt to the stream (for the client to read) or
scp -t myfile.txt which reads from the stream and writes to myfile.txt.
You'll notice that -f and -t (for "from" and "to") are not in the scp manpages. They are considered internal. There is a lightweight acknowledgement scheme, and a scheme for transferring directories by wrapping the file contents in simple headers. But for the most part SCP is a basic matter of writing the bytes of the file onto the SSH tunnel, letting SSH deal with complicated stuff like compression and integrity.
SFTP is a much more complex file transfer protocol, which again is tunnelled through SSH.
In SFTP both requests and responses are binary-encoded packets with names like "SSH_FXP_OPEN", "SSH_FXP_STAT", "SSH_FXP_READ", "SSH_FXP_DATA", "SSH_FXP_CLOSE".
One interesting feature of the protocol is that commands can be pipelined, and responses may come in any order. This can mean that sessions spend less time waiting on responses, and there are opportunities to optimise concurrent transfers from one server with data-sources of various speeds -- although I don't know to what extent those opportunities have been taken.
SFTP has commands to do many things that SCP doesn't address; like delete, rename, truncate, move, etc.
All the details are available in an IETF Draft.
It's worth noting that newer SSH packages replace the user
scp binary with a symlink to the SFTP binary. This SFTP has the look and feel of scp, but under the covers it's using the SFTP protocol.
Citation -- O'Reilly SSH: The Secure Shell, The Definitive Guide, section 5.7 "Subsystems":
WARNING: Don't remove the subsystem-sftp line from sshd2_config: it is required for scp2 and sftp to work. Internally, both programs run ssh2 -s sftp to perform file transfers.
Fish is an interesting piece of history. Let's say you want to transfer files over SSH, but your remote system doesn't have SCP. Or perhaps you want to do more sophisticated file operations than SCP, but your remote system doesn't have SFTP. Neither of those scenarios are likely today, but when Fish was invented, they were.
So the developers of the client Midnight Commander set about creating their own solution. It's similar to scp in principle, but there are more commands. The client sends commands that look like:
ls -l /some/name | ( read a b c d x e; echo $x ); echo '### 100'; cat /some/name; echo '### 200'
If you're talking to a Fish server, then it will interpret the
#RETR command. However if the remote server doesn't have a Fish server installed, the commands will be interpreted by the shell. First a comment, then a command which prints info about the file, followed by the file contents surrounded in some markers.
Effectively, in the absence of scp or fish, the client has "rolled its own" scp equivalent - but it can equally send shell commands to rename, move, truncate, etc.
Details of Fish are in the Midnight Commander source here.
What does this all mean from an end-user perspective?
- older SSH server implementations support scp but not SFTP; you can't use an SFTP client with these
- Use SFTP for performance, reliability and flexibility
- Your "scp" client might be an SFTP client in disguise (Citation needed)
- Fish might be useful in niche circumstances, but otherwise use the more standard SFTP.