You could add puppet to a cron job as normal (which allows you the option to only run it during working hours or more or less frequently than every half hour) but wrap it in a short script that checks whether the revision number of your source control has been incremented. If so, it fires off the puppet client, if not then there's no need for puppet (and all of the expensive hashing of files it does).
This would mean, however, that if you changed a file on a host puppet would not change it back until the next configuration change. You could avoid this problem by changing the logic of the wrapper script to also run a puppet client if it has been more than 24 hours since the last run.
The "masterless" puppet idea (that ewwhite mentioned) removes the puppet master as being the bottleneck and replaces it with git being the bottleneck, which is vastly preferable in my opinion. Unless you make changes to git quicker than it can push those changes out to all the hosts, this bottleneck won't be a problem. You could arrange the "spokes" in a tree fashion if it ever did become a problem. That should scale to tens of thousands of hosts.