I don't own an M0 but from a test upload with no board connected it looks like it uses the same system as the Leonardo. What happens is at the start of the upload the Arduino IDE opens the board's serial port at 1200 baud. That is a signal to some USB code that's added in by the Arduino core library to reset the board to activate the bootloader. With my Leonardo I can successfully upload from the command line by following the steps you list but I wonder if there could be some difference in the way the M0 bootloader handles the software reset that happens at the start of the upload via the IDE and the hard reset you are doing for the command line upload.