> it is really easy to un-share code by copying it into multiple places but it is very hard to unify duplicated code
Code that already exists has a gravity, a presumption of correctness. That presumption is very difficult to overcome, especially for programmers new to the codebase. An abstraction you think of as temporary will be, to those who come after you, simply the way things are done; breaking it apart and re-forming it is, for them, fraught with risk. It's good to keep this in mind as you make commits.
I don't think I agree. Identifying an abstraction as leaky and breaking it apart is substantially more difficult and riskier than identifying duplication and creating an abstraction for it.
Removing an abstraction layer can usually be done mechanically by inlining the calls. This is a trivial operation. Identifying duplication not trivial since there might be various differences and you have to investigate if they are inconsequential or not.
Code that already exists has a gravity, a presumption of correctness. That presumption is very difficult to overcome, especially for programmers new to the codebase. An abstraction you think of as temporary will be, to those who come after you, simply the way things are done; breaking it apart and re-forming it is, for them, fraught with risk. It's good to keep this in mind as you make commits.