mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-11-28 13:26:16 +03:00
list_virtual_branches now includes the series data
at this point only local patches are returned
This commit is contained in:
parent
99e48e4f3e
commit
e00f47aea5
@ -28,7 +28,7 @@ use gitbutler_repo::{
|
||||
rebase::{cherry_rebase, cherry_rebase_group},
|
||||
LogUntil, RepoActionsExt, RepositoryExt,
|
||||
};
|
||||
use gitbutler_stack::Stack;
|
||||
use gitbutler_stack::{commit_by_oid_or_change_id, Stack};
|
||||
use gitbutler_time::time::now_since_unix_epoch_ms;
|
||||
use serde::Serialize;
|
||||
use std::collections::HashSet;
|
||||
@ -417,6 +417,14 @@ pub fn list_virtual_branches_cached(
|
||||
|
||||
let refname = branch.refname()?.into();
|
||||
|
||||
// TODO: Error out here once this API is stable
|
||||
let series = match stack_series(ctx, &branch, &default_target, &check_commit) {
|
||||
Ok(series) => series,
|
||||
Err(e) => {
|
||||
tracing::warn!("failed to compute stack series: {:?}", e);
|
||||
vec![]
|
||||
}
|
||||
};
|
||||
let branch = VirtualBranch {
|
||||
id: branch.id,
|
||||
name: branch.name,
|
||||
@ -441,7 +449,7 @@ pub fn list_virtual_branches_cached(
|
||||
fork_point,
|
||||
refname,
|
||||
tree: branch.tree,
|
||||
series: vec![],
|
||||
series,
|
||||
};
|
||||
branches.push(branch);
|
||||
}
|
||||
@ -453,6 +461,42 @@ pub fn list_virtual_branches_cached(
|
||||
Ok((branches, status.skipped_files))
|
||||
}
|
||||
|
||||
fn stack_series(
|
||||
ctx: &CommandContext,
|
||||
branch: &Branch,
|
||||
default_target: &Target,
|
||||
check_commit: &IsCommitIntegrated,
|
||||
) -> Result<Vec<PatchSeries>> {
|
||||
let mut api_series: Vec<PatchSeries> = vec![];
|
||||
for series in branch.list_series(ctx)? {
|
||||
let upstream_reference = default_target.push_remote_name.as_ref().and_then(|remote| {
|
||||
if series.head.pushed(remote.as_str(), ctx).ok()? {
|
||||
series.head.remote_reference(remote.as_str()).ok()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let mut patches: Vec<VirtualBranchCommit> = vec![];
|
||||
for patch in series.local_commits {
|
||||
let commit = commit_by_oid_or_change_id(&patch, ctx, branch.head, default_target)?;
|
||||
let is_integrated = check_commit.is_integrated(&commit)?;
|
||||
// TODO: correctly determine if commit is remote
|
||||
let vcommit =
|
||||
commit_to_vbranch_commit(ctx, branch, &commit, is_integrated, false, None)?;
|
||||
patches.push(vcommit);
|
||||
}
|
||||
api_series.push(PatchSeries {
|
||||
name: series.head.name,
|
||||
description: series.head.description,
|
||||
upstream_reference,
|
||||
patches,
|
||||
upstream_patches: vec![],
|
||||
});
|
||||
}
|
||||
|
||||
Ok(api_series)
|
||||
}
|
||||
|
||||
/// The commit-data we can use for comparison to see which remote-commit was used to craete
|
||||
/// a local commit from.
|
||||
/// Note that trees can't be used for comparison as these are typically rebased.
|
||||
|
@ -39,12 +39,12 @@ impl Display for CommitOrChangeId {
|
||||
|
||||
impl PatchReference {
|
||||
/// Returns a fully qualified reference with the supplied remote e.g. `refs/remotes/origin/base-branch-improvements`
|
||||
pub fn remote_reference(&self, remote: String) -> Result<String> {
|
||||
pub fn remote_reference(&self, remote: &str) -> Result<String> {
|
||||
Ok(format!("refs/remotes/{}/{}", remote, self.name))
|
||||
}
|
||||
|
||||
/// Returns `true` if the reference is pushed to the provided remote
|
||||
pub fn pushed(&self, remote: String, ctx: CommandContext) -> Result<bool> {
|
||||
pub fn pushed(&self, remote: &str, ctx: &CommandContext) -> Result<bool> {
|
||||
let remote_ref = self.remote_reference(remote)?;
|
||||
Ok(ctx.repository().find_reference(&remote_ref).is_ok())
|
||||
}
|
||||
|
@ -2,4 +2,4 @@ mod heads;
|
||||
mod series;
|
||||
mod stack;
|
||||
pub use series::Series;
|
||||
pub use stack::{PatchReferenceUpdate, Stack, TargetUpdate};
|
||||
pub use stack::{commit_by_oid_or_change_id, PatchReferenceUpdate, Stack, TargetUpdate};
|
||||
|
@ -266,7 +266,7 @@ impl Stack for Branch {
|
||||
// ensure that the head has not been pushed to a remote yet
|
||||
let default_target = branch_state(ctx).get_default_target()?;
|
||||
if let Some(remote) = default_target.push_remote_name {
|
||||
if reference_exists(ctx, &head.remote_reference(remote)?)? {
|
||||
if reference_exists(ctx, &head.remote_reference(remote.as_str())?)? {
|
||||
bail!("Cannot update the name of a head that has been pushed to a remote");
|
||||
}
|
||||
}
|
||||
@ -297,15 +297,17 @@ impl Stack for Branch {
|
||||
}
|
||||
let (_, reference) = get_head(&self.heads, &branch_name)?;
|
||||
let default_target = branch_state(ctx).get_default_target()?;
|
||||
let commit = get_target_commit(&reference.target, ctx, self.head, &default_target)?;
|
||||
let commit =
|
||||
commit_by_oid_or_change_id(&reference.target, ctx, self.head, &default_target)?;
|
||||
let remote_name = branch_state(ctx)
|
||||
.get_default_target()?
|
||||
.push_remote_name
|
||||
.ok_or(anyhow!(
|
||||
"No remote has been configured for the target branch"
|
||||
))?;
|
||||
let upstream_refname = RemoteRefname::from_str(&reference.remote_reference(remote_name)?)
|
||||
.context("Failed to parse the remote reference for branch")?;
|
||||
let upstream_refname =
|
||||
RemoteRefname::from_str(&reference.remote_reference(remote_name.as_str())?)
|
||||
.context("Failed to parse the remote reference for branch")?;
|
||||
ctx.push(
|
||||
commit.id(),
|
||||
&upstream_refname,
|
||||
@ -327,7 +329,7 @@ impl Stack for Branch {
|
||||
let mut previous_head = repo.merge_base(self.head, default_target.sha)?;
|
||||
for head in self.heads.clone() {
|
||||
let head_commit =
|
||||
get_target_commit(&head.target, ctx, self.head, &default_target)?.id();
|
||||
commit_by_oid_or_change_id(&head.target, ctx, self.head, &default_target)?.id();
|
||||
let local_patches = repo
|
||||
.log(head_commit, LogUntil::Commit(previous_head))?
|
||||
.iter()
|
||||
@ -361,7 +363,7 @@ fn validate_target(
|
||||
state: &VirtualBranchesHandle,
|
||||
) -> Result<()> {
|
||||
let default_target = state.get_default_target()?;
|
||||
let commit = get_target_commit(&reference.target, ctx, stack_head, &default_target)?;
|
||||
let commit = commit_by_oid_or_change_id(&reference.target, ctx, stack_head, &default_target)?;
|
||||
let stack_commits = ctx
|
||||
.repository()
|
||||
// TODO: seems like the range that is actually needed is from head to the merge base
|
||||
@ -440,7 +442,7 @@ fn validate_name(
|
||||
let default_target = state.get_default_target()?;
|
||||
// assert that there is no remote git reference with this name
|
||||
if let Some(remote_name) = default_target.push_remote_name {
|
||||
if reference_exists(ctx, &reference.remote_reference(remote_name)?)? {
|
||||
if reference_exists(ctx, &reference.remote_reference(remote_name.as_str())?)? {
|
||||
return Err(anyhow!(
|
||||
"A git reference with the name {} exists",
|
||||
&reference.name
|
||||
@ -486,7 +488,7 @@ fn branch_state(ctx: &CommandContext) -> VirtualBranchesHandle {
|
||||
VirtualBranchesHandle::new(ctx.project().gb_dir())
|
||||
}
|
||||
|
||||
fn get_target_commit<'a>(
|
||||
pub fn commit_by_oid_or_change_id<'a>(
|
||||
reference_target: &'a CommitOrChangeId,
|
||||
ctx: &'a CommandContext,
|
||||
stack_head: git2::Oid,
|
||||
|
Loading…
Reference in New Issue
Block a user