aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Runxi Yu2025-11-20 08:00:00 +0800
committerGravatar Runxi Yu2025-11-20 08:00:00 +0800
commita27bd4625f6e1f5153e5e654b09156cea48f82d2 (patch)
treeba60075ebdda0b0238f02f52465ab5464541841f
parentrefs: ResolveRef and ResolveRefFully, no HEAD split (diff)
signatureNo signature
refs: Support resolving hashes as refs
-rw-r--r--refs.go8
-rw-r--r--refs_test.go52
2 files changed, 60 insertions, 0 deletions
diff --git a/refs.go b/refs.go
index 258f06df..59621b40 100644
--- a/refs.go
+++ b/refs.go
@@ -156,6 +156,14 @@ func (repo *Repository) ResolveRef(path string) (Ref, error) {
"HEAD", "ORIG_HEAD", "FETCH_HEAD", "MERGE_HEAD",
"CHERRY_PICK_HEAD", "REVERT_HEAD", "REBASE_HEAD", "BISECT_HEAD",
}, path) {
+ id, err := repo.ParseHash(path)
+ if err == nil {
+ return Ref{
+ Kind: RefKindDetached,
+ Hash: id,
+ }, nil
+ }
+
// For now let's keep this to prevent e.g., random users from
// specifying something crazy like objects/... or ./config.
// There may be other legal pseudo-refs in the future,
diff --git a/refs_test.go b/refs_test.go
index 58953b53..022a22c6 100644
--- a/refs_test.go
+++ b/refs_test.go
@@ -227,3 +227,55 @@ func TestResolveRefFullySymbolicCycle(t *testing.T) {
t.Fatalf("unexpected error for symbolic cycle: %v", err)
}
}
+
+func TestResolveRefHashInput(t *testing.T) {
+ repoPath, cleanup := setupTestRepo(t)
+ defer cleanup()
+
+ workDir, cleanupWork := setupWorkDir(t)
+ defer cleanupWork()
+
+ err := os.WriteFile(filepath.Join(workDir, "file.txt"), []byte("content"), 0o644)
+ if err != nil {
+ t.Fatalf("failed to write file.txt: %v", err)
+ }
+ gitCmd(t, repoPath, "--work-tree="+workDir, "add", ".")
+ gitCmd(t, repoPath, "--work-tree="+workDir, "commit", "-m", "init")
+
+ commitHash := gitCmd(t, repoPath, "rev-parse", "HEAD")
+
+ repo, err := OpenRepository(repoPath)
+ if err != nil {
+ t.Fatalf("OpenRepository failed: %v", err)
+ }
+ defer repo.Close()
+
+ hashObj, err := repo.ParseHash(commitHash)
+ if err != nil {
+ t.Fatalf("ParseHash failed: %v", err)
+ }
+
+ ref, err := repo.ResolveRef(commitHash)
+ if err != nil {
+ t.Fatalf("ResolveRef(hash) failed: %v", err)
+ }
+ if ref.Kind != RefKindDetached {
+ t.Fatalf("expected RefKindDetached, got %v", ref.Kind)
+ }
+ if ref.Hash != hashObj {
+ t.Fatalf("hash mismatch: got %s, want %s", ref.Hash, hashObj)
+ }
+
+ hash, err := repo.ResolveRefFully(commitHash)
+ if err != nil {
+ t.Fatalf("ResolveRefFully(hash) failed: %v", err)
+ }
+ if hash != hashObj {
+ t.Fatalf("hash mismatch: got %s, want %s", hash, hashObj)
+ }
+
+ _, err = repo.ResolveRef("this_is_not_a_hash")
+ if err == nil {
+ t.Fatalf("expected error for invalid hash input")
+ }
+}