mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-19 07:32:22 +03:00
Merge pull request #5052 from gitbutlerapp/Refactor-tree-updating
Extract tree updating into its own tested function
This commit is contained in:
commit
0c362ae6df
@ -1,6 +1,10 @@
|
|||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
|
use gitbutler_branch::Branch;
|
||||||
|
use gitbutler_cherry_pick::RepositoryExt;
|
||||||
use gitbutler_command_context::CommandContext;
|
use gitbutler_command_context::CommandContext;
|
||||||
|
use gitbutler_commit::commit_ext::CommitExt as _;
|
||||||
use gitbutler_project::access::WorktreeWritePermission;
|
use gitbutler_project::access::WorktreeWritePermission;
|
||||||
|
use gitbutler_repo::rebase::cherry_rebase_group;
|
||||||
use gitbutler_repo::RepositoryExt as _;
|
use gitbutler_repo::RepositoryExt as _;
|
||||||
|
|
||||||
use crate::VirtualBranchesExt as _;
|
use crate::VirtualBranchesExt as _;
|
||||||
@ -61,6 +65,91 @@ pub(crate) fn checkout_branch_trees<'a>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct BranchHeadAndTree {
|
||||||
|
/// This is a commit Oid.
|
||||||
|
///
|
||||||
|
/// This should be used as the new head Oid for the branch.
|
||||||
|
pub head: git2::Oid,
|
||||||
|
/// This is a tree Oid.
|
||||||
|
///
|
||||||
|
/// This should be used as the new tree Oid for the branch.
|
||||||
|
pub tree: git2::Oid,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given a new head for a branch, this comptues how the tree should be
|
||||||
|
/// rebased on top of the new head. If the rebased tree is conflicted, then
|
||||||
|
/// the function will return a new head commit which is the conflicted
|
||||||
|
/// tree commit, and the the tree oid will be the auto-resolved tree.
|
||||||
|
///
|
||||||
|
/// This does not mutate the branch, or update the virtual_branches.toml.
|
||||||
|
/// You probably also want to call [`checkout_branch_trees`] after you have
|
||||||
|
/// mutated the virtual_branches.toml.
|
||||||
|
pub fn compute_updated_branch_head(
|
||||||
|
repository: &git2::Repository,
|
||||||
|
branch: &Branch,
|
||||||
|
new_head: git2::Oid,
|
||||||
|
fearless_rebasing: bool,
|
||||||
|
) -> Result<BranchHeadAndTree> {
|
||||||
|
compute_updated_branch_head_for_commits(
|
||||||
|
repository,
|
||||||
|
branch.head,
|
||||||
|
branch.tree,
|
||||||
|
new_head,
|
||||||
|
fearless_rebasing,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given a new head for a branch, this comptues how the tree should be
|
||||||
|
/// rebased on top of the new head. If the rebased tree is conflicted, then
|
||||||
|
/// the function will return a new head commit which is the conflicted
|
||||||
|
/// tree commit, and the the tree oid will be the auto-resolved tree.
|
||||||
|
///
|
||||||
|
/// If you have access to a [`Branch`] object, it's probably preferable to
|
||||||
|
/// use [`compute_updated_branch_head`] instead to prevent programmer error.
|
||||||
|
///
|
||||||
|
/// This does not mutate the branch, or update the virtual_branches.toml.
|
||||||
|
/// You probably also want to call [`checkout_branch_trees`] after you have
|
||||||
|
/// mutated the virtual_branches.toml.
|
||||||
|
pub fn compute_updated_branch_head_for_commits(
|
||||||
|
repository: &git2::Repository,
|
||||||
|
old_head: git2::Oid,
|
||||||
|
old_tree: git2::Oid,
|
||||||
|
new_head: git2::Oid,
|
||||||
|
fearless_rebasing: bool,
|
||||||
|
) -> Result<BranchHeadAndTree> {
|
||||||
|
let (author, committer) = repository.signatures()?;
|
||||||
|
|
||||||
|
let commited_tree = repository.commit_with_signature(
|
||||||
|
None,
|
||||||
|
&author,
|
||||||
|
&committer,
|
||||||
|
"Uncommited changes",
|
||||||
|
&repository.find_tree(old_tree)?,
|
||||||
|
&[&repository.find_commit(old_head)?],
|
||||||
|
Default::default(),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let rebased_tree =
|
||||||
|
cherry_rebase_group(repository, new_head, &[commited_tree], fearless_rebasing)?;
|
||||||
|
let rebased_tree = repository.find_commit(rebased_tree)?;
|
||||||
|
|
||||||
|
if rebased_tree.is_conflicted() {
|
||||||
|
let auto_tree_id = repository
|
||||||
|
.find_real_tree(&rebased_tree, Default::default())?
|
||||||
|
.id();
|
||||||
|
|
||||||
|
Ok(BranchHeadAndTree {
|
||||||
|
head: rebased_tree.id(),
|
||||||
|
tree: auto_tree_id,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Ok(BranchHeadAndTree {
|
||||||
|
head: new_head,
|
||||||
|
tree: rebased_tree.tree_id(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// These possibly could be considered more "integration" tests, but there is no
|
// These possibly could be considered more "integration" tests, but there is no
|
||||||
// need for `checkout_branch_trees` to be public, so it is tested here.
|
// need for `checkout_branch_trees` to be public, so it is tested here.
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -43,7 +43,7 @@ pub use remote::{RemoteBranch, RemoteBranchData, RemoteCommit};
|
|||||||
|
|
||||||
pub mod conflicts;
|
pub mod conflicts;
|
||||||
|
|
||||||
mod branch_trees;
|
pub mod branch_trees;
|
||||||
mod move_commits;
|
mod move_commits;
|
||||||
mod reorder_commits;
|
mod reorder_commits;
|
||||||
mod undo_commit;
|
mod undo_commit;
|
||||||
|
@ -1,12 +1,15 @@
|
|||||||
use anyhow::{bail, Context as _, Result};
|
use anyhow::{bail, Context as _, Result};
|
||||||
use gitbutler_branch::{signature, BranchId, SignaturePurpose};
|
use gitbutler_branch::BranchId;
|
||||||
use gitbutler_cherry_pick::RepositoryExt as _;
|
|
||||||
use gitbutler_command_context::CommandContext;
|
use gitbutler_command_context::CommandContext;
|
||||||
use gitbutler_commit::commit_ext::CommitExt as _;
|
|
||||||
use gitbutler_project::access::WorktreeWritePermission;
|
use gitbutler_project::access::WorktreeWritePermission;
|
||||||
use gitbutler_repo::{rebase::cherry_rebase_group, LogUntil, RepositoryExt as _};
|
use gitbutler_repo::{rebase::cherry_rebase_group, LogUntil, RepositoryExt as _};
|
||||||
|
|
||||||
use crate::{branch_trees::checkout_branch_trees, VirtualBranchesExt as _};
|
use crate::{
|
||||||
|
branch_trees::{
|
||||||
|
checkout_branch_trees, compute_updated_branch_head_for_commits, BranchHeadAndTree,
|
||||||
|
},
|
||||||
|
VirtualBranchesExt as _,
|
||||||
|
};
|
||||||
|
|
||||||
/// Moves a commit up or down a stack by a certain offset.
|
/// Moves a commit up or down a stack by a certain offset.
|
||||||
///
|
///
|
||||||
@ -119,44 +122,35 @@ fn inner_reorder_commit(
|
|||||||
|
|
||||||
ensure_offset_within_bounds(subject_commit, offset, branch_commits)?;
|
ensure_offset_within_bounds(subject_commit, offset, branch_commits)?;
|
||||||
|
|
||||||
let author = signature(SignaturePurpose::Author)?;
|
let reordered_commits = reorder_commit_list(subject_commit, offset, branch_commits)?;
|
||||||
let committer = signature(SignaturePurpose::Committer)?;
|
|
||||||
let tree_commit = repository.commit(
|
|
||||||
None,
|
|
||||||
&author,
|
|
||||||
&committer,
|
|
||||||
"Uncommited changes",
|
|
||||||
branch_tree,
|
|
||||||
&[&repository.find_commit(branch_commits[0])?],
|
|
||||||
)?;
|
|
||||||
|
|
||||||
let branch_commits = reorder_commit_list(subject_commit, offset, branch_commits)?;
|
|
||||||
|
|
||||||
// Rebase branch commits
|
// Rebase branch commits
|
||||||
// We are passing all the commits to the cherry_rebase_group funcion, but
|
// We are passing all the commits to the cherry_rebase_group funcion, but
|
||||||
// this is not a concern as it will verbaitm copy any commits that have
|
// this is not a concern as it will verbaitm copy any commits that have
|
||||||
// not had their parents changed.
|
// not had their parents changed.
|
||||||
let new_head_oid =
|
let new_head_oid = cherry_rebase_group(
|
||||||
cherry_rebase_group(repository, base_commit, &branch_commits, succeeding_rebases)?;
|
repository,
|
||||||
|
base_commit,
|
||||||
|
&reordered_commits,
|
||||||
|
succeeding_rebases,
|
||||||
|
)?;
|
||||||
|
|
||||||
// Rebase branch tree on top of new stack
|
// Calculate the new head and tree
|
||||||
let new_tree_commit =
|
let BranchHeadAndTree {
|
||||||
cherry_rebase_group(repository, new_head_oid, &[tree_commit], succeeding_rebases)?;
|
head: new_head_oid,
|
||||||
let new_tree_commit = repository.find_commit(new_tree_commit)?;
|
tree: new_tree_oid,
|
||||||
|
} = compute_updated_branch_head_for_commits(
|
||||||
|
repository,
|
||||||
|
branch_commits[0], // This function only operates on lists of 2 or greater
|
||||||
|
branch_tree.id(),
|
||||||
|
new_head_oid,
|
||||||
|
succeeding_rebases,
|
||||||
|
)?;
|
||||||
|
|
||||||
if new_tree_commit.is_conflicted() {
|
Ok(ReorderResult {
|
||||||
Ok(ReorderResult {
|
head: new_head_oid,
|
||||||
tree: repository
|
tree: new_tree_oid,
|
||||||
.find_real_tree(&new_tree_commit, Default::default())?
|
})
|
||||||
.id(),
|
|
||||||
head: new_tree_commit.id(),
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Ok(ReorderResult {
|
|
||||||
tree: new_tree_commit.tree_id(),
|
|
||||||
head: new_head_oid,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reorder_commit_list(
|
fn reorder_commit_list(
|
||||||
|
@ -1,10 +1,7 @@
|
|||||||
use anyhow::{anyhow, bail, Context, Result};
|
use anyhow::{anyhow, bail, Result};
|
||||||
use gitbutler_branch::{
|
use gitbutler_branch::{Branch, BranchId, Target, VirtualBranchesHandle};
|
||||||
signature, Branch, BranchId, SignaturePurpose, Target, VirtualBranchesHandle,
|
|
||||||
};
|
|
||||||
use gitbutler_cherry_pick::RepositoryExt as _;
|
use gitbutler_cherry_pick::RepositoryExt as _;
|
||||||
use gitbutler_command_context::CommandContext;
|
use gitbutler_command_context::CommandContext;
|
||||||
use gitbutler_commit::commit_ext::CommitExt;
|
|
||||||
use gitbutler_project::access::WorktreeWritePermission;
|
use gitbutler_project::access::WorktreeWritePermission;
|
||||||
use gitbutler_repo::{
|
use gitbutler_repo::{
|
||||||
rebase::{cherry_rebase_group, gitbutler_merge_commits},
|
rebase::{cherry_rebase_group, gitbutler_merge_commits},
|
||||||
@ -12,7 +9,10 @@ use gitbutler_repo::{
|
|||||||
};
|
};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{branch_trees::checkout_branch_trees, BranchManagerExt, VirtualBranchesExt as _};
|
use crate::{
|
||||||
|
branch_trees::{checkout_branch_trees, compute_updated_branch_head, BranchHeadAndTree},
|
||||||
|
BranchManagerExt, VirtualBranchesExt as _,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Serialize, PartialEq, Debug)]
|
#[derive(Serialize, PartialEq, Debug)]
|
||||||
#[serde(tag = "type", content = "subject", rename_all = "camelCase")]
|
#[serde(tag = "type", content = "subject", rename_all = "camelCase")]
|
||||||
@ -432,47 +432,24 @@ fn compute_resolutions(
|
|||||||
target_branch_name,
|
target_branch_name,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let head = repository.find_commit(virtual_branch.head)?;
|
// Get the updated tree oid
|
||||||
let tree = repository.find_tree(virtual_branch.tree)?;
|
let BranchHeadAndTree {
|
||||||
|
head: new_head,
|
||||||
// Rebase tree
|
tree: new_tree,
|
||||||
let author_signature = signature(SignaturePurpose::Author)
|
} = compute_updated_branch_head(
|
||||||
.context("Failed to get gitbutler signature")?;
|
repository,
|
||||||
let committer_signature = signature(SignaturePurpose::Committer)
|
virtual_branch,
|
||||||
.context("Failed to get gitbutler signature")?;
|
new_head.id(),
|
||||||
let committed_tree = repository.commit(
|
true,
|
||||||
None,
|
|
||||||
&author_signature,
|
|
||||||
&committer_signature,
|
|
||||||
"Uncommited changes",
|
|
||||||
&tree,
|
|
||||||
&[&head],
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// Rebase commited tree
|
Ok((
|
||||||
let new_commited_tree =
|
virtual_branch.id,
|
||||||
cherry_rebase_group(repository, new_head.id(), &[committed_tree], true)?;
|
IntegrationResult::UpdatedObjects {
|
||||||
let new_commited_tree = repository.find_commit(new_commited_tree)?;
|
head: new_head,
|
||||||
|
tree: new_tree,
|
||||||
if new_commited_tree.is_conflicted() {
|
},
|
||||||
Ok((
|
))
|
||||||
virtual_branch.id,
|
|
||||||
IntegrationResult::UpdatedObjects {
|
|
||||||
head: new_commited_tree.id(),
|
|
||||||
tree: repository
|
|
||||||
.find_real_tree(&new_commited_tree, Default::default())?
|
|
||||||
.id(),
|
|
||||||
},
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
Ok((
|
|
||||||
virtual_branch.id,
|
|
||||||
IntegrationResult::UpdatedObjects {
|
|
||||||
head: new_head.id(),
|
|
||||||
tree: new_commited_tree.tree_id(),
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
ResolutionApproach::Rebase => {
|
ResolutionApproach::Rebase => {
|
||||||
// Rebase the commits, then try rebasing the tree. If
|
// Rebase the commits, then try rebasing the tree. If
|
||||||
@ -497,47 +474,19 @@ fn compute_resolutions(
|
|||||||
true,
|
true,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let head = repository.find_commit(virtual_branch.head)?;
|
// Get the updated tree oid
|
||||||
let tree = repository.find_tree(virtual_branch.tree)?;
|
let BranchHeadAndTree {
|
||||||
|
head: new_head,
|
||||||
|
tree: new_tree,
|
||||||
|
} = compute_updated_branch_head(repository, virtual_branch, new_head, true)?;
|
||||||
|
|
||||||
// Rebase tree
|
Ok((
|
||||||
let author_signature = signature(SignaturePurpose::Author)
|
virtual_branch.id,
|
||||||
.context("Failed to get gitbutler signature")?;
|
IntegrationResult::UpdatedObjects {
|
||||||
let committer_signature = signature(SignaturePurpose::Committer)
|
head: new_head,
|
||||||
.context("Failed to get gitbutler signature")?;
|
tree: new_tree,
|
||||||
let committed_tree = repository.commit(
|
},
|
||||||
None,
|
))
|
||||||
&author_signature,
|
|
||||||
&committer_signature,
|
|
||||||
"Uncommited changes",
|
|
||||||
&tree,
|
|
||||||
&[&head],
|
|
||||||
)?;
|
|
||||||
|
|
||||||
// Rebase commited tree
|
|
||||||
let new_commited_tree =
|
|
||||||
cherry_rebase_group(repository, new_head, &[committed_tree], true)?;
|
|
||||||
let new_commited_tree = repository.find_commit(new_commited_tree)?;
|
|
||||||
|
|
||||||
if new_commited_tree.is_conflicted() {
|
|
||||||
Ok((
|
|
||||||
virtual_branch.id,
|
|
||||||
IntegrationResult::UpdatedObjects {
|
|
||||||
head: new_commited_tree.id(),
|
|
||||||
tree: repository
|
|
||||||
.find_real_tree(&new_commited_tree, Default::default())?
|
|
||||||
.id(),
|
|
||||||
},
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
Ok((
|
|
||||||
virtual_branch.id,
|
|
||||||
IntegrationResult::UpdatedObjects {
|
|
||||||
head: new_head,
|
|
||||||
tree: new_commited_tree.tree_id(),
|
|
||||||
},
|
|
||||||
))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -549,6 +498,7 @@ fn compute_resolutions(
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use gitbutler_branch::BranchOwnershipClaims;
|
use gitbutler_branch::BranchOwnershipClaims;
|
||||||
|
use gitbutler_commit::commit_ext::CommitExt as _;
|
||||||
use gitbutler_testsupport::testing_repository::TestingRepository;
|
use gitbutler_testsupport::testing_repository::TestingRepository;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
@ -0,0 +1,138 @@
|
|||||||
|
use gitbutler_branch::{Branch, BranchOwnershipClaims};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
/// Makes a Branch struct with a bunch of default values.
|
||||||
|
///
|
||||||
|
/// This assumes that the only relevant properties for your test are the head
|
||||||
|
/// and tree Oids.
|
||||||
|
fn make_branch(head: git2::Oid, tree: git2::Oid) -> Branch {
|
||||||
|
Branch {
|
||||||
|
id: Uuid::new_v4().into(),
|
||||||
|
name: "branchy branch".into(),
|
||||||
|
notes: "bla bla bla".into(),
|
||||||
|
source_refname: None,
|
||||||
|
upstream: None,
|
||||||
|
upstream_head: None,
|
||||||
|
created_timestamp_ms: 69420,
|
||||||
|
updated_timestamp_ms: 69420,
|
||||||
|
tree,
|
||||||
|
head,
|
||||||
|
ownership: BranchOwnershipClaims::default(),
|
||||||
|
order: 0,
|
||||||
|
selected_for_changes: None,
|
||||||
|
allow_rebasing: true,
|
||||||
|
in_workspace: true,
|
||||||
|
not_in_workspace_wip_change_id: None,
|
||||||
|
heads: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod compute_updated_branch_head {
|
||||||
|
use super::*;
|
||||||
|
use gitbutler_branch_actions::branch_trees::{compute_updated_branch_head, BranchHeadAndTree};
|
||||||
|
use gitbutler_cherry_pick::RepositoryExt as _;
|
||||||
|
use gitbutler_commit::commit_ext::CommitExt;
|
||||||
|
use gitbutler_testsupport::testing_repository::{
|
||||||
|
assert_commit_tree_matches, assert_tree_matches, TestingRepository,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// When the head ID is the same as the branch ID, we should return the same Oids.
|
||||||
|
#[test]
|
||||||
|
fn head_id_is_the_same() {
|
||||||
|
let test_repository = TestingRepository::open();
|
||||||
|
|
||||||
|
let base_commit = test_repository.commit_tree(None, &[("foo.txt", "foo")]);
|
||||||
|
let head = test_repository.commit_tree(Some(&base_commit), &[("foo.txt", "bar")]);
|
||||||
|
let tree = test_repository.commit_tree(Some(&head), &[("foo.txt", "baz")]);
|
||||||
|
|
||||||
|
let branch = make_branch(head.id(), tree.tree_id());
|
||||||
|
|
||||||
|
let BranchHeadAndTree { head, tree } =
|
||||||
|
compute_updated_branch_head(&test_repository.repository, &branch, head.id(), true)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(head, branch.head);
|
||||||
|
assert_eq!(tree, branch.tree);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// When the head ID is different from the branch ID, we should rebase the
|
||||||
|
/// tree on top of it.
|
||||||
|
///
|
||||||
|
/// This test is set up such that the tree won't be conflicted.
|
||||||
|
///
|
||||||
|
/// We expect to see the head commit match what we passed in as the new
|
||||||
|
/// head, and the tree should rebased on top of that new head.
|
||||||
|
#[test]
|
||||||
|
fn head_id_is_different() {
|
||||||
|
let test_repository = TestingRepository::open();
|
||||||
|
|
||||||
|
let base_commit = test_repository.commit_tree(None, &[("foo.txt", "foo")]);
|
||||||
|
let head = test_repository.commit_tree(Some(&base_commit), &[("foo.txt", "bar")]);
|
||||||
|
let tree =
|
||||||
|
test_repository.commit_tree(Some(&head), &[("foo.txt", "bar"), ("bar.txt", "baz")]);
|
||||||
|
|
||||||
|
let branch = make_branch(head.id(), tree.tree_id());
|
||||||
|
|
||||||
|
let new_head = test_repository.commit_tree(Some(&base_commit), &[("foo.txt", "new")]);
|
||||||
|
|
||||||
|
let BranchHeadAndTree { head, tree } =
|
||||||
|
compute_updated_branch_head(&test_repository.repository, &branch, new_head.id(), true)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
assert_eq!(head, new_head.id());
|
||||||
|
assert_tree_matches(
|
||||||
|
&test_repository.repository,
|
||||||
|
&test_repository.repository.find_tree(tree).unwrap(),
|
||||||
|
&[("foo.txt", b"new"), ("bar.txt", b"baz")],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// When the head ID is different from the branch ID and the new head will
|
||||||
|
/// conflict with the tree.
|
||||||
|
///
|
||||||
|
/// In this case we should expect to receive a new head commit that is the
|
||||||
|
/// conflicted result of the rebase, and the tree will the the
|
||||||
|
/// auto-resolved tree of that new head commit.
|
||||||
|
#[test]
|
||||||
|
fn tree_conflicts() {
|
||||||
|
let test_repository = TestingRepository::open();
|
||||||
|
|
||||||
|
let base_commit = test_repository.commit_tree(None, &[("foo.txt", "foo")]);
|
||||||
|
let head = test_repository.commit_tree(Some(&base_commit), &[("foo.txt", "bar")]);
|
||||||
|
let tree = test_repository.commit_tree(Some(&head), &[("foo.txt", "baz")]);
|
||||||
|
|
||||||
|
let branch = make_branch(head.id(), tree.tree_id());
|
||||||
|
|
||||||
|
let new_head = test_repository.commit_tree(Some(&base_commit), &[("foo.txt", "new")]);
|
||||||
|
|
||||||
|
let BranchHeadAndTree { head, tree } =
|
||||||
|
compute_updated_branch_head(&test_repository.repository, &branch, new_head.id(), true)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let new_new_head = test_repository.repository.find_commit(head).unwrap();
|
||||||
|
assert!(new_new_head.is_conflicted());
|
||||||
|
assert_eq!(new_new_head.parent(0).unwrap().id(), new_head.id());
|
||||||
|
|
||||||
|
assert_commit_tree_matches(
|
||||||
|
&test_repository.repository,
|
||||||
|
&new_new_head,
|
||||||
|
&[
|
||||||
|
(".auto-resolution/foo.txt", b"new"), // Auto-resolves to new_head
|
||||||
|
(".conflict-base-0/foo.txt", b"bar"), // head is the base
|
||||||
|
(".conflict-side-0/foo.txt", b"new"), // new_head is the ours side
|
||||||
|
(".conflict-side-1/foo.txt", b"baz"), // tree is the theris side
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
// Tree should be the auto-resolved tree.
|
||||||
|
assert_eq!(
|
||||||
|
tree,
|
||||||
|
test_repository
|
||||||
|
.repository
|
||||||
|
.find_real_tree(&new_new_head, Default::default())
|
||||||
|
.unwrap()
|
||||||
|
.id()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -57,6 +57,7 @@ impl Test {
|
|||||||
|
|
||||||
mod amend;
|
mod amend;
|
||||||
mod apply_virtual_branch;
|
mod apply_virtual_branch;
|
||||||
|
mod branch_trees;
|
||||||
mod create_commit;
|
mod create_commit;
|
||||||
mod create_virtual_branch_from_branch;
|
mod create_virtual_branch_from_branch;
|
||||||
mod init;
|
mod init;
|
||||||
|
Loading…
Reference in New Issue
Block a user