Storing the AST works for a class of problems, namely whitespace issues, but a refactoring as simple as renaming a token still makes merges a mess. (And if you store a whitespace / comment decorated AST, you can still have a messy merge.)
That said, you could address that and other issues, you're just working with something several steps removed from an AST. Or you could call an AST the 90% solution.
And how do you decide, given two versions of a source file, if the token was renamed or it was a new one?
This looks "trivial" for trivial cases, but I can imagine lots of difficult corner cases there. Depending on how you define what constitutes a "rename", this may even be undecidable.
That said, you could address that and other issues, you're just working with something several steps removed from an AST. Or you could call an AST the 90% solution.