From 4961e2d4c14e50bfc6685c69681d3f2cc9294360 Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Mon, 18 Aug 2025 10:25:26 +0100 Subject: feat(sync): add `ref-name` param to limit sync limit syncing to a single reference with this new parameter. change instructions for out of sync remotes to use sync with this new option. --- src/bin/git_remote_nostr/push.rs | 8 ++++---- src/bin/ngit/sub_commands/sync.rs | 43 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 46 insertions(+), 5 deletions(-) diff --git a/src/bin/git_remote_nostr/push.rs b/src/bin/git_remote_nostr/push.rs index 1738790..80aed22 100644 --- a/src/bin/git_remote_nostr/push.rs +++ b/src/bin/git_remote_nostr/push.rs @@ -601,7 +601,7 @@ fn create_rejected_refspecs_and_remotes_refspecs( .or_insert(vec![url.to_string()]); term.write_line( format!( - "ERROR: {short_name} {to} conflicts with nostr ({} ahead {} behind) and local ({} ahead {} behind). either:\r\n 1. pull from that git server and resolve\r\n 2. force push your branch to the git server before pushing to nostr remote", + "ERROR: {short_name} {to} conflicts with nostr ({} ahead {} behind) and local ({} ahead {} behind). someone else may have pushed new updates. options:\r\n 1. review and integrate remote's tip available via `git checkout {remote_value}` \r\n 2. align remote state with nostr via `ngit sync --ref-name {to} --force` and try to push again", ahead_of_nostr.len(), behind_nostr.len(), ahead_of_local.len(), @@ -622,7 +622,7 @@ fn create_rejected_refspecs_and_remotes_refspecs( .and_modify(|a| a.push(url.to_string())) .or_insert(vec![url.to_string()]); term.write_line( - format!("ERROR: {short_name} {to} conflicts with nostr and is not an ancestor of local branch. either:\r\n 1. pull from that git server and resolve\r\n 2. force push your branch to the git server before pushing to nostr remote").as_str(), + format!("ERROR: {short_name} {to} conflicts with nostr and is not an ancestor of local branch. someone else may have pushed new updates. options:\r\n 1. review and integrate remote's tip available via `git checkout {remote_value}` \r\n 2. align remote state with nostr via `ngit sync --ref-name {to} --force` and try to push again").as_str(), )?; } } else { @@ -655,7 +655,7 @@ fn create_rejected_refspecs_and_remotes_refspecs( .or_insert(vec![url.to_string()]); term.write_line( format!( - "ERROR: {short_name} already contains {to} {} ahead and {} behind local branch. either:\r\n 1. pull from that git server and resolve\r\n 2. force push your branch to the git server before pushing to nostr remote", + "ERROR: {short_name} already contains {to} {} ahead and {} behind local branch. someone else may have pushed new updates. options:\r\n 1. review and integrate remote's tip available via `git checkout {remote_value}` \r\n 2. align remote state with nostr via `ngit sync --ref-name {to} --force` and try to push again", ahead.len(), behind.len(), ).as_str(), @@ -672,7 +672,7 @@ fn create_rejected_refspecs_and_remotes_refspecs( .and_modify(|a| a.push(url.to_string())) .or_insert(vec![url.to_string()]); term.write_line( - format!("ERROR: {short_name} already contains {to} at {remote_value} which is not an ancestor of local branch. either:\r\n 1. pull from that git server and resolve\r\n 2. force push your branch to the git server before pushing to nostr remote").as_str(), + format!("ERROR: {short_name} already contains {to} at {remote_value} which is not an ancestor of local branch. someone else may have pushed new updates. options:\r\n 1. review and integrate remote's tip available via `git checkout {remote_value}` \r\n 2. align remote state with nostr via `ngit sync --ref-name {to} --force` and try to push again").as_str(), )?; } } else { diff --git a/src/bin/ngit/sub_commands/sync.rs b/src/bin/ngit/sub_commands/sync.rs index 00dfe75..61c13a8 100644 --- a/src/bin/ngit/sub_commands/sync.rs +++ b/src/bin/ngit/sub_commands/sync.rs @@ -1,4 +1,4 @@ -use anyhow::{Context, Result}; +use anyhow::{Context, Result, bail}; use ngit::{ client::{ Client, Connect, Params, fetching_with_report, get_repo_ref_from_cache, @@ -13,6 +13,9 @@ use ngit::{ #[derive(Debug, clap::Args)] pub struct SubCommandArgs { + /// optionally just sync a specific reference. eg main or v1.5.2 + #[clap(short, long)] + pub(crate) ref_name: Option, /// force push updates and delete refs from non-grasp git servers #[arg(long, action)] force: bool, @@ -23,6 +26,32 @@ pub async fn launch(args: &SubCommandArgs) -> Result<()> { let git_repo = Repo::discover().context("failed to find a git repository")?; let git_repo_path = git_repo.get_path()?; + let full_ref_name = if let Some(ref_name) = &args.ref_name { + if ref_name.starts_with("refs/") { + if git_repo.git_repo.find_reference(ref_name).is_ok() { + Some(ref_name.clone()) + } else { + bail!("could not find reference {ref_name}"); + } + } else if git_repo + .git_repo + .find_reference(&format!("refs/tags/{ref_name}")) + .is_ok() + { + Some(format!("refs/tags/{ref_name}")) + } else if git_repo + .git_repo + .find_reference(&format!("refs/heads/{ref_name}")) + .is_ok() + { + Some(format!("refs/heads/{ref_name}")) + } else { + bail!("could not find reference {ref_name}"); + } + } else { + None + }; + let client = Client::new(Params::with_git_config_relay_defaults(&Some(&git_repo))); let (nostr_remote_name, decoded_nostr_url) = git_repo @@ -56,6 +85,12 @@ pub async fn launch(args: &SubCommandArgs) -> Result<()> { // delete ref from remote let mut not_deleted = vec![]; for remote_ref_name in remote_state.keys() { + // skip unspecified refs + if let Some(full_ref_name) = &full_ref_name { + if remote_ref_name != full_ref_name { + continue; + } + } if (!remote_ref_name.starts_with("refs/heads/pr/") && (remote_ref_name.starts_with("refs/heads/") || remote_ref_name.starts_with("refs/tags/"))) @@ -75,6 +110,12 @@ pub async fn launch(args: &SubCommandArgs) -> Result<()> { // add or update ref on remote let mut not_updated = vec![]; for nostr_ref_name in nostr_state.state.keys() { + // skip unspecified refs + if let Some(full_ref_name) = &full_ref_name { + if nostr_ref_name != full_ref_name { + continue; + } + } if nostr_ref_name.starts_with("refs/heads/") || nostr_ref_name.starts_with("refs/tags/") || !nostr_ref_name.starts_with("refs/heads/pr/") -- cgit v1.2.3