sha256convert: dedup message-rewrite path; fix package doc and lints · Entire
sha256convert: dedup message-rewrite path; fix package doc and lints
57380c7→main·
nodo·1mo ago·2 files·+178 added/-145 removed
Address a batch of PR #66 review findings:
Merge extractMessageReferences + rewriteHashesInMessage into a single rewriteMessageRefs that resolves and rewrites a commit/tag message in one regex pass. The "translate referenced objects before rewriting" ordering -- the subtlest invariant in the file -- now lives in one place instead of two byte-identical copies, and the message body is scanned once per object instead of twice.
Extract stripSignatures and previewJoin helpers to collapse the remaining copy-paste in translateCommit/translateTag and Result.Lines (the two preview blocks had already drifted: one said "full list in --json", the other didn't).
Package doc no longer claims "no hash mapping is persisted": the SHA1->SHA256 mapping is preserved by default via refs/notes/sha1-origin and optionally via --write-mapping, so the originals stay recoverable.
Make the target-dir failure cleanup best-effort (no returned error), matching the temp-dir cleanup defer. This clears the errcheck and wrapcheck findings golangci-lint flagged on the cleanup helpers, and the exhaustive switch case in rewriteMessageRefs.
Co-Authored-By: Claude Opus 4.8 noreply@anthropic.com
Sessions
09b743cc5de5View transcript
Changes
2
- cmd/git-sync/internal/sha256convert
- Msha256convert.go+146/-138
- Msha256convert_test.go+32/-7
// a temporary on-disk SHA1 bare repo, then walks every reachable object and
// re-emits it under SHA256 into a new bare repo at the user-supplied path.
//
// The tool is intentionally scoped: no hash mapping is persisted, GPG
// signatures on commits and tags are dropped (they sign over the original
// SHA1 byte stream and would be invalid post-rewrite), and any submodule
// gitlink fails the run so the caller chooses which refs to exclude. The
// linked-to repository's URL still points at an upstream SHA1 store,
// which has no way to resolve a SHA256-rewritten gitlink, so rewriting
// would produce a tree that fsck-passes but breaks
// `git submodule update`.
// The SHA1 → SHA256 mapping is preserved, so the original hashes stay
// recoverable: by default as a refs/notes/sha1-origin notes ref in the
// converted repo (disable with --no-origin-notes), and optionally as a
// sidecar TSV via --write-mapping.
package sha256convert
import (
// switching to a "(N more)" suffix.
const previewMax = 5
// previewJoin renders items as a comma-separated list, inlining at most
// previewMax of them and appending ", ... (N more<suffix>)" when the list
// is longer. suffix points at where the full list lives (e.g.
// "; full list in --json"); pass "" for none.
func previewJoin(items []string, suffix string) string {
if len(items) <= previewMax {
return strings.Join(items, ", ")
}
return fmt.Sprintf("%s, ... (%d more%s)",
strings.Join(items[:previewMax], ", "), len(items)-previewMax, suffix)
}
// Lines satisfies the human-readable output contract used by other git-sync subcommands.
func (r Result) Lines() []string {
lines := []string{
lines = append(lines, fmt.Sprintf("rewrote %d SHA1 hash reference(s) in commit/tag messages", r.MessageRewrites))
}
if n := len(r.AmbiguousMessageRefs); n > 0 {
preview := r.AmbiguousMessageRefs
extra := 0
if len(preview) > previewMax {
extra = len(preview) - previewMax
preview = preview[:previewMax]
}
line := fmt.Sprintf("warning: %d ambiguous SHA1 hex prefix(es) in messages left unrewritten (look up via the mapping file): %s",
n, strings.Join(preview, ", "))
if extra > 0 {
line += fmt.Sprintf(", ... (%d more)", extra)
}
lines = append(lines, line)
}
if r.SkippedPullRefs > 0 {
lines = append(lines, fmt.Sprintf("excluded %d foreign pull/merge-request ref(s) (refs/pull/*, refs/pull-requests/*, refs/merge-requests/*) from --all-refs; pass --include-pull-refs to convert them", r.SkippedPullRefs))
}
}
// rewriteHashesInMessage scans msg for short and full SHA1 hashes,
// replacing any that uniquely identify a commit or tag in t.reachable
// with the corresponding full SHA256 hex from t.mapping. Returns the
// rewritten message and the number of substitutions made. Ambiguous
// prefixes are left in place and recorded in t.ambiguousMessageRefs so the
// caller can surface a warning at the end of the run.
func (t *translator) rewriteHashesInMessage(msg string) (string, int) {
count := 0
out := hashPattern.ReplaceAllStringFunc(msg, func(s string) string {
sha1, result := t.resolveMessageRef(s)
switch result {
case matchNone:
return s
case matchAmbiguous:
t.ambiguousMessageRefs[s] = struct{}{}
return s
}
})
}