diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2026-02-27 15:40:24 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2026-02-27 15:46:37 +0000 |
| commit | 28ad5440c7184de9833f8448bc90153ee4499c83 (patch) | |
| tree | 92e72a62cc0465b11c4ec2028f9f6d8c4058057e /src/bin/git_remote_nostr/push.rs | |
| parent | 3aa9b7a8e49d8ec5a87693d3f52ae2c77f036ff2 (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.rs | 31 |
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() { |