“output” is just h unrolled in time. so, actually, I think gather() is rarely needed with LSTMs too, as you can  just use h_n

do you recommend using GRU instead of LSTM?

It is subjective, but I think GRU is good enough for “collapsing” tasks. It is “naked” having no output gate, so when you use “output” from all timesteps, LSTM may work better in theory.
2.2. neither batching nor packing affects output (except padding areas)