mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-28 20:15:20 +03:00
ensure branch updated time is always up to date
This commit is contained in:
parent
82b861758c
commit
0cdf187115
@ -288,10 +288,8 @@ impl Repository {
|
||||
|
||||
// copy branches that we don't already have
|
||||
for branch in &branches {
|
||||
let branch_copy = branch.clone();
|
||||
//branch_copy.applied = false;
|
||||
dst_branch_writer
|
||||
.write(&branch_copy)
|
||||
.write(&mut branch.clone())
|
||||
.with_context(|| format!("{}: failed to write branch", branch.id))?;
|
||||
}
|
||||
|
||||
|
@ -176,7 +176,7 @@ pub fn set_base_branch(
|
||||
(None, None)
|
||||
};
|
||||
|
||||
let branch = branch::Branch {
|
||||
let mut branch = branch::Branch {
|
||||
id: BranchId::generate(),
|
||||
name: head_name.to_string().replace("refs/heads/", ""),
|
||||
notes: String::new(),
|
||||
@ -196,7 +196,7 @@ pub fn set_base_branch(
|
||||
};
|
||||
|
||||
let branch_writer = branch::Writer::new(gb_repository);
|
||||
branch_writer.write(&branch)?;
|
||||
branch_writer.write(&mut branch)?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -294,106 +294,174 @@ pub fn update_base_branch(
|
||||
let updated_vbranches = super::get_status_by_branch(gb_repository, project_repository)?
|
||||
.into_iter()
|
||||
.map(|(branch, _)| branch)
|
||||
.map(|branch: branch::Branch| -> Result<Option<branch::Branch>> {
|
||||
let branch_tree = repo.find_tree(branch.tree)?;
|
||||
.map(
|
||||
|mut branch: branch::Branch| -> Result<Option<branch::Branch>> {
|
||||
let branch_tree = repo.find_tree(branch.tree)?;
|
||||
|
||||
let mut branch_merge_index = repo
|
||||
.merge_trees(&old_target_tree, &branch_tree, &new_target_tree)
|
||||
.context(format!("failed to merge trees for branch {}", branch.id))?;
|
||||
let mut branch_merge_index = repo
|
||||
.merge_trees(&old_target_tree, &branch_tree, &new_target_tree)
|
||||
.context(format!("failed to merge trees for branch {}", branch.id))?;
|
||||
|
||||
if branch_merge_index.has_conflicts() {
|
||||
// branch tree conflicts with new target, unapply branch for now. we'll handle it later, when user applies it back.
|
||||
let branch = branch::Branch {
|
||||
applied: false,
|
||||
..branch
|
||||
};
|
||||
branch_writer.write(&branch)?;
|
||||
return Ok(Some(branch));
|
||||
}
|
||||
if branch_merge_index.has_conflicts() {
|
||||
// branch tree conflicts with new target, unapply branch for now. we'll handle it later, when user applies it back.
|
||||
branch.applied = false;
|
||||
branch_writer.write(&mut branch)?;
|
||||
return Ok(Some(branch));
|
||||
}
|
||||
|
||||
if branch.head == target.sha {
|
||||
// there are no commits on the branch, so we can just update the head to the new target and calculate the new tree
|
||||
let branch = branch::Branch {
|
||||
head: new_target_commit.id(),
|
||||
tree: branch_merge_index.write_tree_to(repo)?,
|
||||
..branch
|
||||
};
|
||||
branch_writer.write(&branch)?;
|
||||
return Ok(Some(branch));
|
||||
}
|
||||
if branch.head == target.sha {
|
||||
// there are no commits on the branch, so we can just update the head to the new target and calculate the new tree
|
||||
branch.head = new_target_commit.id();
|
||||
branch.tree = branch_merge_index.write_tree_to(repo)?;
|
||||
branch_writer.write(&mut branch)?;
|
||||
return Ok(Some(branch));
|
||||
}
|
||||
|
||||
// try to merge branch head with new target
|
||||
let branch_head_commit = repo.find_commit(branch.head).context(format!(
|
||||
"failed to find commit {} for branch {}",
|
||||
branch.head, branch.id
|
||||
))?;
|
||||
let branch_head_tree = branch_head_commit.tree().context(format!(
|
||||
"failed to find tree for commit {} for branch {}",
|
||||
branch.head, branch.id
|
||||
))?;
|
||||
let mut branch_head_merge_index = repo
|
||||
.merge_trees(&old_target_tree, &branch_head_tree, &new_target_tree)
|
||||
.context(format!(
|
||||
"failed to merge head tree for branch {}",
|
||||
branch.id
|
||||
// try to merge branch head with new target
|
||||
let branch_head_commit = repo.find_commit(branch.head).context(format!(
|
||||
"failed to find commit {} for branch {}",
|
||||
branch.head, branch.id
|
||||
))?;
|
||||
let branch_head_tree = branch_head_commit.tree().context(format!(
|
||||
"failed to find tree for commit {} for branch {}",
|
||||
branch.head, branch.id
|
||||
))?;
|
||||
let mut branch_head_merge_index = repo
|
||||
.merge_trees(&old_target_tree, &branch_head_tree, &new_target_tree)
|
||||
.context(format!(
|
||||
"failed to merge head tree for branch {}",
|
||||
branch.id
|
||||
))?;
|
||||
|
||||
if branch_head_merge_index.has_conflicts() {
|
||||
// branch commits conflict with new target, make sure the branch is
|
||||
// unapplied. conflicts witll be dealt with when applying it back.
|
||||
let branch = branch::Branch {
|
||||
applied: false,
|
||||
..branch
|
||||
};
|
||||
branch_writer.write(&branch)?;
|
||||
return Ok(Some(branch));
|
||||
}
|
||||
if branch_head_merge_index.has_conflicts() {
|
||||
// branch commits conflict with new target, make sure the branch is
|
||||
// unapplied. conflicts witll be dealt with when applying it back.
|
||||
branch.applied = false;
|
||||
branch_writer.write(&mut branch)?;
|
||||
return Ok(Some(branch));
|
||||
}
|
||||
|
||||
// branch commits do not conflict with new target, so lets merge them
|
||||
let branch_head_merge_tree_oid =
|
||||
branch_head_merge_index
|
||||
// branch commits do not conflict with new target, so lets merge them
|
||||
let branch_head_merge_tree_oid = branch_head_merge_index
|
||||
.write_tree_to(repo)
|
||||
.context(format!(
|
||||
"failed to write head merge index for {}",
|
||||
branch.id
|
||||
))?;
|
||||
|
||||
if branch_head_merge_tree_oid == new_target_tree.id() {
|
||||
// after merging the branch head with the new target the tree is the
|
||||
// same as the new target tree. meaning we can safely use the new target commit
|
||||
// as the new branch head.
|
||||
let non_commited_files = diff::trees(
|
||||
&project_repository.git_repository,
|
||||
&branch_head_tree,
|
||||
&branch_tree,
|
||||
)?;
|
||||
if non_commited_files.is_empty() {
|
||||
// if there are no commited files, then the branch is fully merged
|
||||
// and we can delete it.
|
||||
branch_writer.delete(&branch)?;
|
||||
project_repository.delete_branch_reference(&branch)?;
|
||||
return Ok(None);
|
||||
if branch_head_merge_tree_oid == new_target_tree.id() {
|
||||
// after merging the branch head with the new target the tree is the
|
||||
// same as the new target tree. meaning we can safely use the new target commit
|
||||
// as the new branch head.
|
||||
let non_commited_files = diff::trees(
|
||||
&project_repository.git_repository,
|
||||
&branch_head_tree,
|
||||
&branch_tree,
|
||||
)?;
|
||||
if non_commited_files.is_empty() {
|
||||
// if there are no commited files, then the branch is fully merged
|
||||
// and we can delete it.
|
||||
branch_writer.delete(&branch)?;
|
||||
project_repository.delete_branch_reference(&branch)?;
|
||||
return Ok(None);
|
||||
}
|
||||
// there are some uncommied files left. we should put them into the branch
|
||||
// tree.
|
||||
branch.head = new_target_commit.id();
|
||||
branch.tree = branch_merge_index.write_tree_to(repo)?;
|
||||
branch_writer.write(&mut branch)?;
|
||||
return Ok(Some(branch));
|
||||
}
|
||||
// there are some uncommied files left. we should put them into the branch
|
||||
// tree.
|
||||
let branch = branch::Branch {
|
||||
head: new_target_commit.id(),
|
||||
tree: branch_merge_index.write_tree_to(repo)?,
|
||||
..branch
|
||||
};
|
||||
branch_writer.write(&branch)?;
|
||||
return Ok(Some(branch));
|
||||
}
|
||||
|
||||
let ok_with_force_push = project_repository.project().ok_with_force_push;
|
||||
if branch.upstream.is_some() && !ok_with_force_push {
|
||||
// branch was pushed to upstream, and user doesn't like force pushing.
|
||||
// create a merge commit to avoid the need of force pushing then.
|
||||
let branch_head_merge_tree = repo
|
||||
let ok_with_force_push = project_repository.project().ok_with_force_push;
|
||||
if branch.upstream.is_some() && !ok_with_force_push {
|
||||
// branch was pushed to upstream, and user doesn't like force pushing.
|
||||
// create a merge commit to avoid the need of force pushing then.
|
||||
let branch_head_merge_tree = repo
|
||||
.find_tree(branch_head_merge_tree_oid)
|
||||
.context("failed to find tree")?;
|
||||
|
||||
let new_target_head = project_repository
|
||||
.commit(
|
||||
user,
|
||||
format!(
|
||||
"Merged {}/{} into {}",
|
||||
target.branch.remote(),
|
||||
target.branch.branch(),
|
||||
branch.name
|
||||
)
|
||||
.as_str(),
|
||||
&branch_head_merge_tree,
|
||||
&[&branch_head_commit, &new_target_commit],
|
||||
signing_key,
|
||||
)
|
||||
.context("failed to commit merge")?;
|
||||
|
||||
branch.head = new_target_head;
|
||||
branch.tree = branch_merge_index.write_tree_to(repo)?;
|
||||
branch_writer.write(&mut branch)?;
|
||||
return Ok(Some(branch));
|
||||
}
|
||||
|
||||
// branch was not pushed to upstream yet. attempt a rebase,
|
||||
let (_, committer) = project_repository.git_signatures(user)?;
|
||||
let annotated_branch_head = repo
|
||||
.find_annotated_commit(branch.head)
|
||||
.context("failed to find annotated commit")?;
|
||||
let annotated_upstream_base = repo
|
||||
.find_annotated_commit(new_target_commit.id())
|
||||
.context("failed to find annotated commit")?;
|
||||
let mut rebase_options = git2::RebaseOptions::new();
|
||||
rebase_options.quiet(true);
|
||||
rebase_options.inmemory(true);
|
||||
let mut rebase = repo
|
||||
.rebase(
|
||||
Some(&annotated_branch_head),
|
||||
Some(&annotated_upstream_base),
|
||||
None,
|
||||
Some(&mut rebase_options),
|
||||
)
|
||||
.context("failed to rebase")?;
|
||||
|
||||
let mut rebase_success = true;
|
||||
// check to see if these commits have already been pushed
|
||||
let mut last_rebase_head = branch.head;
|
||||
while rebase.next().is_some() {
|
||||
let index = rebase
|
||||
.inmemory_index()
|
||||
.context("failed to get inmemory index")?;
|
||||
if index.has_conflicts() {
|
||||
rebase_success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if let Ok(commit_id) = rebase.commit(None, &committer.clone().into(), None) {
|
||||
last_rebase_head = commit_id.into();
|
||||
} else {
|
||||
rebase_success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if rebase_success {
|
||||
// rebase worked out, rewrite the branch head
|
||||
rebase.finish(None).context("failed to finish rebase")?;
|
||||
branch.head = last_rebase_head;
|
||||
branch.tree = branch_merge_index.write_tree_to(repo)?;
|
||||
branch_writer.write(&mut branch)?;
|
||||
return Ok(Some(branch));
|
||||
}
|
||||
|
||||
// rebase failed, do a merge commit
|
||||
rebase.abort().context("failed to abort rebase")?;
|
||||
|
||||
// get tree from merge_tree_oid
|
||||
let merge_tree = repo
|
||||
.find_tree(branch_head_merge_tree_oid)
|
||||
.context("failed to find tree")?;
|
||||
|
||||
let new_target_head = project_repository
|
||||
// commit the merge tree oid
|
||||
let new_branch_head = project_repository
|
||||
.commit(
|
||||
user,
|
||||
format!(
|
||||
@ -403,106 +471,18 @@ pub fn update_base_branch(
|
||||
branch.name
|
||||
)
|
||||
.as_str(),
|
||||
&branch_head_merge_tree,
|
||||
&merge_tree,
|
||||
&[&branch_head_commit, &new_target_commit],
|
||||
signing_key,
|
||||
)
|
||||
.context("failed to commit merge")?;
|
||||
|
||||
let branch = branch::Branch {
|
||||
head: new_target_head,
|
||||
tree: branch_merge_index.write_tree_to(repo)?,
|
||||
..branch
|
||||
};
|
||||
branch_writer.write(&branch)?;
|
||||
return Ok(Some(branch));
|
||||
}
|
||||
|
||||
// branch was not pushed to upstream yet. attempt a rebase,
|
||||
let (_, committer) = project_repository.git_signatures(user)?;
|
||||
let annotated_branch_head = repo
|
||||
.find_annotated_commit(branch.head)
|
||||
.context("failed to find annotated commit")?;
|
||||
let annotated_upstream_base = repo
|
||||
.find_annotated_commit(new_target_commit.id())
|
||||
.context("failed to find annotated commit")?;
|
||||
let mut rebase_options = git2::RebaseOptions::new();
|
||||
rebase_options.quiet(true);
|
||||
rebase_options.inmemory(true);
|
||||
let mut rebase = repo
|
||||
.rebase(
|
||||
Some(&annotated_branch_head),
|
||||
Some(&annotated_upstream_base),
|
||||
None,
|
||||
Some(&mut rebase_options),
|
||||
)
|
||||
.context("failed to rebase")?;
|
||||
|
||||
let mut rebase_success = true;
|
||||
// check to see if these commits have already been pushed
|
||||
let mut last_rebase_head = branch.head;
|
||||
while rebase.next().is_some() {
|
||||
let index = rebase
|
||||
.inmemory_index()
|
||||
.context("failed to get inmemory index")?;
|
||||
if index.has_conflicts() {
|
||||
rebase_success = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if let Ok(commit_id) = rebase.commit(None, &committer.clone().into(), None) {
|
||||
last_rebase_head = commit_id.into();
|
||||
} else {
|
||||
rebase_success = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if rebase_success {
|
||||
// rebase worked out, rewrite the branch head
|
||||
rebase.finish(None).context("failed to finish rebase")?;
|
||||
let branch = branch::Branch {
|
||||
head: last_rebase_head,
|
||||
tree: branch_merge_index.write_tree_to(repo)?,
|
||||
..branch
|
||||
};
|
||||
branch_writer.write(&branch)?;
|
||||
return Ok(Some(branch));
|
||||
}
|
||||
|
||||
// rebase failed, do a merge commit
|
||||
rebase.abort().context("failed to abort rebase")?;
|
||||
|
||||
// get tree from merge_tree_oid
|
||||
let merge_tree = repo
|
||||
.find_tree(branch_head_merge_tree_oid)
|
||||
.context("failed to find tree")?;
|
||||
|
||||
// commit the merge tree oid
|
||||
let new_branch_head = project_repository
|
||||
.commit(
|
||||
user,
|
||||
format!(
|
||||
"Merged {}/{} into {}",
|
||||
target.branch.remote(),
|
||||
target.branch.branch(),
|
||||
branch.name
|
||||
)
|
||||
.as_str(),
|
||||
&merge_tree,
|
||||
&[&branch_head_commit, &new_target_commit],
|
||||
signing_key,
|
||||
)
|
||||
.context("failed to commit merge")?;
|
||||
|
||||
let branch = branch::Branch {
|
||||
head: new_branch_head,
|
||||
tree: branch_merge_index.write_tree_to(repo)?,
|
||||
..branch
|
||||
};
|
||||
branch_writer.write(&branch)?;
|
||||
Ok(Some(branch))
|
||||
})
|
||||
branch.head = new_branch_head;
|
||||
branch.tree = branch_merge_index.write_tree_to(repo)?;
|
||||
branch_writer.write(&mut branch)?;
|
||||
Ok(Some(branch))
|
||||
},
|
||||
)
|
||||
.collect::<Result<Vec<_>>>()?
|
||||
.into_iter()
|
||||
.flatten()
|
||||
@ -733,7 +713,9 @@ pub fn create_virtual_branch_from_branch(
|
||||
}
|
||||
|
||||
let writer = branch::Writer::new(gb_repository);
|
||||
writer.write(&branch).context("failed to write branch")?;
|
||||
writer
|
||||
.write(&mut branch)
|
||||
.context("failed to write branch")?;
|
||||
|
||||
project_repository.add_branch_reference(&branch)?;
|
||||
|
||||
|
@ -114,10 +114,10 @@ mod tests {
|
||||
fn test_read_override() -> Result<()> {
|
||||
let Case { gb_repository, .. } = Suite::default().new_case();
|
||||
|
||||
let branch = test_branch();
|
||||
let mut branch = test_branch();
|
||||
|
||||
let writer = Writer::new(&gb_repository);
|
||||
writer.write(&branch)?;
|
||||
writer.write(&mut branch)?;
|
||||
|
||||
let session = gb_repository.get_current_session()?.unwrap();
|
||||
let session_reader = sessions::Reader::open(&gb_repository, &session)?;
|
||||
|
@ -28,11 +28,15 @@ impl<'writer> BranchWriter<'writer> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn write(&self, branch: &Branch) -> Result<()> {
|
||||
pub fn write(&self, branch: &mut Branch) -> Result<()> {
|
||||
self.repository.mark_active_session()?;
|
||||
|
||||
let _lock = self.repository.lock();
|
||||
|
||||
branch.updated_timestamp_ms = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)?
|
||||
.as_millis();
|
||||
|
||||
self.writer
|
||||
.write_string(
|
||||
&format!("branches/{}/id", branch.id),
|
||||
@ -175,10 +179,10 @@ mod tests {
|
||||
fn test_write_branch() -> Result<()> {
|
||||
let Case { gb_repository, .. } = Suite::default().new_case();
|
||||
|
||||
let branch = test_branch();
|
||||
let mut branch = test_branch();
|
||||
|
||||
let writer = BranchWriter::new(&gb_repository);
|
||||
writer.write(&branch)?;
|
||||
writer.write(&mut branch)?;
|
||||
|
||||
let root = gb_repository
|
||||
.root()
|
||||
@ -236,10 +240,10 @@ mod tests {
|
||||
fn test_should_create_session() -> Result<()> {
|
||||
let Case { gb_repository, .. } = Suite::default().new_case();
|
||||
|
||||
let branch = test_branch();
|
||||
let mut branch = test_branch();
|
||||
|
||||
let writer = BranchWriter::new(&gb_repository);
|
||||
writer.write(&branch)?;
|
||||
writer.write(&mut branch)?;
|
||||
|
||||
assert!(gb_repository.get_current_session()?.is_some());
|
||||
|
||||
@ -250,12 +254,12 @@ mod tests {
|
||||
fn test_should_update() -> Result<()> {
|
||||
let Case { gb_repository, .. } = Suite::default().new_case();
|
||||
|
||||
let branch = test_branch();
|
||||
let mut branch = test_branch();
|
||||
|
||||
let writer = BranchWriter::new(&gb_repository);
|
||||
writer.write(&branch)?;
|
||||
writer.write(&mut branch)?;
|
||||
|
||||
let updated_branch = Branch {
|
||||
let mut updated_branch = Branch {
|
||||
name: "updated_name".to_string(),
|
||||
applied: false,
|
||||
upstream: Some("refs/remotes/origin/upstream_updated".parse().unwrap()),
|
||||
@ -265,7 +269,7 @@ mod tests {
|
||||
..branch.clone()
|
||||
};
|
||||
|
||||
writer.write(&updated_branch)?;
|
||||
writer.write(&mut updated_branch)?;
|
||||
|
||||
let root = gb_repository
|
||||
.root()
|
||||
|
@ -247,7 +247,7 @@ fn verify_head_is_clean(
|
||||
)
|
||||
.context("failed to reset to integration commit")?;
|
||||
|
||||
let new_branch = super::create_virtual_branch(
|
||||
let mut new_branch = super::create_virtual_branch(
|
||||
gb_repository,
|
||||
project_repository,
|
||||
&BranchCreateRequest {
|
||||
@ -294,12 +294,10 @@ fn verify_head_is_clean(
|
||||
rebased_commit_oid
|
||||
))?;
|
||||
|
||||
new_branch.head = rebased_commit.id();
|
||||
new_branch.tree = rebased_commit.tree_id();
|
||||
writer
|
||||
.write(&super::Branch {
|
||||
head: rebased_commit.id(),
|
||||
tree: rebased_commit.tree_id(),
|
||||
..new_branch.clone()
|
||||
})
|
||||
.write(&mut new_branch)
|
||||
.context("failed to write branch")?;
|
||||
|
||||
head = rebased_commit.id();
|
||||
|
@ -152,12 +152,12 @@ mod tests {
|
||||
target_writer.write_default(&test_target())?;
|
||||
|
||||
let branch_writer = branch::Writer::new(&gb_repository);
|
||||
let branch_1 = test_branch();
|
||||
branch_writer.write(&branch_1)?;
|
||||
let branch_2 = test_branch();
|
||||
branch_writer.write(&branch_2)?;
|
||||
let branch_3 = test_branch();
|
||||
branch_writer.write(&branch_3)?;
|
||||
let mut branch_1 = test_branch();
|
||||
branch_writer.write(&mut branch_1)?;
|
||||
let mut branch_2 = test_branch();
|
||||
branch_writer.write(&mut branch_2)?;
|
||||
let mut branch_3 = test_branch();
|
||||
branch_writer.write(&mut branch_3)?;
|
||||
|
||||
let session = gb_repository.get_current_session()?.unwrap();
|
||||
let session_reader = sessions::Reader::open(&gb_repository, &session)?;
|
||||
|
@ -157,7 +157,7 @@ mod tests {
|
||||
fn test_read_override_target() -> Result<()> {
|
||||
let Case { gb_repository, .. } = Suite::default().new_case();
|
||||
|
||||
let branch = test_branch();
|
||||
let mut branch = test_branch();
|
||||
|
||||
let target = Target {
|
||||
branch: "refs/remotes/remote/branch".parse().unwrap(),
|
||||
@ -176,7 +176,7 @@ mod tests {
|
||||
};
|
||||
|
||||
let branch_writer = branch::Writer::new(&gb_repository);
|
||||
branch_writer.write(&branch)?;
|
||||
branch_writer.write(&mut branch)?;
|
||||
|
||||
let session = gb_repository.get_current_session()?.unwrap();
|
||||
let session_reader = sessions::Reader::open(&gb_repository, &session)?;
|
||||
|
@ -165,7 +165,7 @@ mod tests {
|
||||
fn test_write() -> Result<()> {
|
||||
let Case { gb_repository, .. } = Suite::default().new_case();
|
||||
|
||||
let branch = test_branch();
|
||||
let mut branch = test_branch();
|
||||
let target = Target {
|
||||
branch: "refs/remotes/remote name/branch name".parse().unwrap(),
|
||||
remote_url: "remote url".to_string(),
|
||||
@ -174,7 +174,7 @@ mod tests {
|
||||
};
|
||||
|
||||
let branch_writer = branch::Writer::new(&gb_repository);
|
||||
branch_writer.write(&branch)?;
|
||||
branch_writer.write(&mut branch)?;
|
||||
|
||||
let target_writer = TargetWriter::new(&gb_repository);
|
||||
target_writer.write(&branch.id, &target)?;
|
||||
@ -263,7 +263,7 @@ mod tests {
|
||||
fn test_should_update() -> Result<()> {
|
||||
let Case { gb_repository, .. } = Suite::default().new_case();
|
||||
|
||||
let branch = test_branch();
|
||||
let mut branch = test_branch();
|
||||
let target = Target {
|
||||
branch: "refs/remotes/remote name/branch name".parse().unwrap(),
|
||||
remote_url: "remote url".to_string(),
|
||||
@ -272,7 +272,7 @@ mod tests {
|
||||
};
|
||||
|
||||
let branch_writer = branch::Writer::new(&gb_repository);
|
||||
branch_writer.write(&branch)?;
|
||||
branch_writer.write(&mut branch)?;
|
||||
let target_writer = TargetWriter::new(&gb_repository);
|
||||
target_writer.write(&branch.id, &target)?;
|
||||
|
||||
|
@ -18,7 +18,7 @@ use crate::{
|
||||
};
|
||||
|
||||
use super::*;
|
||||
use branch::{Branch, BranchCreateRequest, Ownership};
|
||||
use branch::{BranchCreateRequest, Ownership};
|
||||
|
||||
pub fn set_test_target(
|
||||
gb_repo: &gb_repository::Repository,
|
||||
@ -731,20 +731,16 @@ fn test_move_hunks_multiple_sources() -> Result<()> {
|
||||
let current_session_reader = sessions::Reader::open(&gb_repository, ¤t_session)?;
|
||||
let branch_reader = branch::Reader::new(¤t_session_reader);
|
||||
let branch_writer = branch::Writer::new(&gb_repository);
|
||||
let branch2 = branch_reader.read(&branch2_id)?;
|
||||
branch_writer.write(&branch::Branch {
|
||||
ownership: Ownership {
|
||||
files: vec!["test.txt:1-5".parse()?],
|
||||
},
|
||||
..branch2
|
||||
})?;
|
||||
let branch1 = branch_reader.read(&branch1_id)?;
|
||||
branch_writer.write(&branch::Branch {
|
||||
ownership: Ownership {
|
||||
files: vec!["test.txt:11-15".parse()?],
|
||||
},
|
||||
..branch1
|
||||
})?;
|
||||
let mut branch2 = branch_reader.read(&branch2_id)?;
|
||||
branch2.ownership = Ownership {
|
||||
files: vec!["test.txt:1-5".parse()?],
|
||||
};
|
||||
branch_writer.write(&mut branch2)?;
|
||||
let mut branch1 = branch_reader.read(&branch1_id)?;
|
||||
branch1.ownership = Ownership {
|
||||
files: vec!["test.txt:11-15".parse()?],
|
||||
};
|
||||
branch_writer.write(&mut branch1)?;
|
||||
|
||||
let statuses =
|
||||
get_status_by_branch(&gb_repository, &project_repository).expect("failed to get status");
|
||||
@ -1030,7 +1026,7 @@ fn test_merge_vbranch_upstream_clean() -> Result<()> {
|
||||
branch.upstream = Some(remote_branch.clone());
|
||||
branch.head = last_push;
|
||||
branch_writer
|
||||
.write(&branch)
|
||||
.write(&mut branch)
|
||||
.context("failed to write target branch after push")?;
|
||||
|
||||
// create the branch
|
||||
@ -1159,7 +1155,7 @@ fn test_merge_vbranch_upstream_conflict() -> Result<()> {
|
||||
branch.upstream = Some(remote_branch.clone());
|
||||
branch.head = last_push;
|
||||
branch_writer
|
||||
.write(&branch)
|
||||
.write(&mut branch)
|
||||
.context("failed to write target branch after push")?;
|
||||
|
||||
// create the branch
|
||||
@ -1667,13 +1663,11 @@ fn test_detect_mergeable_branch() -> Result<()> {
|
||||
"line1\nline2\nline3\nline4\nbranch4\n",
|
||||
)?;
|
||||
|
||||
let branch4 = branch_reader.read(&branch4_id)?;
|
||||
branch_writer.write(&Branch {
|
||||
ownership: Ownership {
|
||||
files: vec!["test2.txt:1-6".parse()?],
|
||||
},
|
||||
..branch4
|
||||
})?;
|
||||
let mut branch4 = branch_reader.read(&branch4_id)?;
|
||||
branch4.ownership = Ownership {
|
||||
files: vec!["test2.txt:1-6".parse()?],
|
||||
};
|
||||
branch_writer.write(&mut branch4)?;
|
||||
|
||||
let branches = list_virtual_branches(&gb_repository, &project_repository)?;
|
||||
assert_eq!(branches.len(), 4);
|
||||
|
@ -49,6 +49,7 @@ pub struct VirtualBranch {
|
||||
pub upstream: Option<RemoteBranch>, // the upstream branch where this branch pushes to, if any
|
||||
pub base_current: bool, // is this vbranch based on the current base branch? if false, this needs to be manually merged with conflicts
|
||||
pub ownership: Ownership,
|
||||
pub updated_timestamp_ms: u128,
|
||||
}
|
||||
|
||||
// this is the struct that maps to the view `Commit` type in Typescript
|
||||
@ -231,20 +232,18 @@ pub fn apply_branch(
|
||||
|
||||
if merge_index.has_conflicts() {
|
||||
// currently we can only deal with the merge problem branch
|
||||
for branch in super::get_status_by_branch(gb_repository, project_repository)?
|
||||
for mut branch in super::get_status_by_branch(gb_repository, project_repository)?
|
||||
.into_iter()
|
||||
.map(|(branch, _)| branch)
|
||||
.filter(|branch| branch.applied)
|
||||
{
|
||||
writer.write(&branch::Branch {
|
||||
applied: false,
|
||||
..branch
|
||||
})?;
|
||||
branch.applied = false;
|
||||
writer.write(&mut branch)?;
|
||||
}
|
||||
|
||||
// apply the branch
|
||||
branch.applied = true;
|
||||
writer.write(&branch)?;
|
||||
writer.write(&mut branch)?;
|
||||
|
||||
// checkout the conflicts
|
||||
repo.checkout_index(&mut merge_index)
|
||||
@ -309,7 +308,7 @@ pub fn apply_branch(
|
||||
// ok, update the virtual branch
|
||||
branch.head = new_branch_head;
|
||||
branch.tree = merged_branch_tree_oid;
|
||||
writer.write(&branch)?;
|
||||
writer.write(&mut branch)?;
|
||||
} else {
|
||||
// branch was not pushed to upstream yet. attempt a rebase,
|
||||
let (_, committer) = project_repository.git_signatures(user)?;
|
||||
@ -401,7 +400,7 @@ pub fn apply_branch(
|
||||
|
||||
// apply the branch
|
||||
branch.applied = true;
|
||||
writer.write(&branch)?;
|
||||
writer.write(&mut branch)?;
|
||||
|
||||
// checkout the merge index
|
||||
repo.checkout_index(&mut merge_index)
|
||||
@ -468,7 +467,7 @@ pub fn unapply_ownership(
|
||||
if taken_file_ownerships.is_empty() {
|
||||
continue;
|
||||
}
|
||||
branch_writer.write(&branch)?;
|
||||
branch_writer.write(&mut branch)?;
|
||||
branch_files = branch_files
|
||||
.iter_mut()
|
||||
.filter_map(|(filepath, hunks)| {
|
||||
@ -611,7 +610,7 @@ pub fn unapply_branch(
|
||||
|
||||
target_branch.tree = write_tree(project_repository, &default_target, files)?;
|
||||
target_branch.applied = false;
|
||||
branch_writer.write(&target_branch)?;
|
||||
branch_writer.write(&mut target_branch)?;
|
||||
}
|
||||
|
||||
let repo = &project_repository.git_repository;
|
||||
@ -831,6 +830,7 @@ pub fn list_virtual_branches(
|
||||
conflicted: conflicts::is_resolving(project_repository),
|
||||
base_current,
|
||||
ownership: branch.ownership.clone(),
|
||||
updated_timestamp_ms: branch.updated_timestamp_ms,
|
||||
};
|
||||
branches.push(branch);
|
||||
}
|
||||
@ -1049,7 +1049,7 @@ pub fn create_virtual_branch(
|
||||
if branch.order != new_order {
|
||||
branch.order = new_order;
|
||||
branch_writer
|
||||
.write(&branch)
|
||||
.write(&mut branch)
|
||||
.context("failed to write branch")?;
|
||||
}
|
||||
}
|
||||
@ -1092,7 +1092,7 @@ pub fn create_virtual_branch(
|
||||
}
|
||||
|
||||
branch_writer
|
||||
.write(&branch)
|
||||
.write(&mut branch)
|
||||
.context("failed to write branch")?;
|
||||
|
||||
project_repository.add_branch_reference(&branch)?;
|
||||
@ -1255,7 +1255,7 @@ pub fn merge_virtual_branch_upstream(
|
||||
let branch_writer = branch::Writer::new(gb_repository);
|
||||
branch.head = new_branch_head;
|
||||
branch.tree = merge_tree_oid;
|
||||
branch_writer.write(&branch)?;
|
||||
branch_writer.write(&mut branch)?;
|
||||
}
|
||||
|
||||
super::integration::update_gitbutler_integration(gb_repository, project_repository)?;
|
||||
@ -1339,7 +1339,7 @@ pub fn update_branch(
|
||||
};
|
||||
|
||||
branch_writer
|
||||
.write(&branch)
|
||||
.write(&mut branch)
|
||||
.context("failed to write target branch")?;
|
||||
|
||||
Ok(branch)
|
||||
@ -1796,7 +1796,7 @@ pub fn reset_branch(
|
||||
})?;
|
||||
|
||||
let branch_reader = branch::Reader::new(¤t_session_reader);
|
||||
let branch = match branch_reader.read(branch_id) {
|
||||
let mut branch = match branch_reader.read(branch_id) {
|
||||
Ok(branch) => Ok(branch),
|
||||
Err(reader::Error::NotFound) => Err(errors::ResetBranchError::BranchNotFound(
|
||||
errors::BranchNotFoundError {
|
||||
@ -1823,11 +1823,9 @@ pub fn reset_branch(
|
||||
}
|
||||
|
||||
let branch_writer = branch::Writer::new(gb_repository);
|
||||
branch.head = target_commit_oid;
|
||||
branch_writer
|
||||
.write(&branch::Branch {
|
||||
head: target_commit_oid,
|
||||
..branch
|
||||
})
|
||||
.write(&mut branch)
|
||||
.context("failed to write branch")?;
|
||||
|
||||
super::integration::update_gitbutler_integration(gb_repository, project_repository)
|
||||
@ -2029,11 +2027,11 @@ pub fn commit(
|
||||
})?;
|
||||
|
||||
// get the files to commit
|
||||
let statuses = get_status_by_branch(gb_repository, project_repository)
|
||||
let mut statuses = get_status_by_branch(gb_repository, project_repository)
|
||||
.context("failed to get status by branch")?;
|
||||
|
||||
let (branch, files) = statuses
|
||||
.iter()
|
||||
let (ref mut branch, files) = statuses
|
||||
.iter_mut()
|
||||
.find(|(branch, _)| branch.id == *branch_id)
|
||||
.ok_or_else(|| {
|
||||
errors::CommitError::BranchNotFound(errors::BranchNotFoundError {
|
||||
@ -2115,13 +2113,9 @@ pub fn 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")?;
|
||||
branch.tree = tree_oid;
|
||||
branch.head = commit_oid;
|
||||
writer.write(branch).context("failed to write branch")?;
|
||||
|
||||
super::integration::update_gitbutler_integration(gb_repository, project_repository)
|
||||
.context("failed to update gitbutler integration")?;
|
||||
@ -2147,7 +2141,7 @@ pub fn push(
|
||||
let branch_reader = branch::Reader::new(¤t_session_reader);
|
||||
let branch_writer = branch::Writer::new(gb_repository);
|
||||
|
||||
let vbranch = branch_reader.read(branch_id).map_err(|error| match error {
|
||||
let mut vbranch = branch_reader.read(branch_id).map_err(|error| match error {
|
||||
reader::Error::NotFound => errors::PushError::BranchNotFound(errors::BranchNotFoundError {
|
||||
project_id: project_repository.project().id,
|
||||
branch_id: *branch_id,
|
||||
@ -2193,12 +2187,10 @@ pub fn push(
|
||||
|
||||
project_repository.push(&vbranch.head, &remote_branch, with_force, credentials)?;
|
||||
|
||||
vbranch.upstream = Some(remote_branch.clone());
|
||||
vbranch.upstream_head = Some(vbranch.head);
|
||||
branch_writer
|
||||
.write(&branch::Branch {
|
||||
upstream: Some(remote_branch.clone()),
|
||||
upstream_head: Some(vbranch.head),
|
||||
..vbranch
|
||||
})
|
||||
.write(&mut vbranch)
|
||||
.context("failed to write target branch after push")?;
|
||||
|
||||
project_repository.fetch(remote_branch.remote(), credentials)?;
|
||||
@ -2216,11 +2208,9 @@ pub fn mark_all_unapplied(gb_repository: &gb_repository::Repository) -> Result<(
|
||||
.context("failed to read branches")?
|
||||
.into_iter()
|
||||
.filter(|branch| branch.applied)
|
||||
.map(|branch| {
|
||||
branch_writer.write(&super::Branch {
|
||||
applied: false,
|
||||
..branch
|
||||
})
|
||||
.map(|mut branch| {
|
||||
branch.applied = false;
|
||||
branch_writer.write(&mut branch)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
.context("failed to write branches")?;
|
||||
@ -2487,15 +2477,15 @@ pub fn amend(
|
||||
})
|
||||
})?;
|
||||
|
||||
let applied_statuses = get_applied_status(
|
||||
let mut applied_statuses = get_applied_status(
|
||||
gb_repository,
|
||||
project_repository,
|
||||
&default_target,
|
||||
applied_branches,
|
||||
)?;
|
||||
|
||||
let (target_branch, target_status) = applied_statuses
|
||||
.iter()
|
||||
let (ref mut target_branch, target_status) = applied_statuses
|
||||
.iter_mut()
|
||||
.find(|(b, _)| b.id == *branch_id)
|
||||
.ok_or_else(|| {
|
||||
errors::AmendError::BranchNotFound(errors::BranchNotFoundError {
|
||||
@ -2592,10 +2582,8 @@ pub fn amend(
|
||||
.context("failed to create commit")?;
|
||||
|
||||
let branch_writer = branch::Writer::new(gb_repository);
|
||||
branch_writer.write(&branch::Branch {
|
||||
head: commit_oid,
|
||||
..target_branch.clone()
|
||||
})?;
|
||||
target_branch.head = commit_oid;
|
||||
branch_writer.write(target_branch)?;
|
||||
|
||||
super::integration::update_gitbutler_integration(gb_repository, project_repository)?;
|
||||
|
||||
@ -2622,7 +2610,7 @@ pub fn cherry_pick(
|
||||
let current_session_reader = sessions::Reader::open(gb_repository, ¤t_session)
|
||||
.context("failed to open current session")?;
|
||||
let branch_reader = branch::Reader::new(¤t_session_reader);
|
||||
let branch = branch_reader
|
||||
let mut branch = branch_reader
|
||||
.read(branch_id)
|
||||
.context("failed to read branch")?;
|
||||
|
||||
@ -2776,11 +2764,9 @@ pub fn cherry_pick(
|
||||
|
||||
// update branch status
|
||||
let writer = branch::Writer::new(gb_repository);
|
||||
branch.head = commit_oid;
|
||||
writer
|
||||
.write(&Branch {
|
||||
head: commit_oid,
|
||||
..branch.clone()
|
||||
})
|
||||
.write(&mut branch)
|
||||
.context("failed to write branch")?;
|
||||
|
||||
Some(commit_oid)
|
||||
@ -2822,7 +2808,7 @@ pub fn squash(
|
||||
})
|
||||
})?;
|
||||
|
||||
let branch = branch_reader.read(branch_id).map_err(|error| match error {
|
||||
let mut branch = branch_reader.read(branch_id).map_err(|error| match error {
|
||||
reader::Error::NotFound => {
|
||||
errors::SquashError::BranchNotFound(errors::BranchNotFoundError {
|
||||
project_id: project_repository.project().id,
|
||||
@ -2970,11 +2956,9 @@ pub fn squash(
|
||||
|
||||
// save new branch head
|
||||
let writer = branch::Writer::new(gb_repository);
|
||||
branch.head = new_head_id;
|
||||
writer
|
||||
.write(&Branch {
|
||||
head: new_head_id,
|
||||
..branch.clone()
|
||||
})
|
||||
.write(&mut branch)
|
||||
.context("failed to write branch")?;
|
||||
|
||||
super::integration::update_gitbutler_integration(gb_repository, project_repository)?;
|
||||
@ -3018,7 +3002,7 @@ pub fn update_commit_message(
|
||||
)
|
||||
})?;
|
||||
|
||||
let branch = branch_reader.read(branch_id).map_err(|error| match error {
|
||||
let mut branch = branch_reader.read(branch_id).map_err(|error| match error {
|
||||
reader::Error::NotFound => {
|
||||
errors::UpdateCommitMessageError::BranchNotFound(errors::BranchNotFoundError {
|
||||
project_id: project_repository.project().id,
|
||||
@ -3148,11 +3132,9 @@ pub fn update_commit_message(
|
||||
|
||||
// save new branch head
|
||||
let writer = branch::Writer::new(gb_repository);
|
||||
branch.head = new_head_id;
|
||||
writer
|
||||
.write(&Branch {
|
||||
head: new_head_id,
|
||||
..branch.clone()
|
||||
})
|
||||
.write(&mut branch)
|
||||
.context("failed to write branch")?;
|
||||
|
||||
super::integration::update_gitbutler_integration(gb_repository, project_repository)?;
|
||||
|
@ -815,11 +815,11 @@ mod test {
|
||||
let target_writer = virtual_branches::target::Writer::new(&gb_repository);
|
||||
let default_target = test_target();
|
||||
target_writer.write_default(&default_target)?;
|
||||
let vbranch0 = test_branch();
|
||||
branch_writer.write(&vbranch0)?;
|
||||
let vbranch1 = test_branch();
|
||||
let mut vbranch0 = test_branch();
|
||||
branch_writer.write(&mut vbranch0)?;
|
||||
let mut vbranch1 = test_branch();
|
||||
let vbranch1_target = test_target();
|
||||
branch_writer.write(&vbranch1)?;
|
||||
branch_writer.write(&mut vbranch1)?;
|
||||
target_writer.write(&vbranch1.id, &vbranch1_target)?;
|
||||
|
||||
std::fs::write(project.path.join("test.txt"), "hello world!").unwrap();
|
||||
@ -871,11 +871,11 @@ mod test {
|
||||
let target_writer = virtual_branches::target::Writer::new(&gb_repository);
|
||||
let default_target = test_target();
|
||||
target_writer.write_default(&default_target)?;
|
||||
let vbranch0 = test_branch();
|
||||
branch_writer.write(&vbranch0)?;
|
||||
let vbranch1 = test_branch();
|
||||
let mut vbranch0 = test_branch();
|
||||
branch_writer.write(&mut vbranch0)?;
|
||||
let mut vbranch1 = test_branch();
|
||||
let vbranch1_target = test_target();
|
||||
branch_writer.write(&vbranch1)?;
|
||||
branch_writer.write(&mut vbranch1)?;
|
||||
target_writer.write(&vbranch1.id, &vbranch1_target)?;
|
||||
|
||||
std::fs::write(project.path.join("test.txt"), "hello world!").unwrap();
|
||||
|
Loading…
Reference in New Issue
Block a user