Add functionality to diff specific Git commits

In this commit, functionality is added to generate diffs of specific Git commits for a given project. The Git diffing function is modified to generate strings of diffs in addition to its existing behavior, and an additional function is added to the application to perform diffing based on specified Git commit ids.

Main changes:
- Added the `git_commit_diff` function which takes a project id and commit id, retrieves the corresponding Git repository, finds the specific commit, and generates a diff against its parent commit. 
- The resulting diff is converted to a string using the existing `diff_hunks_to_string` function.
- The `diff_hunks_to_string` function is updated to be a standalone function as it is now utilized in two places.
- Added the `getCommitDiff` function to the front-end, which invokes the newly added `git_commit_diff`.
- The `git_commit_diff` function is added to the main function, ensuring it can be executed in the application
This commit is contained in:
Kiril Videlov 2023-08-29 14:24:04 +02:00 committed by Kiril Videlov
parent 0b24304698
commit 5ab7a7503a
4 changed files with 63 additions and 3 deletions

View File

@ -352,8 +352,35 @@ impl App {
&diff::Options { context_lines }, &diff::Options { context_lines },
) )
.context("failed to diff")?; .context("failed to diff")?;
let diff = Self::diff_hunks_to_string(diff);
Ok(diff)
}
pub fn git_commit_diff(
&self,
project_id: &str,
commit_id: &str,
) -> Result<HashMap<path::PathBuf, String>> {
let project = self.gb_project(project_id)?;
let project_repository = project_repository::Repository::open(&project)
.context("failed to open project repository")?;
let diff = diff let commit = project_repository
.git_repository
.find_commit(git2::Oid::from_str(commit_id).unwrap())?;
let parent = commit.parent(0).context("failed to get parent commit")?;
let commit_tree = commit.tree().context("failed to get commit tree")?;
let parent_tree = parent.tree().context("failed to get parent tree")?;
let diff = diff::trees(&project_repository, &parent_tree, &commit_tree)?;
let diff = Self::diff_hunks_to_string(diff);
Ok(diff)
}
fn diff_hunks_to_string(
diff: HashMap<path::PathBuf, Vec<project_repository::diff::Hunk>>,
) -> HashMap<path::PathBuf, String> {
return diff
.into_iter() .into_iter()
.map(|(file_path, hunks)| { .map(|(file_path, hunks)| {
( (
@ -366,8 +393,6 @@ impl App {
) )
}) })
.collect::<HashMap<_, _>>(); .collect::<HashMap<_, _>>();
Ok(diff)
} }
pub fn git_match_paths(&self, project_id: &str, pattern: &str) -> Result<Vec<String>> { pub fn git_match_paths(&self, project_id: &str, pattern: &str) -> Result<Vec<String>> {

View File

@ -288,6 +288,25 @@ async fn git_wd_diff(
Ok(diff) Ok(diff)
} }
#[tauri::command(async)]
#[instrument(name = "git_commit_diff", skip(handle))]
async fn git_commit_diff(
handle: tauri::AppHandle,
project_id: &str,
commit_id: &str,
) -> Result<HashMap<path::PathBuf, String>, Error> {
let app = handle.state::<app::App>();
let diff = app
.git_commit_diff(project_id, commit_id)
.with_context(|| {
format!(
"failed to get git diff for project {} and commit {}",
project_id, commit_id
)
})?;
Ok(diff)
}
#[tauri::command(async)] #[tauri::command(async)]
#[instrument(name = "git_match_paths", skip(handle))] #[instrument(name = "git_match_paths", skip(handle))]
async fn git_match_paths( async fn git_match_paths(
@ -708,6 +727,7 @@ async fn main() {
git_stage, git_stage,
git_unstage, git_unstage,
git_wd_diff, git_wd_diff,
git_commit_diff,
delete_all_data, delete_all_data,
get_logs_archive_path, get_logs_archive_path,
get_project_archive_path, get_project_archive_path,

View File

@ -11,6 +11,10 @@ const list = (params: { projectId: string; contextLines?: number }) =>
const stores: Record<string, WritableLoadable<Record<string, string>>> = {}; const stores: Record<string, WritableLoadable<Record<string, string>>> = {};
export function getCommitDiff(params: { projectId: string; commitId: string }) {
return invoke<Record<string, string>>('git_commit_diff', params);
}
export function getDiffsStore(params: { projectId: string }) { export function getDiffsStore(params: { projectId: string }) {
if (stores[params.projectId]) return stores[params.projectId]; if (stores[params.projectId]) return stores[params.projectId];
const store = asyncWritable([], () => list(params)); const store = asyncWritable([], () => list(params));

View File

@ -5,6 +5,7 @@
import type { BranchController } from '$lib/vbranches/branchController'; import type { BranchController } from '$lib/vbranches/branchController';
import Scrollbar from '$lib/components/Scrollbar.svelte'; import Scrollbar from '$lib/components/Scrollbar.svelte';
import { projectMergeUpstreamWarningDismissed } from '$lib/config/config'; import { projectMergeUpstreamWarningDismissed } from '$lib/config/config';
// import { getCommitDiff } from '$lib/api/git/diffs';
export let base: BaseBranch; export let base: BaseBranch;
export let branchController: BranchController; export let branchController: BranchController;
@ -72,6 +73,16 @@
<div class="flex flex-col gap-y-2"> <div class="flex flex-col gap-y-2">
{#each base.recentCommits as commit} {#each base.recentCommits as commit}
<CommitCard url={base.commitUrl(commit.id)} {commit} /> <CommitCard url={base.commitUrl(commit.id)} {commit} />
<!-- <button
on:click={() => {
getCommitDiff({ projectId: branchController.projectId, commitId: commit.id }).then(
(result) => {
console.log(result);
}
);
}}
class="w-full bg-red-400">{commit.id}</button
> -->
{/each} {/each}
</div> </div>
</div> </div>