How do I understand the Hindley-Milner rules?
Hindley-Milner is a set of rules in the form of sequent calculus (not natural deduction) that demonstrates that we can deduce the (most general) type of a program from the construction of the program without explicit type declarations.
The symbols and notation
First, let's explain the symbols, and discuss operator precedence
-  is an identifier (informally, a variable name). 
- : means is a type of (informally, an instance of, or "is-a"). 
-  (sigma) is an expression that is either a variable or function. 
- thus : is read " is-a " 
- ∈ means "is an element of" 
-  (Gamma) is an environment. 
- ⊦ (the assertion sign) means asserts (or proves, but contextually "asserts" reads better.) 
-  ⊦  :  is thus read " asserts that , is-a " 
-  is an actual instance (element) of type . 
-  (tau) is a type: either basic, variable (), functional →', or product ×' (product is not used here) 
- →' is a functional type where   and ' are potentially different types. 
- . means  (lambda) is an anonymous function that takes an argument, , and returns an expression, . 
- let  = ₀ in ₁ means in expression, ₁, substitute ₀ wherever  appears. 
- ⊑ means the prior element is a subtype (informally - subclass) of the latter element. 
-  is a type variable. 
- ∀ . is a type, ∀ (for all) argument variables, , returning  expression 
- ∉ free() means not an element of the free type variables of  defined in the outer context. (Bound variables are substitutable.) 
Everything above the line is the premise, everything below is the conclusion (Per Martin-Löf)
Precedence, by example
I have taken some of the more complex examples from the rules and inserted redundant parentheses that show precedence:
-  :  ∈  could be written ( : ) ∈  
-  ⊦  :  could be written  ⊦ ( : ) 
-  ⊦ let  = ₀ in ₁ : 
is equivalently
 ⊦ ((let ( = ₀) in ₁) : ) 
-  ⊦ . : →' is equivalently  ⊦ ((.) : (→')) 
Then, large spaces separating assertion statements and other preconditions indicates a set of such preconditions, and finally the horizontal line separating premise from conclusion brings up the end of the precedence order.
The Rules
What follows here are English interpretations of the rules, each followed by a loose restatement and an explanation.
Variable

Given  is a type of  (sigma), an element of  (Gamma),
conclude  asserts  is a .
Put another way, in , we know  is of type  because  is of type  in .
This is basically a tautology. An identifier name is a variable or a function.
Function Application

Given  asserts ₀ is a functional type and  asserts ₁ is a 
conclude  asserts applying function ₀ to ₁ is a type '
To restate the rule, we know that function application returns type ' because the function has type →' and gets an argument of type .
This means that if we know that a function returns a type, and we apply it to an argument, the result will be an instance of the type we know it returns.
Function Abstraction

Given  and  of type  asserts  is a type, '
conclude  asserts an anonymous function,  of  returning expression,  is of type →'.
Again, when we see a function that takes  and returns an expression , we know it's of type →' because  (a ) asserts that  is a '.
If we know  is of type  and thus an expression  is of type ', then a function of  returning expression  is of type →'.
Let variable declaration

Given  asserts ₀, of type , and  and , of type , asserts ₁ of type 
conclude  asserts let =₀ in ₁ of type 
Loosely,  is bound to ₀ in ₁ (a ) because ₀ is a , and  is a  that asserts ₁ is a .
This means if we have an expression ₀ that is a  (being a variable or a function), and some name, , also a , and an expression ₁ of type , then we can substitute ₀ for  wherever it appears inside of ₁.
Instantiation

Given  asserts  of type ' and ' is a subtype of 
conclude  asserts  is of type 
An expression,  is of parent type  because the expression  is subtype ', and  is the parent type of '.
If an instance is of a type that is a subtype of another type, then it is also an instance of that super-type - the more general type.
Generalization

Given  asserts  is a  and  is not an element of the free variables of ,
conclude  asserts , type for all argument expressions  returning a  expression
So in general,  is typed  for all argument variables () returning , because we know that  is a  and  is not a free variable.
This means we can generalize a program to accept all types for arguments not already bound in the containing scope (variables that are not non-local). These bound variables are substitutable.
Putting it all together
Given certain assumptions (such as no free/undefined variables, a known environment, ) we know the types of:
- atomic elements of our programs (Variable),
- values returned by functions (Function Application),
- functional constructs (Function Abstraction),
- let bindings (Let Variable Declarations),
- parent types of instances (Instantiation), and
- all expressions (Generalization).
Conclusion
These rules combined allow us to prove the most general type of an asserted program, without requiring type annotations.