mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2025-01-04 07:25:44 +03:00
add an enpoint for getting the snapshot diff
This commit is contained in:
parent
2006511a80
commit
58c124627a
@ -218,7 +218,7 @@ pub fn without_large_files(
|
|||||||
/// `repository` should be `None` if there is no reason to access the workdir, which it will do to
|
/// `repository` should be `None` if there is no reason to access the workdir, which it will do to
|
||||||
/// keep the binary data in the object database, which otherwise would be lost to the system
|
/// keep the binary data in the object database, which otherwise would be lost to the system
|
||||||
/// (it's not reconstructable from the delta, or it's not attempted).
|
/// (it's not reconstructable from the delta, or it's not attempted).
|
||||||
fn hunks_by_filepath(repo: Option<&Repository>, diff: &git2::Diff) -> Result<DiffByPathMap> {
|
pub fn hunks_by_filepath(repo: Option<&Repository>, diff: &git2::Diff) -> Result<DiffByPathMap> {
|
||||||
enum LineOrHexHash<'a> {
|
enum LineOrHexHash<'a> {
|
||||||
Line(Cow<'a, BStr>),
|
Line(Cow<'a, BStr>),
|
||||||
HexHashOfBinaryBlob(String),
|
HexHashOfBinaryBlob(String),
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use git2::FileMode;
|
use git2::FileMode;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::fs;
|
use std::collections::HashMap;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
|
use std::{fs, path::PathBuf};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
|
||||||
use crate::projects::Project;
|
use crate::git::diff::FileDiff;
|
||||||
|
use crate::{git::diff::hunks_by_filepath, projects::Project};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
entry::{OperationType, Snapshot, SnapshotDetails, Trailer},
|
entry::{OperationType, Snapshot, SnapshotDetails, Trailer},
|
||||||
@ -54,6 +56,10 @@ pub trait Oplog {
|
|||||||
///
|
///
|
||||||
/// If there are no snapshots, 0 is returned.
|
/// If there are no snapshots, 0 is returned.
|
||||||
fn lines_since_snapshot(&self) -> Result<usize>;
|
fn lines_since_snapshot(&self) -> Result<usize>;
|
||||||
|
/// Returns the diff of the snapshot and it's parent. It only includes the workdir changes.
|
||||||
|
///
|
||||||
|
/// This is useful to show what has changed in this particular snapshot
|
||||||
|
fn snapshot_diff(&self, sha: String) -> Result<HashMap<PathBuf, FileDiff>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Oplog for Project {
|
impl Oplog for Project {
|
||||||
@ -324,6 +330,46 @@ impl Oplog for Project {
|
|||||||
let stats = diff?.stats()?;
|
let stats = diff?.stats()?;
|
||||||
Ok(stats.deletions() + stats.insertions())
|
Ok(stats.deletions() + stats.insertions())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn snapshot_diff(&self, sha: String) -> Result<HashMap<PathBuf, FileDiff>> {
|
||||||
|
let repo_path = self.path.as_path();
|
||||||
|
let repo = git2::Repository::init(repo_path)?;
|
||||||
|
|
||||||
|
let commit = repo.find_commit(git2::Oid::from_str(&sha)?)?;
|
||||||
|
// Top tree
|
||||||
|
let tree = commit.tree()?;
|
||||||
|
let old_tree = commit.parent(0)?.tree()?;
|
||||||
|
|
||||||
|
let wd_tree_entry = tree
|
||||||
|
.get_name("workdir")
|
||||||
|
.ok_or(anyhow!("failed to get workdir tree entry"))?;
|
||||||
|
let old_wd_tree_entry = old_tree
|
||||||
|
.get_name("workdir")
|
||||||
|
.ok_or(anyhow!("failed to get old workdir tree entry"))?;
|
||||||
|
|
||||||
|
// workdir tree
|
||||||
|
let wd_tree = repo.find_tree(wd_tree_entry.id())?;
|
||||||
|
let old_wd_tree = repo.find_tree(old_wd_tree_entry.id())?;
|
||||||
|
|
||||||
|
// Exclude files that are larger than the limit (eg. database.sql which may never be intended to be committed)
|
||||||
|
let files_to_exclude = get_exclude_list(&repo)?;
|
||||||
|
// In-memory, libgit2 internal ignore rule
|
||||||
|
repo.add_ignore_rule(&files_to_exclude)?;
|
||||||
|
|
||||||
|
let mut diff_opts = git2::DiffOptions::new();
|
||||||
|
diff_opts
|
||||||
|
.recurse_untracked_dirs(true)
|
||||||
|
.include_untracked(true)
|
||||||
|
.show_binary(true)
|
||||||
|
.ignore_submodules(true)
|
||||||
|
.show_untracked_content(true);
|
||||||
|
|
||||||
|
let diff =
|
||||||
|
repo.diff_tree_to_tree(Some(&old_wd_tree), Some(&wd_tree), Some(&mut diff_opts))?;
|
||||||
|
|
||||||
|
let hunks = hunks_by_filepath(None, &diff)?;
|
||||||
|
Ok(hunks)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn restore_conflicts_tree(
|
fn restore_conflicts_tree(
|
||||||
|
@ -234,6 +234,7 @@ fn main() {
|
|||||||
virtual_branches::commands::move_commit,
|
virtual_branches::commands::move_commit,
|
||||||
undo::list_snapshots,
|
undo::list_snapshots,
|
||||||
undo::restore_snapshot,
|
undo::restore_snapshot,
|
||||||
|
undo::snapshot_diff,
|
||||||
menu::menu_item_set_enabled,
|
menu::menu_item_set_enabled,
|
||||||
keys::commands::get_public_key,
|
keys::commands::get_public_key,
|
||||||
github::commands::init_device_oauth,
|
github::commands::init_device_oauth,
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
|
use gitbutler_core::git::diff::FileDiff;
|
||||||
use gitbutler_core::{
|
use gitbutler_core::{
|
||||||
ops::{entry::Snapshot, oplog::Oplog},
|
ops::{entry::Snapshot, oplog::Oplog},
|
||||||
projects::{self, ProjectId},
|
projects::{self, ProjectId},
|
||||||
};
|
};
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::path::PathBuf;
|
||||||
use tauri::Manager;
|
use tauri::Manager;
|
||||||
use tracing::instrument;
|
use tracing::instrument;
|
||||||
|
|
||||||
@ -37,3 +40,18 @@ pub async fn restore_snapshot(
|
|||||||
project.restore_snapshot(sha)?;
|
project.restore_snapshot(sha)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tauri::command(async)]
|
||||||
|
#[instrument(skip(handle), err(Debug))]
|
||||||
|
pub async fn snapshot_diff(
|
||||||
|
handle: tauri::AppHandle,
|
||||||
|
project_id: ProjectId,
|
||||||
|
sha: String,
|
||||||
|
) -> Result<HashMap<PathBuf, FileDiff>, Error> {
|
||||||
|
let project = handle
|
||||||
|
.state::<projects::Controller>()
|
||||||
|
.get(&project_id)
|
||||||
|
.context("failed to get project")?;
|
||||||
|
let diff = project.snapshot_diff(sha)?;
|
||||||
|
Ok(diff)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user