We often either submit an issue or a pull request not to fork. When this does not work, we'll write a plugin or equivalent and use that with the dependency so we will not have to fork and play catch up with the upstream.<p>For example, one of the tools we use is MinIO. There was an issue for their Python client that complained it lacked administrative features and the maintainers marked it as not on the roadmap at that time. I wrote a library called <i>bmc</i>, as a wrapper to their CLI exposing admin functions to a Python programmer. I proposed a prototype and the MinIO people said it's the expected behavior and went on to write it. Other people reading the issue asked access to it and we put it on PyPI.<p>It's not a fork but a separate library. Now the MinIO folks have included _some_ functionality in their original Python client but it doesn't have the ones we need. We'll switch back to their client for admin as soon as they have feature match.<p>Another example is MLflow. There was an issue wher it could track models that expect higher dimensional data but when deployed, they could only receive a two dimensional dataframe. I think issue 3570. It didn't go far and we developed a plugin/companion library that did that instead of changing the code and playing catch-up. Same with other features like authentication, which also is a result of good design decisions of having authentication not tied to our product, but having our product as an authentication provider amongst many and it just <i>happens</i> that we used ours, which again, makes supporting other authentication schemes easier.<p>An example of issues are one with Grafana where we didn't like how bandwidth was represented (as Mbs) because it would break dimensional reasoning (if you integrate bandwidth with respect to time, you should have Mb, not Mbs^2). They were super fast and changed it.<p>To good folks at Jupyter also ,ere very helpful when we needed to use custom config files that were overwritten or something. They promptly replied to the issue by making it configurable.<p>These are some things we use to avoid forking. Issues, pull requests, plugins, libraries, etc.
One can imagine applying a series of patches as a rebase operation of a “virtual” branch, with the resulting ephemeral branch being thrown away after the build.<p>So the only real difference is that one stores the changes to be rebased as part of the main repo vs the repo of a forked dependency. As a result of that one loses the existing tooling aimed at merge/rebase management (git rerere, git rebase -i)<p>Thus - if the part of the code base being patched is relatively unchanging, this is a nice shortcut. But if it is part of actively changed code, explicitly managing what is essentially a fork in disguise may be more convenient.
As someone who has been using patch-package on js projects for a number of years I can absolutely attest to its practicality, esp. over forking. Overhead / complexity are negligible, and I can count on a hand the number of times a patch has become stale. That said, I will often fork as well if the fix is worthy of a PR, but still use / import the original package + patch into projects for clarity. Last solid example I can think of is 'fixing' firebase client xhr support in node, which simply required an extra polyfill package and a single line of code at the top of one file.
The way I deal with dependencies lately is I place them in a separate directory (called lib) right next to the project source itself (called src). So the project and its dependencies are the same repository and I can have peace of mind. Also, I've got a few patches for those dependencies and those commits consist of only the patch and a clear log message. This helps when the time comes to update the patched dependencies.<p>Would I recommend this method to everyone? No. Is it useful in certain cases? Definitely yes.
Depending on the nature and scope of changes, forking offers a social advantage: pressure on the upstream project to merge your changes or risk marginalization. The described methodology largely avoids that pressure, yet the amount of effort to maintain a proper fork probably ends up being less work overall, as one can poach talent from the upstream contributor pool.
We do this at $COMPANY around bug fixes and security vulns because our clients expect us to. But we actively endeavour to commit those patches to the original project.