The error message when moving between filesystems is slightly more verbose:
# mv a/foo b/bar
mv: inter-device move failed: 'a/foo' to 'b/bar/foo'; unable to remove target: Directory not empty
So it's not trying to merge directories like you seem to expect, instead it's removing the target before renaming the source; and removing for directories only works when it's empty.
In terms of syscalls, within the same filesystem, it's just rename()
rename("a/foo", "a/bar/foo") = -1 ENOTEMPTY (Directory not empty)
When moving between filesystems, it's first rename()
detecting this case and them a simple attempt at rmdir()
.
rename("a/foo", "b/bar/foo") = -1 EXDEV (Invalid cross-device link)
rmdir("b/bar/foo") = -1 ENOTEMPTY (Directory not empty)
mv
could make more of an effort but it doesn't want to. ;)