Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

handle-commiting-to-workspace-correctly #6103

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion crates/but-workspace/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,13 +19,16 @@ gix = { workspace = true, features = [
"parallel",
"serde",
"status",
"revision"
"revision",
] }
gitbutler-stack.workspace = true
gitbutler-command-context.workspace = true
gitbutler-oxidize.workspace = true
gitbutler-commit.workspace = true
gitbutler-repo.workspace = true
gitbutler-project.workspace = true
gitbutler-operating-modes.workspace = true
gitbutler-diff.workspace = true
serde = { workspace = true, features = ["std"] }
gitbutler-serde.workspace = true
itertools = "0.14"
Expand Down
105 changes: 3 additions & 102 deletions crates/gitbutler-branch-actions/src/integration.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,21 @@
use std::{path::PathBuf, vec};

use anyhow::{anyhow, Context, Result};
use bstr::ByteSlice;
use gitbutler_branch::BranchCreateRequest;
use gitbutler_branch::{self, GITBUTLER_WORKSPACE_REFERENCE};
use gitbutler_cherry_pick::RepositoryExt as _;
use gitbutler_command_context::CommandContext;
use gitbutler_commit::commit_ext::CommitExt;
use gitbutler_error::error::Marker;
use gitbutler_operating_modes::OPEN_WORKSPACE_REFS;
use gitbutler_oxidize::{git2_to_gix_object_id, gix_to_git2_oid, GixRepositoryExt};
use gitbutler_project::access::WorktreeWritePermission;
use gitbutler_repo::logging::{LogUntil, RepositoryExt as _};
use gitbutler_repo::RepositoryExt;
use gitbutler_repo::SignaturePurpose;
use gitbutler_stack::{Stack, VirtualBranchesHandle};
use tracing::instrument;

use crate::{branch_manager::BranchManagerExt, conflicts, VirtualBranchesExt};
use crate::{conflicts, workspace_commit::resolve_commits_above, VirtualBranchesExt};

const WORKSPACE_HEAD: &str = "Workspace Head";
const GITBUTLER_INTEGRATION_COMMIT_TITLE: &str = "GitButler Integration Commit";
pub const GITBUTLER_INTEGRATION_COMMIT_TITLE: &str = "GitButler Integration Commit";
pub const GITBUTLER_WORKSPACE_COMMIT_TITLE: &str = "GitButler Workspace Commit";

/// Creates and returns a merge commit of all active branch heads.
Expand Down Expand Up @@ -292,7 +287,7 @@ pub fn update_workspace_commit(
pub fn verify_branch(ctx: &CommandContext, perm: &mut WorktreeWritePermission) -> Result<()> {
verify_current_branch_name(ctx)
.and_then(verify_head_is_set)
.and_then(|()| verify_head_is_clean(ctx, perm))
.and_then(|()| resolve_commits_above(ctx, perm))
.context(Marker::VerificationFailure)?;
Ok(())
}
Expand Down Expand Up @@ -322,100 +317,6 @@ fn verify_current_branch_name(ctx: &CommandContext) -> Result<&CommandContext> {
}
}

// TODO(ST): Probably there should not be an implicit vbranch creation here.
fn verify_head_is_clean(ctx: &CommandContext, perm: &mut WorktreeWritePermission) -> Result<()> {
let head_commit = ctx
.repo()
.head()
.context("failed to get head")?
.peel_to_commit()
.context("failed to peel to commit")?;

let vb_handle = VirtualBranchesHandle::new(ctx.project().gb_dir());
let default_target = vb_handle
.get_default_target()
.context("failed to get default target")?;

let commits = ctx
.repo()
.log(
head_commit.id(),
LogUntil::Commit(default_target.sha),
false,
)
.context("failed to get log")?;

let workspace_index = commits
.iter()
.position(|commit| {
commit.message().is_some_and(|message| {
message.starts_with(GITBUTLER_WORKSPACE_COMMIT_TITLE)
|| message.starts_with(GITBUTLER_INTEGRATION_COMMIT_TITLE)
})
})
.context("GitButler workspace commit not found")?;
let workspace_commit = &commits[workspace_index];
let mut extra_commits = commits[..workspace_index].to_vec();
extra_commits.reverse();

if extra_commits.is_empty() {
// no extra commits found, so we're good
return Ok(());
}

ctx.repo()
.reset(workspace_commit.as_object(), git2::ResetType::Soft, None)
.context("failed to reset to workspace commit")?;

let branch_manager = ctx.branch_manager();
let mut new_branch = branch_manager
.create_virtual_branch(
&BranchCreateRequest {
name: extra_commits
.last()
.map(|commit| commit.message_bstr().to_string()),
..Default::default()
},
perm,
)
.context("failed to create virtual branch")?;

// rebasing the extra commits onto the new branch
let mut head = new_branch.head();
for commit in extra_commits {
let new_branch_head = ctx
.repo()
.find_commit(head)
.context("failed to find new branch head")?;

let rebased_commit_oid = ctx
.repo()
.commit_with_signature(
None,
&commit.author(),
&commit.committer(),
&commit.message_bstr().to_str_lossy(),
&commit.tree().unwrap(),
&[&new_branch_head],
None,
)
.context(format!(
"failed to rebase commit {} onto new branch",
commit.id()
))?;

let rebased_commit = ctx.repo().find_commit(rebased_commit_oid).context(format!(
"failed to find rebased commit {}",
rebased_commit_oid
))?;

new_branch.set_stack_head(ctx, rebased_commit.id(), Some(rebased_commit.tree_id()))?;

head = rebased_commit.id();
}
Ok(())
}

fn invalid_head_err(head_name: &str) -> anyhow::Error {
anyhow!(
"project is on {head_name}. Please checkout {} to continue",
Expand Down
1 change: 1 addition & 0 deletions crates/gitbutler-branch-actions/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ pub mod upstream_integration;

mod integration;
pub use integration::{update_workspace_commit, verify_branch};
pub mod workspace_commit;

mod file;
pub use file::{Get, RemoteBranchFile};
Expand Down
6 changes: 5 additions & 1 deletion crates/gitbutler-branch-actions/src/virtual.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use crate::{
remote::branch_to_remote_branch,
stack::stack_series,
status::{get_applied_status, get_applied_status_cached},
Get, RemoteBranchData, VirtualBranchHunkRange, VirtualBranchHunkRangeMap, VirtualBranchesExt,
verify_branch, Get, RemoteBranchData, VirtualBranchHunkRange, VirtualBranchHunkRangeMap,
VirtualBranchesExt,
};
use anyhow::{anyhow, bail, Context, Result};
use bstr::{BString, ByteSlice};
Expand Down Expand Up @@ -326,6 +327,9 @@ pub fn list_virtual_branches_cached(
) -> Result<StackListResult> {
assure_open_workspace_mode(ctx)
.context("Listing virtual branches requires open workspace mode")?;
// Make sure that the workspace commit is the head of the branch before listing.
verify_branch(ctx, perm)?;

let mut branches: Vec<VirtualBranch> = Vec::new();

let vb_state = ctx.project().virtual_branches();
Expand Down
Loading
Loading