Long story short: set
can see shell-local variables, env
cannot.
Shells can have variables of 2 types: locals, which are only accessible from the current shell, and (exported) environment variables, which are passed on to every executed program.
Since set
is a built-in shell command, it also sees shell-local variables (including shell functions). env
on the other hand is an independent executable; it only sees the variables that the shell passes to it, or environment variables.
When you type a line like a=1
then a local variable is created (unless it already existed in the environment). Environment variables are created with export a=1