Perforce to lore, past the free five seats

Unlike Git LFS, Perforce isn't a side-channel bolted onto a tool that wasn't built for this. Helix Core is the real prior art for centralized, large-binary version control - server-of-record, file locking, per-path ACLs, decades of production hardening at studios bigger than most. Crediting it costs nothing. It still has real, specific edges that show up the moment your team scales past a handful of seats or steps off the office network.

Where Perforce still makes you pay for it

Pain pointWhat's actually happening
Every routine op phones home p4 edit, p4 add, p4 sync, p4 submit all require a live server round-trip. There's no local staging step that doesn't first ask the server's permission.
Out-of-band edits need reconciling Touch a file without p4 edit first - a script, an IDE that doesn't shell out to p4, a chmod - and it's invisible to the server until p4 reconcile walks the workspace and tells it what actually happened.
Binaries still get the whole-file tax Storage is delta-encoded RCS for text, full-file for binaries. "Lazy copy" branching saves space once, at the moment you branch - every binary edit after that is a fresh full-file revision, same as Git without LFS.
MD5 for content integrity Chosen when MD5 was still a reasonable choice. It's a hash algorithm with practical collision attacks published since 2004, still doing the job of proving a depot file is what it claims to be.
Exclusive locking is opt-in and per-path Real enforcement, when it's on - p4 submit genuinely fails a conflicting write. But it only applies to paths an admin remembered to mark +l or lock explicitly. Unmarked paths get none of it.
Closed, end to end Closed-source server, proprietary wire protocol, proprietary depot format, no third-party server implementation. Whatever you build against Perforce, you build against a moving target nobody outside the vendor can fully audit.
Changelist numbers are server-global One counter, incrementing across every branch and every stream in the depot at once - not a DAG of hash-linked revisions with independent, composable history per branch.
Licensing scales with headcount Commercial per-seat pricing kicks in past a small free tier - cost tracks how many people touch the depot, not how much you're actually storing or how you're actually using it.

Ever opened a file for edit from a hotel Wi-Fi network, three timezones from the server, and watched p4 edit just... sit there? That's not a Perforce bug either - it's the direct, honest cost of an architecture where "open a file" is a permission request, not a local operation.

Where lore closes the gap - and where it doesn't, yet

lore takes Perforce's role seriously - server-of-record, file locking for unmergeable content, per-path access control - and rebuilds the substrate underneath it.

  1. Filesystem is the ground truth, no reconcile step. lore reads the working tree directly. Edit a file with any tool you like; there's no separate server-tracked "opened" state to fall out of sync with.
  2. Content-addressed fragments, BLAKE3, not delta chains and MD5. Every fragment - text or binary - is addressed by a 256-bit cryptographic hash. Dedup works at fragment granularity across the whole store, not just at the moment of a branch.
  3. Offline by default. Staging, committing, branching, diffing, switching - all local, no round-trip. The remote matters when you sync or push, not for every single file you touch.
  4. Open, end to end. MIT-licensed client, server, and storage backends; the wire protocol and on-disk formats are publicly specified and versioned. Nothing about lore requires trusting a closed binary to know what it actually did to your data.
  5. Per-path ACLs via links, not a protections table. lore doesn't have Perforce's single per-path grants table - it gets the same operational outcome by making any directory that needs its own policy a separate linked repository with its own partition. Different mechanism, similar result.

Here's the part that doesn't flatter lore: lore's file locking is advisory today - it signals intent, nothing in the push path enforces it. Perforce's exclusive checkout, once an admin actually configures it on a path, is real enforcement at submit time. That's a genuine capability Perforce has and lore doesn't yet. No point pretending otherwise.

How to actually migrate (the part that needs more thought)

The current-state migration is mechanically easier than the Git+LFS case - p4 sync gives you real files on disk directly, no pointer-stub trap to fall into. What makes Perforce harder isn't the file copy. It's everything the depot's structure was quietly doing for you that a flat file copy throws away.

  1. Map your protections table before you copy anything. Every subtree with its own p4 protects grant needs to become its own lore repository, linked back at the original path - lore has no equivalent of a single cross-tree ACL table inside one repository.
  2. Sync a clean workspace at head.
    p4 sync //depot/path/...@head
    This pulls current content only - not the changelist history behind it.
  3. Create a workspace and repository on folkorama, then install the lore CLI and get a credential, as in Getting started.
  4. Clone the empty repository and copy the synced workspace in:
    lore clone lores://<your-subdomain>.…/<repo-id> migrated-repo
    cd migrated-repo
    rsync -a --exclude='.p4config' /path/to/p4-workspace/ ./
    No hidden VCS directory to strip out beyond an optional .p4config - Perforce doesn't leave one in the workspace by default the way Git leaves .git.
  5. Stage, commit, push, then wire up any links from step 1 at the paths where the protections table used to draw a boundary.
    lore stage .
    lore commit -m "Import from Perforce"
    lore push
  6. Verify, then decide what to do with the depot. Keep it live, read-only, if your license permits - you'll want it for history lookups either way.

Full history is the genuinely hard part here, harder than the Git+LFS case. Git at least hands you one hash-linked commit graph to walk. Perforce's history is per-file RCS delta chains plus separate integration records tying branches together, behind a proprietary depot format with no public interchange spec. A faithful import means scripting p4 filelog and p4 describe across the entire depot and reconstructing changelist order and branch relationships yourself. Fancy hand-rolling a changelist replayer against an undocumented binary format? Budget for that honestly, or don't promise it at all - streams' merge-flow rules don't survive the trip either way, and get re-thought as plain branches on the other side.