Because a constant reference can bind to a temporary, and std::string has a constructor that can take a char * for a parameter.

That assignment constructs a so-called "temporary" object, and binds a constant reference to it.

Interestingly, when I assign a new value to argv[0] then s2 does not
change.

Why should it change? s2 is a separate object. A std::string object does not maintain a pointer to a char * that created it. There are many ways to create a std::string. The actual string is owned by the object. If the std::string is constructed from a literal character string, it gets copied into the std::string. So, if the literal character string comes from a buffer, and the buffer is subsequently modified, it has no effect on the std::string.