diff --git a/lib/crates/fabro-git-storage/src/gitobj.rs b/lib/crates/fabro-git-storage/src/gitobj.rs index 3c7a9ae0f..b5d36b6c0 100644 --- a/lib/crates/fabro-git-storage/src/gitobj.rs +++ b/lib/crates/fabro-git-storage/src/gitobj.rs @@ -106,6 +106,13 @@ impl Store { &self.repo } + pub fn repo_dir(&self) -> &Path { + self.repo + .workdir() + .or_else(|| self.repo.path().parent()) + .unwrap_or(self.repo.path()) + } + /// Store bytes as a git blob. pub fn write_blob(&self, content: &[u8]) -> Result { Ok(self.repo.blob(content)?) diff --git a/lib/crates/fabro-workflows/src/git.rs b/lib/crates/fabro-workflows/src/git.rs index 2a5a4722b..c684d0ea5 100644 --- a/lib/crates/fabro-workflows/src/git.rs +++ b/lib/crates/fabro-workflows/src/git.rs @@ -202,6 +202,32 @@ pub fn push_branch(repo: &Path, remote: &str, branch: &str) -> Result<()> { run_git_push(git_cmd(repo).args(["push", remote, branch])) } +/// Push run and metadata branches to origin if a remote tracking branch exists. +/// +/// Callers supply pre-built refspecs so they control force-push (`+` prefix). +pub fn push_run_branches( + store: &Store, + probe_branch: &str, + run_refspec: Option<&str>, + meta_refspec: &str, + label: &str, +) -> anyhow::Result<()> { + let repo_path = store.repo_dir(); + let remote_ref = format!("refs/remotes/origin/{probe_branch}"); + if store.repo().find_reference(&remote_ref).is_err() { + return Ok(()); + } + eprintln!("Pushing {label} branches to origin..."); + if let Some(refspec) = run_refspec { + push_branch(repo_path, "origin", refspec) + .map_err(|e| anyhow::anyhow!("failed to push run branch: {e}"))?; + } + push_branch(repo_path, "origin", meta_refspec) + .map_err(|e| anyhow::anyhow!("failed to push metadata branch: {e}"))?; + eprintln!("Remote refs updated."); + Ok(()) +} + /// Error from [`blocking_push_with_timeout`]. pub enum BlockingPushError { /// The git push itself failed. diff --git a/lib/crates/fabro-workflows/src/operations/fork.rs b/lib/crates/fabro-workflows/src/operations/fork.rs index d45d796a7..e1bef1808 100644 --- a/lib/crates/fabro-workflows/src/operations/fork.rs +++ b/lib/crates/fabro-workflows/src/operations/fork.rs @@ -134,29 +134,16 @@ fn fork_from_entry( .map_err(|e| anyhow::anyhow!("failed to write metadata entries: {e}"))?; if push { - let repo_path = store - .repo() - .workdir() - .or_else(|| store.repo().path().parent()) - .unwrap_or(store.repo().path()); - let source_run_branch = format!("{}{source_run_id}", crate::git::RUN_BRANCH_PREFIX); - let remote_ref = format!("refs/remotes/origin/{source_run_branch}"); - let has_remote_tracking = store.repo().find_reference(&remote_ref).is_ok(); - - if has_remote_tracking { - eprintln!("Pushing new branches to origin..."); - - let run_refspec = format!("refs/heads/{new_run_branch}:refs/heads/{new_run_branch}"); - crate::git::push_branch(repo_path, "origin", &run_refspec) - .map_err(|e| anyhow::anyhow!("failed to push run branch: {e}"))?; - - let meta_refspec = format!("refs/heads/{new_meta_branch}:refs/heads/{new_meta_branch}"); - crate::git::push_branch(repo_path, "origin", &meta_refspec) - .map_err(|e| anyhow::anyhow!("failed to push metadata branch: {e}"))?; - - eprintln!("Remote refs updated."); - } + let run_refspec = format!("refs/heads/{new_run_branch}:refs/heads/{new_run_branch}"); + let meta_refspec = format!("refs/heads/{new_meta_branch}:refs/heads/{new_meta_branch}"); + crate::git::push_run_branches( + store, + &source_run_branch, + Some(&run_refspec), + &meta_refspec, + "new", + )?; } Ok(new_run_id) diff --git a/lib/crates/fabro-workflows/src/operations/rewind.rs b/lib/crates/fabro-workflows/src/operations/rewind.rs index 73030f17f..a51662bbd 100644 --- a/lib/crates/fabro-workflows/src/operations/rewind.rs +++ b/lib/crates/fabro-workflows/src/operations/rewind.rs @@ -280,30 +280,18 @@ fn rewind_to_entry(store: &Store, run_id: &str, entry: &TimelineEntry, push: boo } if push { - let repo_path = store - .repo() - .workdir() - .or_else(|| store.repo().path().parent()) - .unwrap_or(store.repo().path()); - - let remote_ref = format!("refs/remotes/origin/{run_branch}"); - let has_remote_tracking = store.repo().find_reference(&remote_ref).is_ok(); - - if has_remote_tracking { - eprintln!("Force-pushing rewound branches to origin..."); - - if entry.run_commit_sha.is_some() { - let refspec = format!("+refs/heads/{run_branch}:refs/heads/{run_branch}"); - crate::git::push_branch(repo_path, "origin", &refspec) - .map_err(|e| anyhow::anyhow!("failed to push run branch: {e}"))?; - } - - let meta_refspec = format!("+refs/heads/{meta_branch}:refs/heads/{meta_branch}"); - crate::git::push_branch(repo_path, "origin", &meta_refspec) - .map_err(|e| anyhow::anyhow!("failed to push metadata branch: {e}"))?; - - eprintln!("Remote refs updated."); - } + let run_refspec = entry + .run_commit_sha + .as_ref() + .map(|_| format!("+refs/heads/{run_branch}:refs/heads/{run_branch}")); + let meta_refspec = format!("+refs/heads/{meta_branch}:refs/heads/{meta_branch}"); + crate::git::push_run_branches( + store, + &run_branch, + run_refspec.as_deref(), + &meta_refspec, + "rewound", + )?; } Ok(())