Skip to content

Commit

Permalink
Merge pull request #7342 from gitbutlerapp/simplify-default-reference…
Browse files Browse the repository at this point in the history
…-gen

refactor: simplify virtual reference generation logic
  • Loading branch information
krlvi authored Feb 19, 2025
2 parents 61b9402 + 6380599 commit d67f7c8
Show file tree
Hide file tree
Showing 2 changed files with 45 additions and 29 deletions.
66 changes: 38 additions & 28 deletions crates/gitbutler-stack/src/stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use serde::{Deserialize, Serialize};
use crate::heads::add_head;
use crate::heads::get_head;
use crate::heads::remove_head;
use crate::stack_branch::remote_reference;
use crate::stack_branch::RepositoryExt as _;
use crate::stack_context::CommandContextExt;
use crate::stack_context::StackContext;
Expand Down Expand Up @@ -304,46 +305,54 @@ impl Stack {
allow_duplicate_refs: bool,
) -> Result<StackBranch> {
let commit = ctx.repo().find_commit(self.head())?;
let state = branch_state(ctx);

let mut reference = StackBranch::new(
commit.into(),
let name = Stack::next_available_name(
ctx,
&state,
if let Some(refname) = self.upstream.as_ref() {
refname.branch().to_string()
} else {
let (author, _committer) = ctx.repo().signatures()?;
generate_branch_name(author)?
},
None,
);
let state = branch_state(ctx);
allow_duplicate_refs,
)?;

let is_duplicate = |reference: &StackBranch| -> Result<bool> {
let reference = StackBranch::new(commit.into(), name, None);
validate_name(&reference, &state)?;

Ok(reference)
}

fn next_available_name(
ctx: &CommandContext,
state: &VirtualBranchesHandle,
mut name: String,
allow_duplicate_refs: bool,
) -> Result<String> {
let is_duplicate = |name: &String| -> Result<bool> {
Ok(if allow_duplicate_refs {
patch_reference_exists(&state, reference.name())?
patch_reference_exists(state, name)?
} else {
let repository = ctx.gix_repository()?;
patch_reference_exists(&state, reference.name())?
|| local_reference_exists(&repository, reference.name())?
|| remote_reference_exists(&repository, &state, reference)?
patch_reference_exists(state, name)?
|| local_reference_exists(&repository, name)?
|| remote_reference_exists(&repository, state, name)?
})
};

while is_duplicate(&reference)? {
while is_duplicate(&name)? {
// keep incrementing the suffix until the name is unique
let name = reference.name();
// let name = reference.name();
let mut split = name.split('-');
let left = split.clone().take(split.clone().count() - 1).join("-");
reference.set_name(
split
.next_back()
.and_then(|last| last.parse::<u32>().ok())
.map(|last| format!("{}-{}", left, last + 1)) //take everything except last, and append last + 1
.unwrap_or_else(|| format!("{}-1", reference.name())),
);
name = split
.next_back()
.and_then(|last| last.parse::<u32>().ok())
.map(|last| format!("{}-{}", left, last + 1)) //take everything except last, and append last + 1
.unwrap_or_else(|| format!("{}-1", name));
}
validate_name(&reference, &state)?;

Ok(reference)
Ok(name)
}

/// Adds a new "Branch" to the Stack.
Expand Down Expand Up @@ -948,12 +957,13 @@ fn local_reference_exists(repository: &gix::Repository, name: &str) -> Result<bo
fn remote_reference_exists(
repository: &gix::Repository,
state: &VirtualBranchesHandle,
branch: &StackBranch,
name: &String,
) -> Result<bool> {
local_reference_exists(
repository,
&branch.remote_reference(state.get_default_target()?.push_remote_name().as_str()),
)
let remote_ref = remote_reference(
name,
state.get_default_target()?.push_remote_name().as_str(),
);
local_reference_exists(repository, &remote_ref)
}

#[cfg(test)]
Expand Down
8 changes: 7 additions & 1 deletion crates/gitbutler-stack/src/stack_branch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,9 +116,10 @@ impl StackBranch {
}
}
}

/// Returns a fully qualified reference with the supplied remote e.g. `refs/remotes/origin/base-branch-improvements`
pub fn remote_reference(&self, remote: &str) -> String {
format!("refs/remotes/{}/{}", remote, self.name)
remote_reference(self.name(), remote)
}

/// Returns `true` if the reference is pushed to the provided remote
Expand Down Expand Up @@ -208,6 +209,11 @@ impl StackBranch {
}
}

/// Returns a fully qualified reference with the supplied remote e.g. `refs/remotes/origin/base-branch-improvements`
pub fn remote_reference(name: &String, remote: &str) -> String {
format!("refs/remotes/{}/{}", remote, name)
}

/// Represents the commits that belong to a `Branch` within a `Stack`.
#[derive(Debug, Clone)]
pub struct BranchCommits<'a> {
Expand Down

0 comments on commit d67f7c8

Please sign in to comment.