Skip to content

Commit d97c63b

Browse files
committed
Stuff and things
1 parent 715b57c commit d97c63b

File tree

6 files changed

+233
-170
lines changed

6 files changed

+233
-170
lines changed

Cargo.lock

+3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

crates/but-workspace/Cargo.toml

+4-1
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,16 @@ gix = { workspace = true, features = [
1919
"parallel",
2020
"serde",
2121
"status",
22-
"revision"
22+
"revision",
2323
] }
2424
gitbutler-stack.workspace = true
2525
gitbutler-command-context.workspace = true
2626
gitbutler-oxidize.workspace = true
2727
gitbutler-commit.workspace = true
2828
gitbutler-repo.workspace = true
29+
gitbutler-project.workspace = true
30+
gitbutler-operating-modes.workspace = true
31+
gitbutler-diff.workspace = true
2932
serde = { workspace = true, features = ["std"] }
3033
gitbutler-serde.workspace = true
3134
itertools = "0.14"

crates/gitbutler-branch-actions/src/integration.rs

+6-165
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,21 @@
1-
use std::cmp::Ordering;
2-
use std::collections::HashMap;
31
use std::{path::PathBuf, vec};
42

53
use anyhow::{anyhow, Context, Result};
6-
use gitbutler_branch::BranchCreateRequest;
74
use gitbutler_branch::{self, GITBUTLER_WORKSPACE_REFERENCE};
85
use gitbutler_cherry_pick::RepositoryExt as _;
96
use gitbutler_command_context::CommandContext;
10-
use gitbutler_commit::commit_ext::CommitExt;
11-
use gitbutler_diff::diff_files_into_hunks;
127
use gitbutler_error::error::Marker;
13-
use gitbutler_operating_modes::{OPEN_WORKSPACE_REFS, WORKSPACE_BRANCH_REF};
8+
use gitbutler_operating_modes::OPEN_WORKSPACE_REFS;
149
use gitbutler_oxidize::{git2_to_gix_object_id, gix_to_git2_oid, GixRepositoryExt};
15-
use gitbutler_project::access::{WorktreeReadPermission, WorktreeWritePermission};
16-
use gitbutler_repo::logging::{LogUntil, RepositoryExt as _};
17-
use gitbutler_repo::rebase::cherry_rebase_group;
10+
use gitbutler_project::access::WorktreeWritePermission;
1811
use gitbutler_repo::SignaturePurpose;
19-
use gitbutler_stack::{Stack, StackId, VirtualBranchesHandle};
12+
use gitbutler_stack::{Stack, VirtualBranchesHandle};
2013
use tracing::instrument;
2114

22-
use crate::compute_workspace_dependencies;
23-
use crate::{branch_manager::BranchManagerExt, conflicts, VirtualBranchesExt};
15+
use crate::{conflicts, workspace_commit::resolve_commits_above, VirtualBranchesExt};
2416

2517
const WORKSPACE_HEAD: &str = "Workspace Head";
26-
const GITBUTLER_INTEGRATION_COMMIT_TITLE: &str = "GitButler Integration Commit";
18+
pub const GITBUTLER_INTEGRATION_COMMIT_TITLE: &str = "GitButler Integration Commit";
2719
pub const GITBUTLER_WORKSPACE_COMMIT_TITLE: &str = "GitButler Workspace Commit";
2820

2921
/// Creates and returns a merge commit of all active branch heads.
@@ -295,7 +287,7 @@ pub fn update_workspace_commit(
295287
pub fn verify_branch(ctx: &CommandContext, perm: &mut WorktreeWritePermission) -> Result<()> {
296288
verify_current_branch_name(ctx)
297289
.and_then(verify_head_is_set)
298-
.and_then(|()| verify_head_is_clean(ctx, perm))
290+
.and_then(|()| resolve_commits_above(ctx, perm))
299291
.context(Marker::VerificationFailure)?;
300292
Ok(())
301293
}
@@ -325,157 +317,6 @@ fn verify_current_branch_name(ctx: &CommandContext) -> Result<&CommandContext> {
325317
}
326318
}
327319

328-
#[derive(Debug)]
329-
pub enum WorkspaceState {
330-
OffWorkspaceCommit {
331-
workspace_commit: git2::Oid,
332-
extra_commits: Vec<git2::Oid>,
333-
},
334-
OnWorkspaceCommit,
335-
}
336-
337-
pub fn workspace_state(
338-
ctx: &CommandContext,
339-
_perm: &WorktreeReadPermission,
340-
) -> Result<WorkspaceState> {
341-
let repository = ctx.repo();
342-
let vb_handle = VirtualBranchesHandle::new(ctx.project().gb_dir());
343-
let default_target = vb_handle.get_default_target()?;
344-
345-
let head_commit = repository.head()?.peel_to_commit()?;
346-
let commits = repository.log(
347-
head_commit.id(),
348-
LogUntil::Commit(default_target.sha),
349-
false,
350-
)?;
351-
352-
let workspace_index = commits
353-
.iter()
354-
.position(|commit| {
355-
commit.message().is_some_and(|message| {
356-
message.starts_with(GITBUTLER_WORKSPACE_COMMIT_TITLE)
357-
|| message.starts_with(GITBUTLER_INTEGRATION_COMMIT_TITLE)
358-
})
359-
})
360-
.context("")?;
361-
let workspace_commit = &commits[workspace_index];
362-
let extra_commits = commits[..workspace_index].to_vec();
363-
364-
if extra_commits.is_empty() {
365-
// no extra commits found, so we're good
366-
return Ok(WorkspaceState::OnWorkspaceCommit);
367-
}
368-
369-
Ok(WorkspaceState::OffWorkspaceCommit {
370-
workspace_commit: workspace_commit.id(),
371-
extra_commits: extra_commits
372-
.iter()
373-
.map(git2::Commit::id)
374-
.collect::<Vec<_>>(),
375-
})
376-
}
377-
378-
// TODO(ST): Probably there should not be an implicit vbranch creation here.
379-
fn verify_head_is_clean(ctx: &CommandContext, perm: &mut WorktreeWritePermission) -> Result<()> {
380-
let repository = ctx.repo();
381-
let head_commit = repository.head()?.peel_to_commit()?;
382-
383-
let WorkspaceState::OffWorkspaceCommit {
384-
workspace_commit,
385-
extra_commits,
386-
} = workspace_state(ctx, perm.read_permission())?
387-
else {
388-
return Ok(());
389-
};
390-
391-
let best_stack_id = find_best_stack_for_changes(ctx, perm, head_commit.id(), workspace_commit)?;
392-
393-
if let Some(best_stack_id) = best_stack_id {
394-
let vb_handle = VirtualBranchesHandle::new(ctx.project().gb_dir());
395-
let mut stack = vb_handle.get_stack_in_workspace(best_stack_id)?;
396-
397-
let new_head = cherry_rebase_group(repository, stack.head(), &extra_commits, false)?;
398-
399-
stack.set_stack_head(
400-
ctx,
401-
new_head,
402-
Some(repository.find_commit(new_head)?.tree_id()),
403-
)?;
404-
405-
update_workspace_commit(&vb_handle, ctx)?;
406-
} else {
407-
// There is no stack which can hold the commits so we should just unroll those changes
408-
repository.reference(WORKSPACE_BRANCH_REF, workspace_commit, true, "")?;
409-
repository.set_head(WORKSPACE_BRANCH_REF)?;
410-
}
411-
412-
Ok(())
413-
}
414-
415-
fn find_best_stack_for_changes(
416-
ctx: &CommandContext,
417-
perm: &mut WorktreeWritePermission,
418-
head_commit: git2::Oid,
419-
workspace_commit: git2::Oid,
420-
) -> Result<Option<StackId>> {
421-
let vb_state = VirtualBranchesHandle::new(ctx.project().gb_dir());
422-
let default_target = vb_state.get_default_target()?;
423-
let repository = ctx.repo();
424-
let stacks = vb_state.list_stacks_in_workspace()?;
425-
426-
let head_commit = repository.find_commit(head_commit)?;
427-
428-
let diffs = gitbutler_diff::trees(
429-
ctx.repo(),
430-
&repository.find_commit(workspace_commit)?.tree()?,
431-
&head_commit.tree()?,
432-
true,
433-
)?;
434-
let base_diffs: HashMap<_, _> = diff_files_into_hunks(&diffs).collect();
435-
let workspace_dependencies =
436-
compute_workspace_dependencies(ctx, &default_target.sha, &base_diffs, &stacks)?;
437-
438-
match workspace_dependencies.commit_dependent_diffs.len().cmp(&1) {
439-
Ordering::Greater => {
440-
// The commits are locked to multiple stacks. We can't correctly assign it
441-
// to any one stack, so the commits should be undone.
442-
Ok(None)
443-
}
444-
Ordering::Equal => {
445-
// There is one stack which the commits are locked to, so the commits
446-
// should be added to that particular stack.
447-
let stack_id = workspace_dependencies
448-
.commit_dependent_diffs
449-
.keys()
450-
.next()
451-
.expect("Values was asserted length 1 above");
452-
Ok(Some(*stack_id))
453-
}
454-
Ordering::Less => {
455-
// We should return the branch selected for changes, or create a new default branch.
456-
let mut stacks = vb_state.list_stacks_in_workspace()?;
457-
stacks.sort_by_key(|stack| stack.selected_for_changes.unwrap_or(0));
458-
459-
if let Some(stack) = stacks.last() {
460-
return Ok(Some(stack.id));
461-
}
462-
463-
let branch_manager = ctx.branch_manager();
464-
let new_stack = branch_manager
465-
.create_virtual_branch(
466-
&BranchCreateRequest {
467-
name: Some(head_commit.message_bstr().to_string()),
468-
..Default::default()
469-
},
470-
perm,
471-
)
472-
.context("failed to create virtual branch")?;
473-
474-
Ok(Some(new_stack.id))
475-
}
476-
}
477-
}
478-
479320
fn invalid_head_err(head_name: &str) -> anyhow::Error {
480321
anyhow!(
481322
"project is on {head_name}. Please checkout {} to continue",

crates/gitbutler-branch-actions/src/lib.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ pub use dependencies::compute_workspace_dependencies;
3838
pub mod upstream_integration;
3939

4040
mod integration;
41-
pub use integration::{update_workspace_commit, verify_branch, workspace_state, WorkspaceState};
41+
pub use integration::{update_workspace_commit, verify_branch};
42+
pub mod workspace_commit;
4243

4344
mod file;
4445
pub use file::{Get, RemoteBranchFile};

0 commit comments

Comments
 (0)