mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-11-25 07:45:41 +03:00
Merge pull request #1180 from gitbutlerapp/fix-hunk-movement
Fix hunk movement
This commit is contained in:
commit
05557f69c5
@ -60,6 +60,7 @@ impl super::RunCommand for Commit {
|
|||||||
&app.project_repository(),
|
&app.project_repository(),
|
||||||
&commit_branch,
|
&commit_branch,
|
||||||
&message,
|
&message,
|
||||||
|
None,
|
||||||
)
|
)
|
||||||
.context("failed to commit")?;
|
.context("failed to commit")?;
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ use tracing::instrument;
|
|||||||
|
|
||||||
use crate::{error::Error, git};
|
use crate::{error::Error, git};
|
||||||
|
|
||||||
use super::controller::Controller;
|
use super::{branch::Ownership, controller::Controller};
|
||||||
|
|
||||||
#[tauri::command(async)]
|
#[tauri::command(async)]
|
||||||
#[instrument(skip(handle))]
|
#[instrument(skip(handle))]
|
||||||
@ -13,10 +13,11 @@ pub async fn commit_virtual_branch(
|
|||||||
project_id: &str,
|
project_id: &str,
|
||||||
branch: &str,
|
branch: &str,
|
||||||
message: &str,
|
message: &str,
|
||||||
|
ownership: Option<Ownership>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
handle
|
handle
|
||||||
.state::<Controller>()
|
.state::<Controller>()
|
||||||
.create_commit(project_id, branch, message)
|
.create_commit(project_id, branch, message, ownership.as_ref())
|
||||||
.await
|
.await
|
||||||
.map_err(Into::into)
|
.map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
@ -11,6 +11,8 @@ use crate::{
|
|||||||
projects, users, watcher,
|
projects, users, watcher,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use super::branch::Ownership;
|
||||||
|
|
||||||
pub struct Controller {
|
pub struct Controller {
|
||||||
local_data_dir: path::PathBuf,
|
local_data_dir: path::PathBuf,
|
||||||
semaphores: Arc<tokio::sync::Mutex<HashMap<String, Semaphore>>>,
|
semaphores: Arc<tokio::sync::Mutex<HashMap<String, Semaphore>>>,
|
||||||
@ -66,11 +68,18 @@ impl Controller {
|
|||||||
project_id: &str,
|
project_id: &str,
|
||||||
branch: &str,
|
branch: &str,
|
||||||
message: &str,
|
message: &str,
|
||||||
|
ownership: Option<&Ownership>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
self.with_lock(project_id, || {
|
self.with_lock(project_id, || {
|
||||||
self.with_verify_branch(project_id, |gb_repository, project_repository| {
|
self.with_verify_branch(project_id, |gb_repository, project_repository| {
|
||||||
super::commit(gb_repository, project_repository, branch, message)
|
super::commit(
|
||||||
.map_err(Error::Other)
|
gb_repository,
|
||||||
|
project_repository,
|
||||||
|
branch,
|
||||||
|
message,
|
||||||
|
ownership,
|
||||||
|
)
|
||||||
|
.map_err(Error::Other)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
.await
|
.await
|
||||||
|
@ -115,7 +115,13 @@ fn test_commit_on_branch_then_change_file_then_get_status() -> Result<()> {
|
|||||||
assert_eq!(branch.commits.len(), 0);
|
assert_eq!(branch.commits.len(), 0);
|
||||||
|
|
||||||
// commit
|
// commit
|
||||||
commit(&gb_repo, &project_repository, &branch1_id, "test commit")?;
|
commit(
|
||||||
|
&gb_repo,
|
||||||
|
&project_repository,
|
||||||
|
&branch1_id,
|
||||||
|
"test commit",
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
|
||||||
// status (no files)
|
// status (no files)
|
||||||
let branches = list_virtual_branches(&gb_repo, &project_repository)?;
|
let branches = list_virtual_branches(&gb_repo, &project_repository)?;
|
||||||
@ -205,7 +211,13 @@ fn test_track_binary_files() -> Result<()> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// commit
|
// commit
|
||||||
commit(&gb_repo, &project_repository, &branch1_id, "test commit")?;
|
commit(
|
||||||
|
&gb_repo,
|
||||||
|
&project_repository,
|
||||||
|
&branch1_id,
|
||||||
|
"test commit",
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
|
||||||
// status (no files)
|
// status (no files)
|
||||||
let branches = list_virtual_branches(&gb_repo, &project_repository).unwrap();
|
let branches = list_virtual_branches(&gb_repo, &project_repository).unwrap();
|
||||||
@ -226,7 +238,13 @@ fn test_track_binary_files() -> Result<()> {
|
|||||||
file.write_all(&image_data)?;
|
file.write_all(&image_data)?;
|
||||||
|
|
||||||
// commit
|
// commit
|
||||||
commit(&gb_repo, &project_repository, &branch1_id, "test commit")?;
|
commit(
|
||||||
|
&gb_repo,
|
||||||
|
&project_repository,
|
||||||
|
&branch1_id,
|
||||||
|
"test commit",
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
|
||||||
let branches = list_virtual_branches(&gb_repo, &project_repository).unwrap();
|
let branches = list_virtual_branches(&gb_repo, &project_repository).unwrap();
|
||||||
let commit_id = &branches[0].commits[0].id;
|
let commit_id = &branches[0].commits[0].id;
|
||||||
@ -1040,7 +1058,13 @@ fn test_update_base_branch_base() -> Result<()> {
|
|||||||
.expect("failed to create virtual branch")
|
.expect("failed to create virtual branch")
|
||||||
.id;
|
.id;
|
||||||
|
|
||||||
commit(&gb_repo, &project_repository, &branch1_id, "test commit")?;
|
commit(
|
||||||
|
&gb_repo,
|
||||||
|
&project_repository,
|
||||||
|
&branch1_id,
|
||||||
|
"test commit",
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
|
||||||
std::fs::write(
|
std::fs::write(
|
||||||
std::path::Path::new(&project.path).join(file_path2),
|
std::path::Path::new(&project.path).join(file_path2),
|
||||||
@ -1143,7 +1167,13 @@ fn test_update_base_branch_detect_integrated_branches() -> Result<()> {
|
|||||||
"line1\nline2\nline3\nline4\nupstream\n",
|
"line1\nline2\nline3\nline4\nupstream\n",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
commit(&gb_repo, &project_repository, &branch1_id, "test commit")?;
|
commit(
|
||||||
|
&gb_repo,
|
||||||
|
&project_repository,
|
||||||
|
&branch1_id,
|
||||||
|
"test commit",
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
|
||||||
// add something to the branch
|
// add something to the branch
|
||||||
let branches = list_virtual_branches(&gb_repo, &project_repository)?;
|
let branches = list_virtual_branches(&gb_repo, &project_repository)?;
|
||||||
@ -1213,7 +1243,13 @@ fn test_update_base_branch_detect_integrated_branches_with_more_work() -> Result
|
|||||||
"update target",
|
"update target",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
commit(&gb_repo, &project_repository, &branch1_id, "test commit")?;
|
commit(
|
||||||
|
&gb_repo,
|
||||||
|
&project_repository,
|
||||||
|
&branch1_id,
|
||||||
|
"test commit",
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
|
||||||
// add some uncommitted work
|
// add some uncommitted work
|
||||||
std::fs::write(
|
std::fs::write(
|
||||||
@ -1462,6 +1498,7 @@ fn test_update_target_with_conflicts_in_vbranches() -> Result<()> {
|
|||||||
&project_repository,
|
&project_repository,
|
||||||
&branch7_id,
|
&branch7_id,
|
||||||
"integrated commit",
|
"integrated commit",
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
unapply_branch(&gb_repo, &project_repository, &branch7_id)?;
|
unapply_branch(&gb_repo, &project_repository, &branch7_id)?;
|
||||||
@ -1510,6 +1547,7 @@ fn test_update_target_with_conflicts_in_vbranches() -> Result<()> {
|
|||||||
&project_repository,
|
&project_repository,
|
||||||
&branch2_id,
|
&branch2_id,
|
||||||
"commit conflicts",
|
"commit conflicts",
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
std::fs::write(
|
std::fs::write(
|
||||||
std::path::Path::new(&project.path).join(file_path),
|
std::path::Path::new(&project.path).join(file_path),
|
||||||
@ -1567,6 +1605,7 @@ fn test_update_target_with_conflicts_in_vbranches() -> Result<()> {
|
|||||||
&project_repository,
|
&project_repository,
|
||||||
&branch5_id,
|
&branch5_id,
|
||||||
"broken, but will fix",
|
"broken, but will fix",
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
std::fs::write(
|
std::fs::write(
|
||||||
std::path::Path::new(&project.path).join(file_path3),
|
std::path::Path::new(&project.path).join(file_path3),
|
||||||
@ -2038,6 +2077,7 @@ fn test_detect_remote_commits() -> Result<()> {
|
|||||||
&project_repository,
|
&project_repository,
|
||||||
&branch1_id,
|
&branch1_id,
|
||||||
"upstream commit 1",
|
"upstream commit 1",
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// create another commit to push upstream
|
// create another commit to push upstream
|
||||||
@ -2051,6 +2091,7 @@ fn test_detect_remote_commits() -> Result<()> {
|
|||||||
&project_repository,
|
&project_repository,
|
||||||
&branch1_id,
|
&branch1_id,
|
||||||
"upstream commit 2",
|
"upstream commit 2",
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// push the commit upstream
|
// push the commit upstream
|
||||||
@ -2070,7 +2111,13 @@ fn test_detect_remote_commits() -> Result<()> {
|
|||||||
"line1\nline2\nline3\nline4\nupstream\nmore upstream\nmore work\n",
|
"line1\nline2\nline3\nline4\nupstream\nmore upstream\nmore work\n",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
commit(&gb_repo, &project_repository, &branch1_id, "local commit")?;
|
commit(
|
||||||
|
&gb_repo,
|
||||||
|
&project_repository,
|
||||||
|
&branch1_id,
|
||||||
|
"local commit",
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
|
||||||
let branches = list_virtual_branches(&gb_repo, &project_repository)?;
|
let branches = list_virtual_branches(&gb_repo, &project_repository)?;
|
||||||
assert_eq!(branches.len(), 1);
|
assert_eq!(branches.len(), 1);
|
||||||
@ -2425,12 +2472,14 @@ fn test_upstream_integrated_vbranch() -> Result<()> {
|
|||||||
&project_repository,
|
&project_repository,
|
||||||
&branch1_id,
|
&branch1_id,
|
||||||
"integrated commit",
|
"integrated commit",
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
commit(
|
commit(
|
||||||
&gb_repo,
|
&gb_repo,
|
||||||
&project_repository,
|
&project_repository,
|
||||||
&branch2_id,
|
&branch2_id,
|
||||||
"non-integrated commit",
|
"non-integrated commit",
|
||||||
|
None,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let branches = list_virtual_branches(&gb_repo, &project_repository)?;
|
let branches = list_virtual_branches(&gb_repo, &project_repository)?;
|
||||||
@ -2475,9 +2524,6 @@ fn test_partial_commit() -> Result<()> {
|
|||||||
let branch1_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
|
let branch1_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
|
||||||
.expect("failed to create virtual branch")
|
.expect("failed to create virtual branch")
|
||||||
.id;
|
.id;
|
||||||
let branch2_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
|
|
||||||
.expect("failed to create virtual branch")
|
|
||||||
.id;
|
|
||||||
|
|
||||||
// create a change with two hunks
|
// create a change with two hunks
|
||||||
std::fs::write(
|
std::fs::write(
|
||||||
@ -2485,90 +2531,104 @@ fn test_partial_commit() -> Result<()> {
|
|||||||
"line1\npatch1\nline2\nline3\nline4\nline5\nmiddle\nmiddle\nmiddle\nmiddle\nline6\npatch2\nline7\nline8\nline9\nline10\nmiddle\nmiddle\nmiddle\nmiddle\nline11\nline12\npatch3\n",
|
"line1\npatch1\nline2\nline3\nline4\nline5\nmiddle\nmiddle\nmiddle\nmiddle\nline6\npatch2\nline7\nline8\nline9\nline10\nmiddle\nmiddle\nmiddle\nmiddle\nline11\nline12\npatch3\n",
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
// move hunk1 and hunk3 to branch2
|
|
||||||
let current_session = gb_repo.get_or_create_current_session()?;
|
|
||||||
let current_session_reader = sessions::Reader::open(&gb_repo, ¤t_session)?;
|
|
||||||
let branch_reader = branch::Reader::new(¤t_session_reader);
|
|
||||||
let branch_writer = branch::Writer::new(&gb_repo);
|
|
||||||
let branch2 = branch_reader.read(&branch2_id)?;
|
|
||||||
branch_writer.write(&branch::Branch {
|
|
||||||
ownership: Ownership {
|
|
||||||
files: vec!["test.txt:9-16".parse()?],
|
|
||||||
},
|
|
||||||
..branch2
|
|
||||||
})?;
|
|
||||||
let branch1 = branch_reader.read(&branch1_id)?;
|
|
||||||
branch_writer.write(&branch::Branch {
|
|
||||||
ownership: Ownership {
|
|
||||||
files: vec!["test.txt:1-6".parse()?, "test.txt:17-24".parse()?],
|
|
||||||
},
|
|
||||||
..branch1
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let branches = list_virtual_branches(&gb_repo, &project_repository)?;
|
let branches = list_virtual_branches(&gb_repo, &project_repository)?;
|
||||||
let branch1 = &branches.iter().find(|b| b.id == branch1_id).unwrap();
|
let branch = &branches.iter().find(|b| b.id == branch1_id).unwrap();
|
||||||
assert_eq!(branch1.files[0].hunks.len(), 2);
|
|
||||||
let branch2 = &branches.iter().find(|b| b.id == branch2_id).unwrap();
|
assert_eq!(branch.files.len(), 1);
|
||||||
assert_eq!(branch2.files[0].hunks.len(), 1);
|
assert_eq!(branch.files[0].hunks.len(), 3);
|
||||||
|
assert_eq!(branch.commits.len(), 0);
|
||||||
|
|
||||||
// commit
|
// commit
|
||||||
commit(&gb_repo, &project_repository, &branch1_id, "branch1 commit")?;
|
commit(
|
||||||
commit(&gb_repo, &project_repository, &branch2_id, "branch2 commit")?;
|
&gb_repo,
|
||||||
|
&project_repository,
|
||||||
|
&branch1_id,
|
||||||
|
"partial commit",
|
||||||
|
Some(&"test.txt:17-24".parse::<Ownership>().unwrap()),
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let branches = list_virtual_branches(&gb_repo, &project_repository)?;
|
||||||
|
let branch = &branches.iter().find(|b| b.id == branch1_id).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(branch.files.len(), 1);
|
||||||
|
assert_eq!(branch.files[0].hunks.len(), 2);
|
||||||
|
|
||||||
|
assert_eq!(branch.commits.len(), 1);
|
||||||
|
assert_eq!(branch.commits[0].files.len(), 1);
|
||||||
|
assert_eq!(branch.commits[0].files[0].hunks.len(), 1);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_commit_partial() -> Result<()> {
|
||||||
|
let TestDeps {
|
||||||
|
repository,
|
||||||
|
project,
|
||||||
|
gb_repo,
|
||||||
|
..
|
||||||
|
} = new_test_deps()?;
|
||||||
|
let project_repository = project_repository::Repository::open(&project)?;
|
||||||
|
|
||||||
|
let file_path = std::path::Path::new("test.txt");
|
||||||
|
std::fs::write(
|
||||||
|
std::path::Path::new(&project.path).join(file_path),
|
||||||
|
"file1\n",
|
||||||
|
)?;
|
||||||
|
let file_path2 = std::path::Path::new("test2.txt");
|
||||||
|
std::fs::write(
|
||||||
|
std::path::Path::new(&project.path).join(file_path2),
|
||||||
|
"file2\n",
|
||||||
|
)?;
|
||||||
|
test_utils::commit_all(&repository);
|
||||||
|
|
||||||
|
let commit1_oid = repository.head().unwrap().target().unwrap();
|
||||||
|
let commit1 = repository.find_commit(commit1_oid).unwrap();
|
||||||
|
|
||||||
|
set_test_target(&gb_repo, &project_repository, &repository)?;
|
||||||
|
|
||||||
|
// remove file
|
||||||
|
std::fs::remove_file(std::path::Path::new(&project.path).join(file_path2))?;
|
||||||
|
// add new file
|
||||||
|
let file_path3 = std::path::Path::new("test3.txt");
|
||||||
|
std::fs::write(
|
||||||
|
std::path::Path::new(&project.path).join(file_path3),
|
||||||
|
"file3\n",
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let branch1_id = create_virtual_branch(&gb_repo, &BranchCreateRequest::default())
|
||||||
|
.expect("failed to create virtual branch")
|
||||||
|
.id;
|
||||||
|
|
||||||
|
// commit
|
||||||
|
commit(
|
||||||
|
&gb_repo,
|
||||||
|
&project_repository,
|
||||||
|
&branch1_id,
|
||||||
|
"branch1 commit",
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
|
||||||
let branches = list_virtual_branches(&gb_repo, &project_repository)?;
|
let branches = list_virtual_branches(&gb_repo, &project_repository)?;
|
||||||
let branch1 = &branches.iter().find(|b| b.id == branch1_id).unwrap();
|
let branch1 = &branches.iter().find(|b| b.id == branch1_id).unwrap();
|
||||||
let branch2 = &branches.iter().find(|b| b.id == branch2_id).unwrap();
|
|
||||||
|
|
||||||
// branch one test.txt has just the 1st and 3rd hunks applied
|
// branch one test.txt has just the 1st and 3rd hunks applied
|
||||||
assert_eq!(
|
let commit2 = &branch1.commits[0].id;
|
||||||
branch1.commits[0].files[0]
|
let commit2 = commit2
|
||||||
.path
|
.parse::<git::Oid>()
|
||||||
.display()
|
.expect("failed to parse commit id");
|
||||||
.to_string()
|
let commit2 = repository
|
||||||
.as_str(),
|
.find_commit(commit2)
|
||||||
"test.txt"
|
.expect("failed to get commit object");
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
branch1.commits[0].files[0].hunks[0].diff,
|
|
||||||
"@@ -1,4 +1,5 @@\n line1\n+patch1\n line2\n line3\n line4\n"
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
branch1.commits[0].files[0].hunks[1].diff,
|
|
||||||
"@@ -15,5 +16,7 @@ line10\n middle\n middle\n middle\n+middle\n line11\n line12\n+patch3\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
// branch two test.txt has just the middle hunk applied
|
let tree = commit1.tree().expect("failed to get tree");
|
||||||
assert_eq!(
|
let file_list = tree_to_file_list(&repository, &tree);
|
||||||
branch2.commits[0].files[0]
|
assert_eq!(file_list, vec!["test.txt", "test2.txt"]);
|
||||||
.path
|
|
||||||
.display()
|
|
||||||
.to_string()
|
|
||||||
.as_str(),
|
|
||||||
"test.txt"
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
branch2.commits[0].files[0].hunks[0].diff,
|
|
||||||
"@@ -8,6 +8,7 @@ middle\n middle\n middle\n line6\n+patch2\n line7\n line8\n line9\n"
|
|
||||||
);
|
|
||||||
|
|
||||||
// ok, now we're going to unapply branch1, which should remove the 1st and 3rd hunks
|
// get the tree
|
||||||
unapply_branch(&gb_repo, &project_repository, &branch1_id)?;
|
let tree = commit2.tree().expect("failed to get tree");
|
||||||
// read contents of test.txt
|
let file_list = tree_to_file_list(&repository, &tree);
|
||||||
let contents = std::fs::read_to_string(std::path::Path::new(&project.path).join(file_path))?;
|
assert_eq!(file_list, vec!["test.txt", "test3.txt"]);
|
||||||
assert_eq!(contents, "line1\nline2\nline3\nline4\nline5\nmiddle\nmiddle\nmiddle\nmiddle\nline6\npatch2\nline7\nline8\nline9\nline10\nmiddle\nmiddle\nmiddle\nline11\nline12\n");
|
|
||||||
|
|
||||||
// ok, now we're going to re-apply branch1, which adds hunk 1 and 3, then unapply branch2, which should remove the middle hunk
|
|
||||||
apply_branch(&gb_repo, &project_repository, &branch1_id)?;
|
|
||||||
unapply_branch(&gb_repo, &project_repository, &branch2_id)?;
|
|
||||||
|
|
||||||
let contents = std::fs::read_to_string(std::path::Path::new(&project.path).join(file_path))?;
|
|
||||||
assert_eq!(contents, "line1\npatch1\nline2\nline3\nline4\nline5\nmiddle\nmiddle\nmiddle\nmiddle\nline6\nline7\nline8\nline9\nline10\nmiddle\nmiddle\nmiddle\nmiddle\nline11\nline12\npatch3\n");
|
|
||||||
|
|
||||||
// finally, reapply the middle hunk on branch2, so we have all of them again
|
|
||||||
apply_branch(&gb_repo, &project_repository, &branch2_id)?;
|
|
||||||
|
|
||||||
let contents = std::fs::read_to_string(std::path::Path::new(&project.path).join(file_path))?;
|
|
||||||
assert_eq!(contents, "line1\npatch1\nline2\nline3\nline4\nline5\nmiddle\nmiddle\nmiddle\nmiddle\nline6\npatch2\nline7\nline8\nline9\nline10\nmiddle\nmiddle\nmiddle\nmiddle\nline11\nline12\npatch3\n");
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -2614,7 +2674,13 @@ fn test_commit_add_and_delete_files() -> Result<()> {
|
|||||||
.id;
|
.id;
|
||||||
|
|
||||||
// commit
|
// commit
|
||||||
commit(&gb_repo, &project_repository, &branch1_id, "branch1 commit")?;
|
commit(
|
||||||
|
&gb_repo,
|
||||||
|
&project_repository,
|
||||||
|
&branch1_id,
|
||||||
|
"branch1 commit",
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
|
||||||
let branches = list_virtual_branches(&gb_repo, &project_repository)?;
|
let branches = list_virtual_branches(&gb_repo, &project_repository)?;
|
||||||
let branch1 = &branches.iter().find(|b| b.id == branch1_id).unwrap();
|
let branch1 = &branches.iter().find(|b| b.id == branch1_id).unwrap();
|
||||||
@ -2683,7 +2749,13 @@ fn test_commit_executable_and_symlinks() -> Result<()> {
|
|||||||
.id;
|
.id;
|
||||||
|
|
||||||
// commit
|
// commit
|
||||||
commit(&gb_repo, &project_repository, &branch1_id, "branch1 commit")?;
|
commit(
|
||||||
|
&gb_repo,
|
||||||
|
&project_repository,
|
||||||
|
&branch1_id,
|
||||||
|
"branch1 commit",
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
|
||||||
let branches = list_virtual_branches(&gb_repo, &project_repository)?;
|
let branches = list_virtual_branches(&gb_repo, &project_repository)?;
|
||||||
let branch1 = &branches.iter().find(|b| b.id == branch1_id).unwrap();
|
let branch1 = &branches.iter().find(|b| b.id == branch1_id).unwrap();
|
||||||
@ -3041,7 +3113,13 @@ fn test_apply_out_of_date_conflicting_vbranch() -> Result<()> {
|
|||||||
assert!(branch1.conflicted);
|
assert!(branch1.conflicted);
|
||||||
|
|
||||||
// try to commit, fail
|
// try to commit, fail
|
||||||
let result = commit(&gb_repo, &project_repository, branch_id, "resolve commit");
|
let result = commit(
|
||||||
|
&gb_repo,
|
||||||
|
&project_repository,
|
||||||
|
branch_id,
|
||||||
|
"resolve commit",
|
||||||
|
None,
|
||||||
|
);
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
|
|
||||||
// fix the conflict and commit it
|
// fix the conflict and commit it
|
||||||
@ -3060,7 +3138,13 @@ fn test_apply_out_of_date_conflicting_vbranch() -> Result<()> {
|
|||||||
assert!(branch1.active);
|
assert!(branch1.active);
|
||||||
|
|
||||||
// commit
|
// commit
|
||||||
commit(&gb_repo, &project_repository, branch_id, "resolve commit")?;
|
commit(
|
||||||
|
&gb_repo,
|
||||||
|
&project_repository,
|
||||||
|
branch_id,
|
||||||
|
"resolve commit",
|
||||||
|
None,
|
||||||
|
)?;
|
||||||
|
|
||||||
let branches = list_virtual_branches(&gb_repo, &project_repository)?;
|
let branches = list_virtual_branches(&gb_repo, &project_repository)?;
|
||||||
let branch1 = &branches.iter().find(|b| &b.id == branch_id).unwrap();
|
let branch1 = &branches.iter().find(|b| &b.id == branch_id).unwrap();
|
||||||
|
@ -4,7 +4,7 @@ use std::{
|
|||||||
path, time, vec,
|
path, time, vec,
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{bail, Context, Result};
|
use anyhow::{anyhow, bail, Context, Result};
|
||||||
use diffy::{apply_bytes, Patch};
|
use diffy::{apply_bytes, Patch};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
|
||||||
@ -1818,6 +1818,7 @@ pub fn commit(
|
|||||||
project_repository: &project_repository::Repository,
|
project_repository: &project_repository::Repository,
|
||||||
branch_id: &str,
|
branch_id: &str,
|
||||||
message: &str,
|
message: &str,
|
||||||
|
ownership: Option<&branch::Ownership>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
if conflicts::is_conflicting(project_repository, None)? {
|
if conflicts::is_conflicting(project_repository, None)? {
|
||||||
bail!("cannot commit, project is in a conflicted state");
|
bail!("cannot commit, project is in a conflicted state");
|
||||||
@ -1832,70 +1833,99 @@ pub fn commit(
|
|||||||
let statuses = get_status_by_branch(gb_repository, project_repository)
|
let statuses = get_status_by_branch(gb_repository, project_repository)
|
||||||
.context("failed to get status by branch")?;
|
.context("failed to get status by branch")?;
|
||||||
|
|
||||||
match statuses.iter().find(|(branch, _)| branch.id == branch_id) {
|
let (branch, files) = statuses
|
||||||
None => bail!("branch {} not found", branch_id),
|
.iter()
|
||||||
Some((branch, files)) => {
|
.find(|(branch, _)| branch.id == branch_id)
|
||||||
let tree_oid = write_tree(project_repository, &default_target, files)?;
|
.ok_or_else(|| anyhow!("branch {} not found", branch_id))?;
|
||||||
|
|
||||||
let git_repository = &project_repository.git_repository;
|
let tree_oid = if let Some(ownership) = ownership {
|
||||||
let parent_commit = git_repository
|
let files = files
|
||||||
.find_commit(branch.head)
|
.iter()
|
||||||
.context(format!("failed to find commit {:?}", branch.head))?;
|
.filter_map(|file| {
|
||||||
let tree = git_repository
|
let hunks = file
|
||||||
.find_tree(tree_oid)
|
.hunks
|
||||||
.context(format!("failed to find tree {:?}", tree_oid))?;
|
.iter()
|
||||||
|
.filter(|hunk| {
|
||||||
// now write a commit, using a merge parent if it exists
|
ownership
|
||||||
let (author, committer) = gb_repository
|
.files
|
||||||
.git_signatures()
|
.iter()
|
||||||
.context("failed to get git signatures")?;
|
.find(|f| f.file_path == file.path)
|
||||||
let extra_merge_parent = conflicts::merge_parent(project_repository)
|
.map(|f| {
|
||||||
.context("failed to get merge parent")?;
|
f.hunks
|
||||||
|
.iter()
|
||||||
let commit_oid = match extra_merge_parent {
|
.any(|h| h.start == hunk.start && h.end == hunk.end)
|
||||||
Some(merge_parent) => {
|
})
|
||||||
let merge_parent = git_repository
|
.unwrap_or(false)
|
||||||
.find_commit(merge_parent)
|
})
|
||||||
.context(format!("failed to find merge parent {:?}", merge_parent))?;
|
.cloned()
|
||||||
let commit_oid = git_repository
|
.collect::<Vec<_>>();
|
||||||
.commit(
|
if hunks.is_empty() {
|
||||||
None,
|
None
|
||||||
&author,
|
} else {
|
||||||
&committer,
|
Some(VirtualBranchFile {
|
||||||
message,
|
hunks,
|
||||||
&tree,
|
..file.clone()
|
||||||
&[&parent_commit, &merge_parent],
|
})
|
||||||
)
|
|
||||||
.context("failed to commit")?;
|
|
||||||
conflicts::clear(project_repository).context("failed to clear conflicts")?;
|
|
||||||
commit_oid
|
|
||||||
}
|
}
|
||||||
None => git_repository.commit(
|
})
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
write_tree(project_repository, &default_target, &files)?
|
||||||
|
} else {
|
||||||
|
write_tree(project_repository, &default_target, files)?
|
||||||
|
};
|
||||||
|
|
||||||
|
let git_repository = &project_repository.git_repository;
|
||||||
|
let parent_commit = git_repository
|
||||||
|
.find_commit(branch.head)
|
||||||
|
.context(format!("failed to find commit {:?}", branch.head))?;
|
||||||
|
let tree = git_repository
|
||||||
|
.find_tree(tree_oid)
|
||||||
|
.context(format!("failed to find tree {:?}", tree_oid))?;
|
||||||
|
|
||||||
|
// now write a commit, using a merge parent if it exists
|
||||||
|
let (author, committer) = gb_repository
|
||||||
|
.git_signatures()
|
||||||
|
.context("failed to get git signatures")?;
|
||||||
|
let extra_merge_parent =
|
||||||
|
conflicts::merge_parent(project_repository).context("failed to get merge parent")?;
|
||||||
|
|
||||||
|
let commit_oid = match extra_merge_parent {
|
||||||
|
Some(merge_parent) => {
|
||||||
|
let merge_parent = git_repository
|
||||||
|
.find_commit(merge_parent)
|
||||||
|
.context(format!("failed to find merge parent {:?}", merge_parent))?;
|
||||||
|
let commit_oid = git_repository
|
||||||
|
.commit(
|
||||||
None,
|
None,
|
||||||
&author,
|
&author,
|
||||||
&committer,
|
&committer,
|
||||||
message,
|
message,
|
||||||
&tree,
|
&tree,
|
||||||
&[&parent_commit],
|
&[&parent_commit, &merge_parent],
|
||||||
)?,
|
)
|
||||||
};
|
.context("failed to commit")?;
|
||||||
|
conflicts::clear(project_repository).context("failed to clear conflicts")?;
|
||||||
// update the virtual branch head
|
commit_oid
|
||||||
let writer = branch::Writer::new(gb_repository);
|
|
||||||
writer
|
|
||||||
.write(&Branch {
|
|
||||||
tree: tree_oid,
|
|
||||||
head: commit_oid,
|
|
||||||
..branch.clone()
|
|
||||||
})
|
|
||||||
.context("failed to write branch")?;
|
|
||||||
|
|
||||||
super::integration::update_gitbutler_integration(gb_repository, project_repository)
|
|
||||||
.context("failed to update gitbutler integration")?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
None => {
|
||||||
|
git_repository.commit(None, &author, &committer, message, &tree, &[&parent_commit])?
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// update the virtual branch head
|
||||||
|
let writer = branch::Writer::new(gb_repository);
|
||||||
|
writer
|
||||||
|
.write(&Branch {
|
||||||
|
tree: tree_oid,
|
||||||
|
head: commit_oid,
|
||||||
|
..branch.clone()
|
||||||
|
})
|
||||||
|
.context("failed to write branch")?;
|
||||||
|
|
||||||
|
super::integration::update_gitbutler_integration(gb_repository, project_repository)
|
||||||
|
.context("failed to update gitbutler integration")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name_to_branch(name: &str) -> String {
|
pub fn name_to_branch(name: &str) -> String {
|
||||||
|
Loading…
Reference in New Issue
Block a user