How to choose between hooking into per_get_posts or into parse_query

I’m looking real hard at the code around both hooks, and they run one right after the other, with the same arguments, and I just can’t see any meaningful difference.

Theoretically only parse_query would run, and not pre_get_posts, if WP_Query::parse_query() were to be run directly on its own, but WordPress itself never does that. Maybe some plugins do, but I don’t know why they would. Near as I can tell there’s no technical reason to use one over the other, but pre_get_posts is newer, much more widely used, and much better documented, officially and by third parties. I suspect parse_query is somewhat vestigial.

I’d suggest using pre_get_posts. Any code you see using parse_query should work as-is with pre_get_posts.