Fix checkout corner cases, index handling, and reset hard behavior

This is actually a fairly significant reorganization of checkout internals.

1. Make it possible to checkout based on any pair of baseline and target iterators instead of tied to a pre-loaded index, and
2. Drive checkout off of the diff of baseline to target instead of the diff between target to working directory, and
3. Map correct behavior much more completely to get corner cases, and
4. Add more general notification callbacks for things such as dirty files in the working directory besides just conflicts, and
5. Update the index selectively as files are updated.

With these changes a more complete emulation of core git checkout is possible, plus this uses the updated checkout to implement the correct behavior for reset hard (e.g. deleting files that have been added to the index even if they are not yet committed).

There are still a few corner cases where this updated version is incorrect (particularly relating to a typechange from a submodule to a regular tree), but this is much closer. Unfortunately, in getting the various small details worked out at the end, this grew substantially uglier than I hoped. I have an idea for a somewhat different approach that I think will be cleaner, but I'd like to get these improvements merged before going too much further off the deep end.