aboutsummaryrefslogtreecommitdiff
path: root/internal/peel/peel.go
diff options
context:
space:
mode:
authorGravatar Runxi Yu2026-03-06 21:19:56 +0800
committerGravatar Runxi Yu2026-03-07 00:34:30 +0800
commit01d15bccf3b1dcc51516b1f64d50950b31d7f8fb (patch)
treee491fcc762c67c1ef4ce54faafc5dafdb734ae8a /internal/peel/peel.go
parentobjectstored/refstore: Weird ireturn behavior (diff)
signatureNo signature
Urgh I made some wrong amends and I'm too tired to separate the commits out this time
ancestor: Split out of reachability mergebase: Add merge base routines internal/commitquery: Add commit query context engine thingy internal/peel: Shared tag peeling errors: Shared object query errors internal/testgit: Add rooted repo helpers; remove raw path access objectstore/memory: Add in-memory object store objectid: Add Compare helper
Diffstat (limited to 'internal/peel/peel.go')
-rw-r--r--internal/peel/peel.go50
1 files changed, 50 insertions, 0 deletions
diff --git a/internal/peel/peel.go b/internal/peel/peel.go
new file mode 100644
index 00000000..a3e84b8d
--- /dev/null
+++ b/internal/peel/peel.go
@@ -0,0 +1,50 @@
+// Package peel peels Git object references through annotated tags.
+package peel
+
+import (
+ stderrors "errors"
+
+ giterrors "codeberg.org/lindenii/furgit/errors"
+ "codeberg.org/lindenii/furgit/object"
+ "codeberg.org/lindenii/furgit/objectid"
+ "codeberg.org/lindenii/furgit/objectstore"
+ "codeberg.org/lindenii/furgit/objecttype"
+)
+
+// ToCommit peels annotated tags transitively until a commit is reached.
+func ToCommit(store objectstore.Store, id objectid.ObjectID) (objectid.ObjectID, error) {
+ for {
+ ty, _, err := store.ReadHeader(id)
+ if err != nil {
+ if stderrors.Is(err, objectstore.ErrObjectNotFound) {
+ return objectid.ObjectID{}, &giterrors.ObjectMissingError{OID: id}
+ }
+
+ return objectid.ObjectID{}, err
+ }
+
+ if ty != objecttype.TypeTag {
+ if ty != objecttype.TypeCommit {
+ return objectid.ObjectID{}, &giterrors.ObjectTypeError{OID: id, Got: ty, Want: objecttype.TypeCommit}
+ }
+
+ return id, nil
+ }
+
+ _, content, err := store.ReadBytesContent(id)
+ if err != nil {
+ if stderrors.Is(err, objectstore.ErrObjectNotFound) {
+ return objectid.ObjectID{}, &giterrors.ObjectMissingError{OID: id}
+ }
+
+ return objectid.ObjectID{}, err
+ }
+
+ tag, err := object.ParseTag(content, id.Algorithm())
+ if err != nil {
+ return objectid.ObjectID{}, err
+ }
+
+ id = tag.Target
+ }
+}