feat(commits): enhance commit listing with pagination and skipping
This update introduces pagination and skipping functionality for the commit listing feature, allowing users to load commits in pages and navigate through them more efficiently. The UI has been adjusted to support loading more commits dynamically, improving the overall user experience when dealing with large repositories. - Added pagination support for commit history - Introduced a loading mechanism for fetching more commits - Updated UI components to reflect changes in commit loading behavior
This commit is contained in:
+53
-3
@@ -2917,17 +2917,31 @@ fn cherry_pick_status_or_error(
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn list_commits(path: String, limit: Option<u32>) -> Result<Vec<GitCommit>, String> {
|
||||
pub fn list_commits(
|
||||
path: String,
|
||||
limit: Option<u32>,
|
||||
skip: Option<u32>,
|
||||
) -> Result<Vec<GitCommit>, String> {
|
||||
let repo = resolve_repo(&path)?;
|
||||
commits_for_repo(&repo, limit)
|
||||
commit_page_for_repo(&repo, limit, skip)
|
||||
}
|
||||
|
||||
fn commits_for_repo(repo: &Path, limit: Option<u32>) -> Result<Vec<GitCommit>, String> {
|
||||
let bounded_limit = limit.unwrap_or(100).clamp(1, 500);
|
||||
commit_page_for_repo(repo, Some(bounded_limit), None)
|
||||
}
|
||||
|
||||
fn commit_page_for_repo(
|
||||
repo: &Path,
|
||||
limit: Option<u32>,
|
||||
skip: Option<u32>,
|
||||
) -> Result<Vec<GitCommit>, String> {
|
||||
if verify_commit(repo, "HEAD").is_err() {
|
||||
return Ok(Vec::new());
|
||||
}
|
||||
|
||||
let limit = limit.unwrap_or(100).clamp(1, 500).to_string();
|
||||
let limit = limit.unwrap_or(100).clamp(1, 5_000).to_string();
|
||||
let skip = skip.unwrap_or(0).min(10_000_000).to_string();
|
||||
// Fetch the per-commit changed files inline via `--name-status` in a single
|
||||
// `git log` process, instead of spawning one `git diff-tree` per commit
|
||||
// (which was ~100 extra processes and the main cost of opening a repo).
|
||||
@@ -2943,6 +2957,8 @@ fn commits_for_repo(repo: &Path, limit: Option<u32>) -> Result<Vec<GitCommit>, S
|
||||
"-z",
|
||||
"--root",
|
||||
"--pretty=format:%x1e%H%x1f%h%x1f%an%x1f%ae%x1f%aI%x1f%D%x1f%P%x1f%s%x1f",
|
||||
"--skip",
|
||||
skip.as_str(),
|
||||
"-n",
|
||||
limit.as_str(),
|
||||
],
|
||||
@@ -6339,6 +6355,40 @@ mod tests {
|
||||
}));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn commit_pages_use_stable_non_overlapping_offsets() {
|
||||
let repo = init_temp_repo("commit_pages");
|
||||
commit_initial_file(&repo.path);
|
||||
|
||||
for index in 1..=3 {
|
||||
fs::write(repo.path.join("old.txt"), format!("version {index}\n"))
|
||||
.expect("tracked file should change");
|
||||
run_git_test(&repo.path, ["add", "old.txt"]);
|
||||
run_git_test(
|
||||
&repo.path,
|
||||
["commit", "-q", "-m", format!("commit {index}").as_str()],
|
||||
);
|
||||
}
|
||||
|
||||
let all = commits_for_repo(&repo.path, Some(10)).expect("commits should load");
|
||||
let first = commit_page_for_repo(&repo.path, Some(2), Some(0))
|
||||
.expect("first commit page should load");
|
||||
let second = commit_page_for_repo(&repo.path, Some(2), Some(2))
|
||||
.expect("second commit page should load");
|
||||
|
||||
assert_eq!(first.len(), 2);
|
||||
assert_eq!(second.len(), 2);
|
||||
assert_eq!(first[0].hash, all[0].hash);
|
||||
assert_eq!(first[1].hash, all[1].hash);
|
||||
assert_eq!(second[0].hash, all[2].hash);
|
||||
assert_eq!(second[1].hash, all[3].hash);
|
||||
assert!(
|
||||
first
|
||||
.iter()
|
||||
.all(|commit| second.iter().all(|other| other.hash != commit.hash))
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[cfg_attr(
|
||||
windows,
|
||||
|
||||
Reference in New Issue
Block a user