Hashing + custom server merge is the main logical device, the rest is just encoding tricks to make everything fast.
Push becomes like git push to a tmp branch, then you do a server-side merge, then a pull on remaining clients. Push/pull is fast just like git, and due to content hashing, there are never any problems overwriting another device's work on the server.
I think I had some clever tricks with text syncing (IIRC I implemented a Merkle tree-inspired approach), but that's the general concept.
(I don't remember anything else, it was so long ago. :-)
Push becomes like git push to a tmp branch, then you do a server-side merge, then a pull on remaining clients. Push/pull is fast just like git, and due to content hashing, there are never any problems overwriting another device's work on the server.
I think I had some clever tricks with text syncing (IIRC I implemented a Merkle tree-inspired approach), but that's the general concept.
(I don't remember anything else, it was so long ago. :-)