From 07d74db2112ebaa68bc10e6ffdf3f774b6d5fecf Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 3 Jul 2026 18:44:53 +0000 Subject: [PATCH] sx-gitea import: snapshot imports + custom commit message + remote replace MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Import from an IMMUTABLE snapshot (git archive), not the live tree — a replay diverges the moment a source file changes (the forge's own non-fast-forward check caught exactly that). import-stage-msg! carries the source SHA in the commit message; import-delete-remote! + push replaces a partial import's history in two requests. rose-ash mirrored to sx.sx-web.org/giles/rose-ash: 4468 files @ 4a7c05a2, one commit, zero skipped, single push under the linear wire. Co-Authored-By: Claude Fable 5 --- lib/gitea/import.sx | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/lib/gitea/import.sx b/lib/gitea/import.sx index 15d9e433..e8ac97b6 100644 --- a/lib/gitea/import.sx +++ b/lib/gitea/import.sx @@ -12,7 +12,8 @@ ; without re-pushing), import-push! sends the delta between the remote's ; advertised head and the local one in a single request. Pushing per ; batch is quadratic (every push walks the full closure on both sides); -; stage many, push once. +; stage many, push once. Import from an IMMUTABLE snapshot (git archive) +; — replaying against a live tree diverges the moment a file changes. ; ; Files whose pack line would exceed the pkt-line limit are skipped and ; reported per batch (wire limit; see lib/gitea/wire.sx). @@ -54,12 +55,12 @@ gitea/import-fits? (fn (data) (gitea/pkt-fits? (str "x" (serialize (git/blob data)))))) -; read + stage one manifest of paths and commit — NO push -; => {:batch n :files k :skipped (paths) :cid commit-cid} +; read + stage one manifest of paths and commit with the given message — +; NO push. => {:batch n :files k :skipped (paths) :cid commit-cid} (define - gitea/import-stage! + gitea/import-stage-msg! (fn - (root manifest) + (root manifest message time) (let ((st gitea/import-state)) (let @@ -69,9 +70,21 @@ (let ((skipped (reduce (fn (acc p) (let ((data (file-read (str root "/" p)))) (if (gitea/import-fits? data) (begin (git/add! repo p data) acc) (append acc (list p))))) (list) paths))) (let - ((cid (git/commit! repo {:message (str "import rose-ash: batch " n) :time n :author "giles"}))) + ((cid (git/commit! repo {:message message :time time :author "giles"}))) (begin (set! gitea/import-state (assoc st :batch n)) {:batch n :files (- (len paths) (len skipped)) :skipped skipped :cid cid}))))))) +(define + gitea/import-stage! + (fn + (root manifest) + (let + ((n (+ 1 (get gitea/import-state :batch)))) + (gitea/import-stage-msg! + root + manifest + (str "import rose-ash: batch " n) + n)))) + ; one delta push of everything staged since the remote's advertised head (define gitea/import-push! @@ -81,6 +94,15 @@ ((st gitea/import-state)) (gitea/push! (get st :remote) (get st :repo) "heads/main")))) +; delete the remote branch (for replacing an import's history) +(define + gitea/import-delete-remote! + (fn + () + (let + ((st gitea/import-state)) + (gitea/push-delete! (get st :remote) (get st :repo) "heads/main")))) + ; stage + push in one step (fine for small imports) (define gitea/import-batch!