Merge pull request #5071 from gitbutlerapp/Add-extra-info-on-patch-series-remote_commit_id

Add an extra field `remote_commit_id` on the API type `VirtualBranchCommit`
This commit is contained in:
Kiril Videlov 2024-10-09 18:25:50 +02:00 committed by GitHub
commit f2d2a7ae14
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 67 additions and 9 deletions

View File

@ -188,6 +188,19 @@ export class DetailedCommit {
// author, commit and message.
copiedFromRemoteId?: string;
/**
*
* Represents the remote commit id of this patch.
* This field is set if:
* - The commit has been pushed
* - The commit has been copied from a remote commit (when applying a remote branch)
*
* The `remoteCommitId` may be the same as the `id` or it may be different if the commit has been rebased or updated.
*
* Note: This makes both the `isRemote` and `copiedFromRemoteId` fields redundant, but they are kept for compatibility.
*/
remoteCommitId?: string;
prev?: DetailedCommit;
next?: DetailedCommit;

View File

@ -25,6 +25,7 @@ pub struct VirtualBranchCommit {
pub description: BStringForFrontend,
pub created_at: u128,
pub author: Author,
/// Dont use, favor `remote_commit_id` instead
pub is_remote: bool,
pub files: Vec<VirtualBranchFile>,
pub is_integrated: bool,
@ -39,6 +40,16 @@ pub struct VirtualBranchCommit {
/// This is used by the frontend similar to the `change_id` to group matching commits.
#[serde(with = "gitbutler_serde::oid_opt")]
pub copied_from_remote_id: Option<git2::Oid>,
/// Represents the remote commit id of this patch.
/// This field is set if:
/// - The commit has been pushed
/// - The commit has been copied from a remote commit (when applying a remote branch)
///
/// The `remote_commit_id` may be the same as the `id` or it may be different if the commit has been rebased or updated.
///
/// Note: This makes both the `is_remote` and `copied_from_remote_id` fields redundant, but they are kept for compatibility.
#[serde(with = "gitbutler_serde::oid_opt")]
pub remote_commit_id: Option<git2::Oid>,
}
pub(crate) fn commit_to_vbranch_commit(
@ -48,6 +59,7 @@ pub(crate) fn commit_to_vbranch_commit(
is_integrated: bool,
is_remote: bool,
copied_from_remote_id: Option<git2::Oid>,
remote_commit_id: Option<git2::Oid>,
) -> Result<VirtualBranchCommit> {
let timestamp = u128::try_from(commit.time().seconds())?;
let message = commit.message_bstr().to_owned();
@ -76,6 +88,7 @@ pub(crate) fn commit_to_vbranch_commit(
is_signed: commit.is_signed(),
conflicted: commit.is_conflicted(),
copied_from_remote_id,
remote_commit_id: remote_commit_id.or(copied_from_remote_id),
};
Ok(commit)

View File

@ -380,6 +380,7 @@ pub fn list_virtual_branches_cached(
is_integrated,
is_remote,
copied_from_remote_id,
None, // remote_commit_id is only used inside PatchSeries
)
})
.collect::<Result<Vec<_>>>()?
@ -420,7 +421,13 @@ pub fn list_virtual_branches_cached(
let refname = branch.refname()?.into();
// TODO: Error out here once this API is stable
let series = match stack_series(ctx, &branch, &default_target, &check_commit) {
let series = match stack_series(
ctx,
&branch,
&default_target,
&check_commit,
remote_commit_data,
) {
Ok(series) => series,
Err(e) => {
tracing::warn!("failed to compute stack series: {:?}", e);
@ -472,6 +479,7 @@ fn stack_series(
branch: &Stack,
default_target: &Target,
check_commit: &IsCommitIntegrated,
remote_commit_data: HashMap<CommitData, git2::Oid>,
) -> Result<Vec<PatchSeries>> {
let mut api_series: Vec<PatchSeries> = vec![];
let stack_series = branch.list_series(ctx)?;
@ -487,13 +495,23 @@ fn stack_series(
for patch in series.clone().local_commits {
let commit = commit_by_oid_or_change_id(&patch, ctx, branch.head(), default_target)?;
let is_integrated = check_commit.is_integrated(&commit)?;
let copied_from_remote_id = CommitData::try_from(&commit)
.ok()
.and_then(|data| remote_commit_data.get(&data).copied());
let remote_commit_id = commit.change_id().and_then(|change_id| {
series
.remote_commit_ids_by_change_id
.get(&change_id)
.cloned()
});
let vcommit = commit_to_vbranch_commit(
ctx,
branch,
&commit,
is_integrated,
series.remote(&patch),
None,
copied_from_remote_id,
remote_commit_id,
)?;
patches.push(vcommit);
}
@ -508,7 +526,8 @@ fn stack_series(
&commit,
is_integrated,
true, // per definition
None,
None, // per definition
Some(commit.id()),
)?;
upstream_patches.push(vcommit);
}

View File

@ -1,11 +1,12 @@
use gitbutler_patch_reference::{CommitOrChangeId, PatchReference};
use std::collections::HashMap;
/// Series or (patch) Series is a set of patches (commits) that are dependent on each other.
/// This is effectively a sub-branch within a (series) stack.
/// The difference from a branch is that only the patches (commits) unique to the series are included.
///
/// The `pushed` status, as well as the `remote_reference` can be obtained from the methods on `head` (PatchReference).
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Series {
/// The GitButler-managed head reference for this series. It points to a commit ID or a change ID in the stack.
/// This head may or may not be part of the commits that are in the series
@ -19,6 +20,9 @@ pub struct Series {
/// If the branch/series have never been pushed, this list will be empty.
/// Topologically ordered, the first entry is the newest in the series.
pub remote_commits: Vec<CommitOrChangeId>,
/// 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
pub remote_commit_ids_by_change_id: HashMap<String, git2::Oid>,
}
impl Series {

View File

@ -24,6 +24,7 @@ use crate::heads::add_head;
use crate::heads::get_head;
use crate::heads::remove_head;
use crate::series::Series;
use std::collections::HashMap;
/// A (series) Stack represents multiple "branches" that are dependent on each other in series.
///
@ -457,6 +458,7 @@ impl StackExt for Stack {
.collect_vec();
let mut remote_patches: Vec<CommitOrChangeId> = vec![];
let mut remote_commit_ids_by_change_id: HashMap<String, git2::Oid> = HashMap::new();
if let Some(remote_name) = default_target.push_remote_name.as_ref() {
if head.pushed(remote_name, ctx).unwrap_or_default() {
let head_commit = repo
@ -466,17 +468,24 @@ impl StackExt for Stack {
repo.log(head_commit.id(), LogUntil::Commit(merge_base))?
.iter()
.rev()
.map(|c| match c.change_id() {
Some(change_id) => CommitOrChangeId::ChangeId(change_id.to_string()),
None => CommitOrChangeId::CommitId(c.id().to_string()),
})
.for_each(|c| remote_patches.push(c));
.for_each(|c| {
let commit_or_change_id = match c.change_id() {
Some(change_id) => {
remote_commit_ids_by_change_id
.insert(change_id.to_string(), c.id());
CommitOrChangeId::ChangeId(change_id.to_string())
}
None => CommitOrChangeId::CommitId(c.id().to_string()),
};
remote_patches.push(commit_or_change_id);
});
}
};
all_series.push(Series {
head: head.clone(),
local_commits: local_patches,
remote_commits: remote_patches,
remote_commit_ids_by_change_id,
});
previous_head = head_commit;
}