upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/bin/git_remote_nostr/push.rs
diff options
context:
space:
mode:
authorDanConwayDev <DanConwayDev@protonmail.com>2026-02-27 15:40:24 +0000
committerDanConwayDev <DanConwayDev@protonmail.com>2026-02-27 15:46:37 +0000
commit28ad5440c7184de9833f8448bc90153ee4499c83 (patch)
tree92e72a62cc0465b11c4ec2028f9f6d8c4058057e /src/bin/git_remote_nostr/push.rs
parent3aa9b7a8e49d8ec5a87693d3f52ae2c77f036ff2 (diff)
fix: annotated tags missing from list due to dropped peeled refs
RepoState::try_from was explicitly discarding all refs/tags/*^{} entries ("peeled" refs) when parsing the nostr state event. This meant the list command only advertised the tag object OID, but git requires two lines for annotated tags: <tag-object-oid> refs/tags/v1.0.0 <commit-oid> refs/tags/v1.0.0^{} Without the ^{} peeled line git cannot resolve the tag to a commit, so git fetch --prune treats it as unresolvable and deletes it. The nostr state event already stores both entries correctly (written by generate_updated_state in push.rs). The fix simply stops try_from from discarding the ^{} entries on read, so they flow through to the list output unchanged.
Diffstat (limited to 'src/bin/git_remote_nostr/push.rs')
-rw-r--r--src/bin/git_remote_nostr/push.rs31
1 files changed, 31 insertions, 0 deletions
diff --git a/src/bin/git_remote_nostr/push.rs b/src/bin/git_remote_nostr/push.rs
index 870f22d..ed0f7df 100644
--- a/src/bin/git_remote_nostr/push.rs
+++ b/src/bin/git_remote_nostr/push.rs
@@ -925,6 +925,37 @@ fn generate_updated_state(
925) -> Result<HashMap<String, String>> { 925) -> Result<HashMap<String, String>> {
926 let mut new_state = existing_state.clone(); 926 let mut new_state = existing_state.clone();
927 927
928 // Backfill missing ^{} peeled refs for any annotated tags already in the
929 // state. State events published before this fix only stored the tag object
930 // OID; without the corresponding ^{} entry git cannot resolve the tag to a
931 // commit and treats it as missing (git fetch --prune deletes it). We fix
932 // this opportunistically on every push so affected repos self-heal without
933 // requiring manual intervention.
934 let tag_refs: Vec<(String, String)> = new_state
935 .iter()
936 .filter(|(k, _)| k.starts_with("refs/tags/") && !k.ends_with("^{}"))
937 .map(|(k, v)| (k.clone(), v.clone()))
938 .collect();
939 for (ref_name, tag_oid) in tag_refs {
940 let peeled_key = format!("{ref_name}^{{}}");
941 if new_state.contains_key(&peeled_key) {
942 continue;
943 }
944 // check if the stored OID is a tag object (annotated tag)
945 if let Ok(oid) = git2::Oid::from_str(&tag_oid) {
946 if git_repo
947 .git_repo
948 .find_object(oid, Some(git2::ObjectType::Tag))
949 .is_ok()
950 {
951 // peel to the commit the annotated tag points to
952 if let Ok(commit_oid) = git_repo.get_commit_or_tip_of_reference(&ref_name) {
953 new_state.insert(peeled_key, commit_oid.to_string());
954 }
955 }
956 }
957 }
958
928 for refspec in refspecs { 959 for refspec in refspecs {
929 let (from, to) = refspec_to_from_to(refspec)?; 960 let (from, to) = refspec_to_from_to(refspec)?;
930 if from.is_empty() { 961 if from.is_empty() {