mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-21 00:21:35 +03:00
Use common primatives, and make sure conflicted trees are handled correctly
This commit is contained in:
parent
0c362ae6df
commit
2cb1358ac0
@ -12,7 +12,7 @@ use crate::VirtualBranchesExt as _;
|
|||||||
/// Checks out the combined trees of all branches in the workspace.
|
/// Checks out the combined trees of all branches in the workspace.
|
||||||
///
|
///
|
||||||
/// This function will fail if the applied branches conflict with each other.
|
/// This function will fail if the applied branches conflict with each other.
|
||||||
pub(crate) fn checkout_branch_trees<'a>(
|
pub fn checkout_branch_trees<'a>(
|
||||||
ctx: &'a CommandContext,
|
ctx: &'a CommandContext,
|
||||||
_perm: &mut WorktreeWritePermission,
|
_perm: &mut WorktreeWritePermission,
|
||||||
) -> Result<git2::Tree<'a>> {
|
) -> Result<git2::Tree<'a>> {
|
||||||
|
@ -4,6 +4,9 @@ use anyhow::{bail, Context, Result};
|
|||||||
use bstr::ByteSlice;
|
use bstr::ByteSlice;
|
||||||
use git2::build::CheckoutBuilder;
|
use git2::build::CheckoutBuilder;
|
||||||
use gitbutler_branch::{signature, Branch, SignaturePurpose, VirtualBranchesHandle};
|
use gitbutler_branch::{signature, Branch, SignaturePurpose, VirtualBranchesHandle};
|
||||||
|
use gitbutler_branch_actions::branch_trees::{
|
||||||
|
checkout_branch_trees, compute_updated_branch_head, BranchHeadAndTree,
|
||||||
|
};
|
||||||
use gitbutler_branch_actions::internal::list_virtual_branches;
|
use gitbutler_branch_actions::internal::list_virtual_branches;
|
||||||
use gitbutler_branch_actions::{update_workspace_commit, RemoteBranchFile};
|
use gitbutler_branch_actions::{update_workspace_commit, RemoteBranchFile};
|
||||||
use gitbutler_cherry_pick::{ConflictedTreeKey, RepositoryExt as _};
|
use gitbutler_cherry_pick::{ConflictedTreeKey, RepositoryExt as _};
|
||||||
@ -19,46 +22,10 @@ use gitbutler_operating_modes::{
|
|||||||
};
|
};
|
||||||
use gitbutler_project::access::{WorktreeReadPermission, WorktreeWritePermission};
|
use gitbutler_project::access::{WorktreeReadPermission, WorktreeWritePermission};
|
||||||
use gitbutler_reference::{ReferenceName, Refname};
|
use gitbutler_reference::{ReferenceName, Refname};
|
||||||
use gitbutler_repo::{
|
use gitbutler_repo::{rebase::cherry_rebase, RepositoryExt};
|
||||||
rebase::{cherry_rebase, cherry_rebase_group},
|
|
||||||
RepositoryExt,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub mod commands;
|
pub mod commands;
|
||||||
|
|
||||||
pub const EDIT_UNCOMMITED_FILES_REF: &str = "refs/gitbutler/edit_uncommited_files";
|
|
||||||
|
|
||||||
fn save_uncommited_files(ctx: &CommandContext) -> Result<()> {
|
|
||||||
let repository = ctx.repository();
|
|
||||||
|
|
||||||
// Create a tree of all uncommited files
|
|
||||||
let tree = repository.create_wd_tree()?;
|
|
||||||
|
|
||||||
// Commit tree and reference it
|
|
||||||
let author_signature =
|
|
||||||
signature(SignaturePurpose::Author).context("Failed to get gitbutler signature")?;
|
|
||||||
let committer_signature =
|
|
||||||
signature(SignaturePurpose::Committer).context("Failed to get gitbutler signature")?;
|
|
||||||
let head = repository.head().context("Failed to get head")?;
|
|
||||||
let head_commit = head.peel_to_commit().context("Failed to get head commit")?;
|
|
||||||
let commit = repository
|
|
||||||
.commit(
|
|
||||||
None,
|
|
||||||
&author_signature,
|
|
||||||
&committer_signature,
|
|
||||||
"Edit mode saved changes",
|
|
||||||
&tree,
|
|
||||||
&[&head_commit],
|
|
||||||
)
|
|
||||||
.context("Failed to write stash commit")?;
|
|
||||||
|
|
||||||
repository
|
|
||||||
.reference(EDIT_UNCOMMITED_FILES_REF, commit, true, "")
|
|
||||||
.context("Failed to reference uncommited files")?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_commit_index(repository: &git2::Repository, commit: &git2::Commit) -> Result<git2::Index> {
|
fn get_commit_index(repository: &git2::Repository, commit: &git2::Commit) -> Result<git2::Index> {
|
||||||
let commit_tree = commit.tree().context("Failed to get commit's tree")?;
|
let commit_tree = commit.tree().context("Failed to get commit's tree")?;
|
||||||
// Checkout the commit as unstaged changes
|
// Checkout the commit as unstaged changes
|
||||||
@ -182,7 +149,6 @@ pub(crate) fn enter_edit_mode(
|
|||||||
bail!("Can not enter edit mode for a reference which does not have a cooresponding virtual branch")
|
bail!("Can not enter edit mode for a reference which does not have a cooresponding virtual branch")
|
||||||
}
|
}
|
||||||
|
|
||||||
save_uncommited_files(ctx).context("Failed to save uncommited files")?;
|
|
||||||
checkout_edit_branch(ctx, commit).context("Failed to checkout edit branch")?;
|
checkout_edit_branch(ctx, commit).context("Failed to checkout edit branch")?;
|
||||||
write_edit_mode_metadata(ctx, &edit_mode_metadata).context("Failed to persist metadata")?;
|
write_edit_mode_metadata(ctx, &edit_mode_metadata).context("Failed to persist metadata")?;
|
||||||
|
|
||||||
@ -191,36 +157,16 @@ pub(crate) fn enter_edit_mode(
|
|||||||
|
|
||||||
pub(crate) fn abort_and_return_to_workspace(
|
pub(crate) fn abort_and_return_to_workspace(
|
||||||
ctx: &CommandContext,
|
ctx: &CommandContext,
|
||||||
_perm: &mut WorktreeWritePermission,
|
perm: &mut WorktreeWritePermission,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let repository = ctx.repository();
|
let repository = ctx.repository();
|
||||||
|
|
||||||
// Checkout gitbutler workspace branch
|
// Checkout gitbutler workspace branch
|
||||||
{
|
|
||||||
repository
|
repository
|
||||||
.set_head(WORKSPACE_BRANCH_REF)
|
.set_head(WORKSPACE_BRANCH_REF)
|
||||||
.context("Failed to set head reference")?;
|
.context("Failed to set head reference")?;
|
||||||
repository
|
|
||||||
.checkout_head(Some(CheckoutBuilder::new().force().remove_untracked(true)))
|
|
||||||
.context("Failed to checkout gitbutler/workspace")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Checkout any stashed changes.
|
checkout_branch_trees(ctx, perm)?;
|
||||||
{
|
|
||||||
let stashed_workspace_changes_reference = repository
|
|
||||||
.find_reference(EDIT_UNCOMMITED_FILES_REF)
|
|
||||||
.context("Failed to find stashed workspace changes")?;
|
|
||||||
let stashed_workspace_changes_commit = stashed_workspace_changes_reference
|
|
||||||
.peel_to_commit()
|
|
||||||
.context("Failed to get stashed changes commit")?;
|
|
||||||
|
|
||||||
repository
|
|
||||||
.checkout_tree(
|
|
||||||
stashed_workspace_changes_commit.tree()?.as_object(),
|
|
||||||
Some(CheckoutBuilder::new().force().remove_untracked(true)),
|
|
||||||
)
|
|
||||||
.context("Failed to checkout workspace changes tree")?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -237,12 +183,6 @@ pub(crate) fn save_and_return_to_workspace(
|
|||||||
let commit = repository
|
let commit = repository
|
||||||
.find_commit(edit_mode_metadata.commit_oid)
|
.find_commit(edit_mode_metadata.commit_oid)
|
||||||
.context("Failed to find commit")?;
|
.context("Failed to find commit")?;
|
||||||
let stashed_workspace_changes_reference = repository
|
|
||||||
.find_reference(EDIT_UNCOMMITED_FILES_REF)
|
|
||||||
.context("Failed to find stashed workspace changes")?;
|
|
||||||
let stashed_workspace_changes_commit = stashed_workspace_changes_reference
|
|
||||||
.peel_to_commit()
|
|
||||||
.context("Failed to get stashed changes commit")?;
|
|
||||||
|
|
||||||
let Some(mut virtual_branch) =
|
let Some(mut virtual_branch) =
|
||||||
find_virtual_branch_by_reference(ctx, &edit_mode_metadata.branch_reference)?
|
find_virtual_branch_by_reference(ctx, &edit_mode_metadata.branch_reference)?
|
||||||
@ -255,6 +195,7 @@ pub(crate) fn save_and_return_to_workspace(
|
|||||||
// Recommit commit
|
// Recommit commit
|
||||||
let tree = repository.create_wd_tree()?;
|
let tree = repository.create_wd_tree()?;
|
||||||
|
|
||||||
|
let (_, committer) = repository.signatures()?;
|
||||||
let commit_headers = commit
|
let commit_headers = commit
|
||||||
.gitbutler_headers()
|
.gitbutler_headers()
|
||||||
.map(|commit_headers| CommitHeadersV2 {
|
.map(|commit_headers| CommitHeadersV2 {
|
||||||
@ -266,7 +207,7 @@ pub(crate) fn save_and_return_to_workspace(
|
|||||||
.commit_with_signature(
|
.commit_with_signature(
|
||||||
None,
|
None,
|
||||||
&commit.author(),
|
&commit.author(),
|
||||||
&commit.committer(),
|
&committer, // Use a new committer
|
||||||
&commit.message_bstr().to_str_lossy(),
|
&commit.message_bstr().to_str_lossy(),
|
||||||
&tree,
|
&tree,
|
||||||
&parents.iter().collect::<Vec<_>>(),
|
&parents.iter().collect::<Vec<_>>(),
|
||||||
@ -278,58 +219,35 @@ pub(crate) fn save_and_return_to_workspace(
|
|||||||
let new_branch_head = cherry_rebase(ctx, new_commit_oid, commit.id(), virtual_branch.head)
|
let new_branch_head = cherry_rebase(ctx, new_commit_oid, commit.id(), virtual_branch.head)
|
||||||
.context("Failed to rebase commits onto new commit")?
|
.context("Failed to rebase commits onto new commit")?
|
||||||
.unwrap_or(new_commit_oid);
|
.unwrap_or(new_commit_oid);
|
||||||
repository
|
|
||||||
.reference(
|
|
||||||
&edit_mode_metadata.branch_reference,
|
|
||||||
new_branch_head,
|
|
||||||
true,
|
|
||||||
"",
|
|
||||||
)
|
|
||||||
.context("Failed to reference new commit branch head")?;
|
|
||||||
|
|
||||||
// Move back to gitbutler/workspace and restore stashed changes
|
// Update virtual_branch
|
||||||
{
|
let fearless_rebasing = ctx.project().succeeding_rebases;
|
||||||
repository
|
let BranchHeadAndTree {
|
||||||
.set_head(WORKSPACE_BRANCH_REF)
|
head: new_branch_head,
|
||||||
.context("Failed to set head reference")?;
|
tree: new_branch_tree,
|
||||||
repository
|
} = compute_updated_branch_head(
|
||||||
.checkout_head(Some(CheckoutBuilder::new().force().remove_untracked(true)))
|
repository,
|
||||||
.context("Failed to checkout gitbutler/workspace")?;
|
&virtual_branch,
|
||||||
|
new_branch_head,
|
||||||
|
fearless_rebasing,
|
||||||
|
)?;
|
||||||
|
|
||||||
virtual_branch.head = new_branch_head;
|
virtual_branch.head = new_branch_head;
|
||||||
|
virtual_branch.tree = new_branch_tree;
|
||||||
virtual_branch.updated_timestamp_ms = gitbutler_time::time::now_ms();
|
virtual_branch.updated_timestamp_ms = gitbutler_time::time::now_ms();
|
||||||
vb_state
|
vb_state
|
||||||
.set_branch(virtual_branch)
|
.set_branch(virtual_branch)
|
||||||
.context("Failed to update vbstate")?;
|
.context("Failed to update vbstate")?;
|
||||||
|
|
||||||
let workspace_commit_oid = update_workspace_commit(&vb_state, ctx)
|
// Switch branch to gitbutler/workspace
|
||||||
.context("Failed to update gitbutler workspace")?;
|
|
||||||
|
|
||||||
let rebased_stashed_workspace_changes_commit = cherry_rebase_group(
|
|
||||||
repository,
|
|
||||||
workspace_commit_oid,
|
|
||||||
&[stashed_workspace_changes_commit.id()],
|
|
||||||
true,
|
|
||||||
)
|
|
||||||
.context("Failed to rebase stashed workspace commit changes")?;
|
|
||||||
|
|
||||||
let commit_thing = repository
|
|
||||||
.find_commit(rebased_stashed_workspace_changes_commit)
|
|
||||||
.context("Failed to find commit of rebased stashed workspace changes commit oid")?;
|
|
||||||
|
|
||||||
let tree_thing = repository
|
|
||||||
.find_real_tree(&commit_thing, Default::default())
|
|
||||||
.context("Failed to get tree of commit of rebased stashed workspace changes")?;
|
|
||||||
|
|
||||||
repository
|
repository
|
||||||
.checkout_tree(
|
.set_head(WORKSPACE_BRANCH_REF)
|
||||||
tree_thing.as_object(),
|
.context("Failed to set head reference")?;
|
||||||
Some(CheckoutBuilder::new().force().remove_untracked(true)),
|
|
||||||
)
|
|
||||||
.context("Failed to checkout stashed changes tree")?;
|
|
||||||
|
|
||||||
list_virtual_branches(ctx, perm).context("Failed to list virtual branches")?;
|
// Checkout the applied branches
|
||||||
}
|
checkout_branch_trees(ctx, perm)?;
|
||||||
|
update_workspace_commit(&vb_state, ctx)?;
|
||||||
|
list_virtual_branches(ctx, perm)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user