Merge pull request #5178 from gitbutlerapp/stack-compute-upstream-only-correctly

stack: improvve computing of upstream only commits
This commit is contained in:
Kiril Videlov 2024-10-16 20:30:41 +02:00 committed by GitHub
commit 60b365d988
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 23 additions and 16 deletions

View File

@ -542,7 +542,7 @@ fn stack_series(
.repository() .repository()
.find_reference(&upstream_reference)? .find_reference(&upstream_reference)?
.peel_to_commit()?; .peel_to_commit()?;
for patch in series.upstream_only(&stack_series) { for patch in series.upstream_only_commits {
if let Ok(commit) = if let Ok(commit) =
commit_by_oid_or_change_id(&patch, ctx, remote_head.id(), default_target) commit_by_oid_or_change_id(&patch, ctx, remote_head.id(), default_target)
{ {

View File

@ -20,6 +20,9 @@ pub struct Series {
/// If the branch/series have never been pushed, this list will be empty. /// If the branch/series have never been pushed, this list will be empty.
/// Topologically ordered, the first entry is the newest in the series. /// Topologically ordered, the first entry is the newest in the series.
pub remote_commits: Vec<CommitOrChangeId>, pub remote_commits: Vec<CommitOrChangeId>,
/// The list of patches that are only in the upstream (remote) and not in the local commits,
/// as determined by the commit ID or change ID.
pub upstream_only_commits: Vec<CommitOrChangeId>,
/// The commit IDs of the remote commits that are part of this series, grouped by change id. /// The commit IDs of the remote commits that are part of this series, grouped by change id.
/// Since we dont have a change_id to commit_id index, this is used to determine /// Since we dont have a change_id to commit_id index, this is used to determine
pub remote_commit_ids_by_change_id: HashMap<String, git2::Oid>, pub remote_commit_ids_by_change_id: HashMap<String, git2::Oid>,
@ -30,19 +33,4 @@ impl Series {
pub fn remote(&self, patch: &CommitOrChangeId) -> bool { pub fn remote(&self, patch: &CommitOrChangeId) -> bool {
self.remote_commits.contains(patch) self.remote_commits.contains(patch)
} }
/// Returns a list of patches that are only in the upstream (remote) and not in the local commits,
/// as determined by the commit ID or change ID.
/// This comparison is peformed against the full stack of series.
pub fn upstream_only(&self, stack_series: &[Series]) -> Vec<CommitOrChangeId> {
let mut upstream_only = vec![];
for commit in &self.remote_commits {
if !stack_series
.iter()
.any(|s| s.local_commits.contains(commit))
{
upstream_only.push(commit.clone());
}
}
upstream_only
}
} }

View File

@ -499,10 +499,29 @@ impl StackExt for Stack {
}); });
} }
}; };
// compute the commits that are only in the upstream
let local_patches_including_merge = repo
.log(head_commit, LogUntil::Commit(previous_head), true)?
.iter()
.rev() // oldest commit first
.map(|c| match c.change_id() {
Some(change_id) => CommitOrChangeId::ChangeId(change_id.to_string()),
None => CommitOrChangeId::CommitId(c.id().to_string()),
})
.collect_vec();
let mut upstream_only = vec![];
for patch in remote_patches.iter() {
if !local_patches_including_merge.contains(patch) {
upstream_only.push(patch.clone());
}
}
all_series.push(Series { all_series.push(Series {
head: head.clone(), head: head.clone(),
local_commits: local_patches, local_commits: local_patches,
remote_commits: remote_patches, remote_commits: remote_patches,
upstream_only_commits: upstream_only,
remote_commit_ids_by_change_id, remote_commit_ids_by_change_id,
}); });
previous_head = head_commit; previous_head = head_commit;