The easy, short answer is that “GET” has all the information right in the query string, whereas “POST” may have some of the information in the data. This has a number of interesting consequences: The data in “GET” is clearly visible (it appears in the address bar) and so it is easily hacked. (Although for HTTPS connections everything beyond the hostname is encrypted). On the other hand the data in a “POST” is delivered in a separate package so there can be a routing problem.
“GET” is more nearly idempotent – i.e., multiple instances of a particular “GET” will be pretty much the same as one instance. So, for example, if a user clicks a button – and then clicks it again because they’re not sure it took, if the query is idempotent this will not matter. BUT, look at the case of submitting a payment: if the user clicks twice it will mean they pay twice, so that’s a classic case of NOT being idempotent.
So it IS possible to have a “POST” be idempotent, since it’s a property of what the action is on the server, not the nature of the query. But, since the “POST” is actually in 2 (or more) parts it would be more usual for idempotent queries to be “GET”s.
Other consequences: There’s a limit on how much data can be in a “GET”, and it must all be ASCII (although with “escaping” that can be pretty general if necessary). Also it’s hard to do “hidden” fields. A “GET” is much easier to hack. But it is cacheable, and in one piece so it can be much faster.