Upstream Anchoring: A Versioning Strategy for Forked Packages

September 22, 2024 · View on GitHub

Introduction

Upstream Anchoring is a versioning strategy designed to align forked package versions with their upstream counterparts while allowing for independent patch revisions. It ensures clarity, compatibility, and ease of tracking changes, making it ideal for maintaining synchronization without introducing version conflicts.

How it works

  • Version Structure: Keep the MAJOR and MINOR versions identical to the upstream package.
  • Patch Calculation:
    • Formula:
      Forked PATCH = (Upstream PATCH × Multiplier) + Fork Revision
      
    • Multiplier: A constant value (e.g., 1000) to provide ample revision space.
    • Fork Revision: Starts at 1 and increments with each revision.

Example

  • Upstream Version: 1.2.4
  • Multiplier: 1000
  • First Fork Revision:
    Forked PATCH = (4 × 1000) + 1 = 4001
    Forked Version = 1.2.4001
    

Why?

  • Alignment with Upstream: Easily identify the corresponding upstream version.
  • Ample Revision Space: Up to 999 revisions per upstream patch level.
  • Semantic Versioning Compliance: Compatible with npm and other package managers.
  • Correct Version Precedence: Forked versions are recognized as newer.

Official Implementation

import { parse } from 'semver'

export function calculatePackageVersion(
  version: string,
  factoryPackageVersion: string
): string {
  const semver = parse(version)
  if (!semver) throw new Error(`Invalid version: ${version}`)

  const paddedPatch = (semver.patch * 1000 + parseInt(factoryPackageVersion))
    .toString()
    .padStart(4, '0')

  return `${semver.major}.${semver.minor}.${paddedPatch}`
}