find() is for retrieving objects from the database - always generates SQL and loads into memory an object initialized according to the active fetch strategy. If you have newly created objects in a persistent context but have not called flush() or committed the transaction, find() will not find them and will return NULL (even if you have called persist()).
merge() is for retrieving a persistent version of a detached or transient object. If not found in the persistent context caches, an SQL statement is issued to retrieve the object from the database, and dirty checking is done to merge the objects. Because it uses non-NULL properties of the detached or transient object to overwrite the retrieved object, you want to be careful about how you use attribute defaults. So watch out when working with transient objects.
getReference() returns a proxy with only the identifier initialized, and does not hit the database. If you are not working directly on an object (such as when it is used only as a reference in queries or other objects), you want to use this strategy. Rule of thumb: if you have entity references in an object, this is likely how you refer to them. Note that the proxy has all other properties set to NULL. To fully initialize the proxies, you'd need to find() or merge().