Imagine you have installed packages A-1.deb and B-1.deb
A-1.deb depends on packages Adep1-1.deb and Adep2-1.deb while B-1.deb depends on package Bdep1-1.deb:

A-1.deb
|
`—– Adep1-1.deb
`—– Adep2-1.deb

B-1.deb
|
`—— Bdep1-1.deb

Now, there is a new package available for program A, namely A-2.deb. A-2.deb still depends on Adep1-1.deb but now it also depends on a new version of Adep2, namely Adep2-2.deb:

A-2.deb
|
`—– Adep1-1.deb
`—– Adep2-2.deb

There is also a new package for program B, namely B-2.deb, and there is also a new version of B-2’s dependency, namely Bdep1-2.deb. But contrary to the already installed version of B, B-1.deb, B-2.deb also depends on a new package: Bdep-new-1.deb

B-2.deb
|
`—— Bdep1-2.deb
`—— Bdep-new-1.deb

If you now execute an apt-get upgrade you would see something like this:

# apt-get upgrade
Reading Package Lists... Done
Building Dependency Tree... Done
The following packages have been kept back
B
The following packages will be upgraded
A Adep1 Adep2
3 packages upgraded, 0 newly installed, 0 to remove and 1 not upgraded.
Need to get 5055B/5055kB of archives. After unpacking 1161kB will be used.
Do you want to continue? [Y/n]

As you can see the package B is kept back. The reason is that in order to install the new version of B, B-2.deb, a new package must be installed, Bdep-new-1.deb, but apt-get upgrade doesn’t install new packages, it only upgrades already installed packages.

On the other hand, apt-get dist-upgrade will also install new packages in order to resolve dependencies. So with a dist-upgrade you would get something like this:

# apt-get dist-upgrade
Reading Package Lists... Done
Building Dependency Tree... Done
Calculating Upgrade... Done
The following NEW packages will be installed:
Bdep-new
The following packages will be upgraded
A Adep1 Adep2 B Bdep1
5 packages upgraded, 1 newly installed, 0 to remove and 0 not upgraded.
Need to get 7055B/7055kB of archives. After unpacking 1161kB will be used.
Do you want to continue? [Y/n]

In general, if you do an apt-get upgrade and a package is kept back:
“This means that there are new versions of these packages which will not be installed for some reason. Possible reasons are broken dependencies (a package on which it depends doesn’t have a version available for download) or [like in my example] new dependencies (the package has come to depend on new packages since the last version). ” [APT HOWTO
Chapter 3 – Managing packages, section 3.4 Upgrading packages]