Migrating Git Repos to SHA-256: An Adventure With Submodules

Translated by a model; the original is in Russian.

· Linux and open source
A hands-on account of moving a Git repository to the SHA-256 object format — and why the official documentation turns into meaningless soup the moment submodules enter the picture.

cover.svg

SHA-256 has been available as a Git object format since version 2.42. The author lists its "benefits" with a straight face: no real security gain — plain old SHA-1dc is good enough; object IDs that are even longer and more unwieldy; and the street cred of using a fashionable hash function. The new format also gives most third-party tools like jujutsu/gitoxide and Eclipse/JGit indigestion — which, of course, is not a benefit at all.

The Easy Case

For a repository without submodules the recipe is easy to find (not in the Git docs, naturally, but scattered across random web pages). In the old repo you run git fast-export --all > export; in the new one, git init --object-format sha256 followed by git fast-import < ../old/export.

The trouble starts the instant submodules appear: everything explodes. Adding a SHA-1 submodule to a SHA-256 repo just pads the old ID with zeroes, and fast-import dies with an "object not found" error, dumping a crash report for good measure.

The Undocumented Rescue

There are options --rewrite-submodules-from and --rewrite-submodules-to that rewrite submodule object IDs from the old hash to the new one. But the entire documentation for them is a few paragraphs with no example and no mention of the companion commands involved. The author admits it plainly: without prior knowledge it reads like meaningless soup.

The working sequence goes like this. First export the submodule while saving its marks: git fast-export --export-marks=marks --all > export. One caveat: if the referencing repo ever pointed at a commit that has since dropped off its branches (after a force-push, say), those orphaned objects must be named explicitly. Then import the submodule into the new SHA-256 repo, again saving marks. Only after that is the main repo migrated, passing the paired --rewrite-submodules-from and --rewrite-submodules-to options, where the left-hand label is most conveniently the submodule's own name.

Bonus: Forgejo and Signatures

Forgejo would rather you delete the repo and create a fresh one. But with server access you can migrate in place — the author warns this is "extremely a hack" and will break every reference to an exact commit (tags survive). After converting the bare repo you must hand-edit the database to set object_format_name = "sha256", then run the branch, tag and hook synchronization actions from the admin panel. Issues, wiki, pull requests and projects all survive.

Finally, you can re-sign every commit with git rebase --exec and --gpg-sign — though not for submodules. In practice a single signature at the tip of a branch is enough: Git's structure turns it into a full chain of trust.


Source: Lobsters

Comments

Sign in, to comment.

  • No comments yet.