First, let’s remember some properties of XOR (exclusive-OR):
- A A = 0
- neutral element: A 0 = A
- commutative: A B = B A
- associative: (A B) C = A (B C)
The following is a retracted explanation from here:
The key to convince yourself that this works is to track the original values of x and y. Let A be the original value of x (that is, the value that x has before executing these three lines of code). Similarly, let B be the original value of y.
We can comment on each line of code to see what’s going on.
// x == A, y == B
x = x ^ y ;  
 // x == A ^ B, y == B
y = x ^ y ;  
 // x == A ^ B
 // y == (A ^ B) ^ B == A ^ (B ^ B)  (por associatividade)
 //   == A ^ 0  (devido à propriedade z ^ z == 0)
 //   == A      (devido à propriedade z ^ 0 == z)
x = x ^ y ;
 // x == ( A ^ B ) ^ A
 //   == ( A ^ A ) ^ B  (por associatividade/comutatividade)
 //   == 0 ^ B            (devido à propriedade z ^ z == 0)
 //   == B                (devido À propriedade z ^ 0 == z)
 // y == A
After the second statement executed, y = A. After the third statement, x = B.