Different ways of Slicing

In PyTorch, 0.4.1, there are different ways to slice/index Variables.
For example, in the following code

a = torch.randn((3,4)) 

# Using Index Select
torch.index_select(a, 1, torch.tensor([0,2]))
# Using Gather
torch.gather(a, 1, torch.tensor([0,2]).repeat(3,1))
# Using Direct Slicing

What is the difference between the three, specially with respect to tracking of gradients? Also, which can be used for assignment with respect to tracking gradients.