Skip to content

Commit 67f418f

Browse files
committed
Use gitoxide in get_branches_info
1 parent 3dbf120 commit 67f418f

File tree

1 file changed

+107
-61
lines changed
  • asyncgit/src/sync/branch

1 file changed

+107
-61
lines changed

asyncgit/src/sync/branch/mod.rs

Lines changed: 107 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@ use super::{utils::bytes2string, RepoPath};
99
use crate::{
1010
error::{Error, Result},
1111
sync::{
12-
remotes::get_default_remote_for_push_in_repo,
12+
gix_repo, remotes::get_default_remote_for_push_in_repo,
1313
repository::repo, utils::get_head_repo, CommitId,
1414
},
1515
};
1616
use git2::{Branch, BranchType, Repository};
17+
use gix::remote::Direction;
1718
use scopetime::scope_time;
1819
use std::collections::HashSet;
1920

@@ -128,76 +129,121 @@ pub fn get_branches_info(
128129
) -> Result<Vec<BranchInfo>> {
129130
scope_time!("get_branches_info");
130131

131-
let repo = repo(repo_path)?;
132+
let gix_repo = gix_repo(repo_path)?;
133+
let platform = gix_repo.references()?;
134+
let head_name = gix_repo.head_name().ok().flatten();
135+
136+
let mut branches_for_display: Vec<_> = if local {
137+
platform
138+
.local_branches()?
139+
.flatten()
140+
.filter_map(|mut branch| {
141+
let branch_name = branch.name();
142+
let name = branch_name.shorten().to_string();
143+
let reference = branch_name.to_owned().to_string();
144+
145+
// There is no `gitoxide` equivalent of [`Branch::is_head`][branch-is-head]. This will
146+
// also not change in the future as it would require reading and resolving the `HEAD`
147+
// reference each time it is called. It is more efficient for us to read the `HEAD`
148+
// reference once and then do the individual comparisons ourselves.
149+
//
150+
// This implementation is based on [`git_branch_is_head`][libgit2-git-branch-is-head].
151+
//
152+
// [branch-is-head]: https://docs.rs/git2/latest/git2/struct.Branch.html#method.is_head
153+
// [libgit2-git-branch-is-head]: https://github.com/libgit2/libgit2/blob/58d9363f02f1fa39e46d49b604f27008e75b72f2/src/libgit2/branch.c#L773-L800
154+
let is_head =
155+
head_name.as_ref().is_some_and(|head_name| {
156+
head_name.as_ref() == branch_name
157+
});
158+
159+
let top_commit = branch.peel_to_commit().ok()?;
160+
let upstream = branch.remote_tracking_ref_name(
161+
// Using `Fetch` replicates the behaviour of `Branch::upstream` as much as possible.
162+
//
163+
// See https://docs.rs/git2/latest/git2/struct.Branch.html#method.upstream
164+
Direction::Fetch,
165+
);
166+
167+
let upstream_branch = match upstream {
168+
Some(Ok(reference)) => Some(UpstreamBranch {
169+
reference: reference.into_owned().to_string(),
170+
}),
171+
_ => None,
172+
};
173+
174+
let remote = branch
175+
.remote_name(
176+
// Using `Fetch` replicates the behaviour of `Repository::branch_upstream_remote` as much as possible.
177+
//
178+
// See https://docs.rs/git2/latest/git2/struct.Repository.html#method.branch_upstream_remote
179+
Direction::Fetch,
180+
)
181+
.map(|name| name.as_bstr().to_string());
182+
183+
let details = BranchDetails::Local(LocalBranch {
184+
is_head,
185+
has_upstream: upstream_branch.is_some(),
186+
upstream: upstream_branch,
187+
remote,
188+
});
132189

133-
let (filter, remotes_with_tracking) = if local {
134-
(BranchType::Local, HashSet::default())
190+
Some(BranchInfo {
191+
name,
192+
reference,
193+
top_commit_message: top_commit
194+
.message()
195+
.ok()?
196+
.title
197+
.to_string(),
198+
top_commit: top_commit.into(),
199+
details,
200+
})
201+
})
202+
.collect()
135203
} else {
136-
let remotes: HashSet<_> = repo
137-
.branches(Some(BranchType::Local))?
138-
.filter_map(|b| {
139-
let branch = b.ok()?.0;
140-
let upstream = branch.upstream();
141-
upstream
142-
.ok()?
143-
.name_bytes()
144-
.ok()
145-
.map(ToOwned::to_owned)
204+
let remotes_with_tracking: HashSet<_> = platform
205+
.local_branches()?
206+
.flatten()
207+
.filter_map(|branch| {
208+
let upstream = branch.remote_tracking_ref_name(
209+
// Using `Fetch` replicates the behaviour of `Branch::upstream` as much as possible.
210+
//
211+
// See https://docs.rs/git2/latest/git2/struct.Branch.html#method.upstream
212+
Direction::Fetch,
213+
)?;
214+
Some(upstream.ok()?.into_owned())
146215
})
147216
.collect();
148-
(BranchType::Remote, remotes)
149-
};
150-
151-
let mut branches_for_display: Vec<BranchInfo> = repo
152-
.branches(Some(filter))?
153-
.map(|b| {
154-
let branch = b?.0;
155-
let top_commit = branch.get().peel_to_commit()?;
156-
let reference = bytes2string(branch.get().name_bytes())?;
157-
let upstream = branch.upstream();
158-
159-
let remote = repo
160-
.branch_upstream_remote(&reference)
161-
.ok()
162-
.as_ref()
163-
.and_then(git2::Buf::as_str)
164-
.map(String::from);
165217

166-
let name_bytes = branch.name_bytes()?;
218+
platform
219+
.remote_branches()?
220+
.flatten()
221+
.filter_map(|mut branch| {
222+
let branch_name = branch.name();
223+
let name = branch_name.shorten().to_string();
224+
let reference = branch_name.to_owned().to_string();
167225

168-
let upstream_branch =
169-
upstream.ok().and_then(|upstream| {
170-
bytes2string(upstream.get().name_bytes())
171-
.ok()
172-
.map(|reference| UpstreamBranch { reference })
226+
let details = BranchDetails::Remote(RemoteBranch {
227+
has_tracking: remotes_with_tracking
228+
.contains(branch_name),
173229
});
174230

175-
let details = if local {
176-
BranchDetails::Local(LocalBranch {
177-
is_head: branch.is_head(),
178-
has_upstream: upstream_branch.is_some(),
179-
upstream: upstream_branch,
180-
remote,
231+
let top_commit = branch.peel_to_commit().ok()?;
232+
233+
Some(BranchInfo {
234+
name,
235+
reference,
236+
top_commit_message: top_commit
237+
.message()
238+
.ok()?
239+
.title
240+
.to_string(),
241+
top_commit: top_commit.into(),
242+
details,
181243
})
182-
} else {
183-
BranchDetails::Remote(RemoteBranch {
184-
has_tracking: remotes_with_tracking
185-
.contains(name_bytes),
186-
})
187-
};
188-
189-
Ok(BranchInfo {
190-
name: bytes2string(name_bytes)?,
191-
reference,
192-
top_commit_message: bytes2string(
193-
top_commit.summary_bytes().unwrap_or_default(),
194-
)?,
195-
top_commit: top_commit.id().into(),
196-
details,
197244
})
198-
})
199-
.filter_map(Result::ok)
200-
.collect();
245+
.collect()
246+
};
201247

202248
branches_for_display.sort_by(|a, b| a.name.cmp(&b.name));
203249

0 commit comments

Comments
 (0)