(bare repo): # Make sure receive.denyDeleteCurrent = ignore
(Dev A): git push
(Dev B): git pull --rebase # you can make this the default for a particular tracking branch so it is just "git pull"
(Dev B): # do some work
(Dev B): git commit
(Dev A): git commit --amend
(Dev A): git push origin :master # Deletes remote master. Not required for shared branches -- those can simply be replaced -- but "master" is usually the "current branch" for a repo, so it bears knowing.
(Dev A): git push origin master:master # And now we replace the remote's version with our local version.
(Dev B): git pull --rebase # Updates pointers and applies the new commit on top.
Yes, if you do even more devastating history changes than this, Dev B needs to dig a little further on why his rebase is going haywire. THIS is why people fear the history change; it is sometimes extra work for downstream developers to handle the rearrangements (and we developers like to be lazy and for everything to work smoothly the first time). Thankfully, downstream developers can solve these problems with a few git tools, including "rebase --onto" and cherry-picking. But in the case of a quick and simple commit amend, all is well.
Alternatively, you can code review, but sometimes people are in a rush, and you run into this situation. In most environments, I wager it will be okay, especially if there is communication on the changes and reasonable education on version control theory.