gitgithubgit-fork

How to Keep a Forked GitHub Repository in Sync Without Disrupting Independent Releases and Changelogs?


I forked a GitHub repository to add a specific functionality, and I intend to maintain it as an independent project. However, I need to frequently sync my fork with the original repository to incorporate updates. Using git fetch and git rebase upstream/main isn't ideal for my use case because I have my own releases and changelogs, and rebasing would disrupt this history.

What is the recommended way to keep a forked repository in sync with the original while maintaining independent versioning and changelogs? For example, how does a project like Neovim stay in sync with Vim without losing its own release history?

Are there best practices or workflows for this kind of scenario?

Edit: Rephrase for clarity and added an example.


Solution

  • For example, how does a project like Neovim stay in sync with Vim without losing its own release history?

    A quick glance at the neovim history and the vim history suggests neovim is cherry-picking vim commits. For example, here is a vim commit and its neovim cherry-pick. They also appear to accept upstream patches as normal pull requests and sometimes they need some work. Vim only has 5 or 10 commits a day, so this is viable and allows the work to be distributed across a large enough team. Each upstream commit is treated like any other commit.

    Your other option, if you want all the upstream work, is to merge. This is a much more daunting task, so it should be done as frequently as possible, but not so frequent as to destabilize your fork.

    There's no magic bullet, you simply have to do the work of integrating updates somehow. But there's many ways to make that process easier.

    Test, test, and test some more!

    Because you will be merging large amounts of code from upstream causing large changes, good tests will supplement the inevitable mistakes that slip through. Ideally you'll want 100% coverage of all your new code and features.

    As much as possible, be backwards compatible.

    It will let you incorporate upstream changes easier if you try to remain backwards compatible with the upstream. For example, instead of changing a class, write a subclass.

    This also allows you to piggy-back off the upstream project's tests.

    As much as possible, write new code.

    For example, if you have to extensively rewrite an existing function consider instead writing a new function and leave the old one alone.

    If possible, put changes into completely new files to avoid conflicts when the upstream makes extensive changes.

    If the project has a system for plugins or add-ons or mods, do as much work as possible using this system.

    Share as much as possible upstream.

    Carefully separate refactoring, bug fixes, compatible tests, documentation improvements, and other compatible changes from new features. These can then be submitted to the upstream project as general improvements. The more work you share upstream the less you need to merge and maintain.

    There may even be features from your project the upstream will accept.

    Coordinate with the upstream.

    Maintain a good relationship with the upstream. Help them see the value in your project. Coordinate your work and theirs. For example, the upstream might be about to make a big change that would affect your project and maybe they make you aware that it's happening and you can provide feedback about how they can do their big change without disrupting your project.