Use config snapshotting

This way we can assume we have a consistent view of the config situation
when we're looking up remote, branch, pack-objects, etc.
config: make refresh atomic

Current code sets the active map to a new one and builds it whilst it's
active. This is a race condition with someone else trying to access the
same config.

Instead, let's build up our new map and swap the active and new one.
config: split out the refresh step

This will be used by the writing commands in a later step.
config: use a snapshot for the iterator