mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-18 06:22:28 +03:00
use new snapshot types
This commit is contained in:
parent
371a944e71
commit
5420fc3e3c
@ -19,7 +19,7 @@ pub struct Snapshot {
|
||||
/// Snapshot creation time in epoch milliseconds
|
||||
pub created_at: i64,
|
||||
/// Snapshot details as persisted in the commit message
|
||||
pub details: SnapshotDetails,
|
||||
pub details: Option<SnapshotDetails>,
|
||||
}
|
||||
|
||||
/// The payload of a snapshot commit
|
||||
@ -40,6 +40,19 @@ pub struct SnapshotDetails {
|
||||
pub trailers: Vec<Trailer>,
|
||||
}
|
||||
|
||||
impl SnapshotDetails {
|
||||
pub fn new(operation: OperationType) -> Self {
|
||||
let title = operation.to_string();
|
||||
SnapshotDetails {
|
||||
version: Default::default(),
|
||||
operation,
|
||||
title,
|
||||
body: None,
|
||||
trailers: vec![],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for SnapshotDetails {
|
||||
type Err = anyhow::Error;
|
||||
|
||||
@ -128,11 +141,12 @@ pub enum OperationType {
|
||||
DiscardFile,
|
||||
AmendCommit,
|
||||
UndoCommit,
|
||||
UnapplyBranchError,
|
||||
UnapplyBranch,
|
||||
CherryPick,
|
||||
SquashCommit,
|
||||
UpdateCommitMessage,
|
||||
MoveCommit,
|
||||
RestoreFromSnapshot,
|
||||
Unknown,
|
||||
}
|
||||
|
||||
@ -164,11 +178,12 @@ impl FromStr for OperationType {
|
||||
"DiscardFile" => Ok(OperationType::DiscardFile),
|
||||
"AmendCommit" => Ok(OperationType::AmendCommit),
|
||||
"UndoCommit" => Ok(OperationType::UndoCommit),
|
||||
"UnapplyBranchError" => Ok(OperationType::UnapplyBranchError),
|
||||
"UnapplyBranch" => Ok(OperationType::UnapplyBranch),
|
||||
"CherryPick" => Ok(OperationType::CherryPick),
|
||||
"SquashCommit" => Ok(OperationType::SquashCommit),
|
||||
"UpdateCommitMessage" => Ok(OperationType::UpdateCommitMessage),
|
||||
"MoveCommit" => Ok(OperationType::MoveCommit),
|
||||
"RestoreFromSnapshot" => Ok(OperationType::RestoreFromSnapshot),
|
||||
_ => Ok(OperationType::Unknown),
|
||||
}
|
||||
}
|
||||
@ -176,6 +191,11 @@ impl FromStr for OperationType {
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Serialize)]
|
||||
pub struct Version(u32);
|
||||
impl Default for Version {
|
||||
fn default() -> Self {
|
||||
Version(1)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Version {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
@ -292,24 +312,25 @@ mod tests {
|
||||
let snapshot = Snapshot {
|
||||
id: commit_sha.clone(),
|
||||
created_at,
|
||||
details,
|
||||
details: Some(details),
|
||||
};
|
||||
assert_eq!(snapshot.id, commit_sha);
|
||||
assert_eq!(snapshot.details.version.0, 1);
|
||||
assert_eq!(snapshot.details.operation, OperationType::CreateCommit);
|
||||
assert_eq!(snapshot.details.title, "Create a new snapshot");
|
||||
assert_eq!(snapshot.created_at, created_at);
|
||||
let details = snapshot.details.unwrap();
|
||||
assert_eq!(details.version.0, 1);
|
||||
assert_eq!(details.operation, OperationType::CreateCommit);
|
||||
assert_eq!(details.title, "Create a new snapshot");
|
||||
assert_eq!(
|
||||
snapshot.details.body,
|
||||
details.body,
|
||||
Some("Body text 1\nBody text2\n\nBody text 3".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
snapshot.details.trailers,
|
||||
details.trailers,
|
||||
vec![Trailer {
|
||||
key: "Foo".to_string(),
|
||||
value: "Bar".to_string(),
|
||||
}]
|
||||
);
|
||||
assert_eq!(snapshot.created_at, created_at);
|
||||
assert_eq!(snapshot.details.to_string(), commit_message);
|
||||
assert_eq!(details.to_string(), commit_message);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
mod entry;
|
||||
pub mod entry;
|
||||
mod reflog;
|
||||
pub mod snapshot;
|
||||
mod state;
|
||||
|
@ -1,22 +1,14 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use anyhow::Result;
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::{projects::Project, virtual_branches::VirtualBranchesHandle};
|
||||
|
||||
use super::{reflog::set_reference_to_oplog, state::OplogHandle};
|
||||
|
||||
/// A snapshot of the repository and virtual branches state that GitButler can restore to.
|
||||
/// It captures the state of the working directory, virtual branches and commits.
|
||||
#[derive(Debug, PartialEq, Clone, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SnapshotEntry {
|
||||
/// The sha of the commit that represents the snapshot.
|
||||
pub sha: String,
|
||||
/// Textual description of the snapshot.
|
||||
pub label: String,
|
||||
/// The time the snapshot was created at in milliseconds since epoch.
|
||||
pub created_at: i64,
|
||||
}
|
||||
use super::{
|
||||
entry::{OperationType, Snapshot, SnapshotDetails, Trailer},
|
||||
reflog::set_reference_to_oplog,
|
||||
state::OplogHandle,
|
||||
};
|
||||
|
||||
/// Creates a snapshot of the current state of the repository and virtual branches using the given label.
|
||||
///
|
||||
@ -25,7 +17,7 @@ pub struct SnapshotEntry {
|
||||
/// - A fake branch `gitbutler/target` is created and maintained in order to keep the oplog head reachable.
|
||||
///
|
||||
/// The state of virtual branches `.git/gitbutler/virtual_branches.toml` is copied to the project root so that it is snapshotted.
|
||||
pub fn create(project: &Project, label: &str) -> Result<()> {
|
||||
pub fn create(project: &Project, details: SnapshotDetails) -> Result<()> {
|
||||
if project.enable_snapshots.is_none() || project.enable_snapshots == Some(false) {
|
||||
return Ok(());
|
||||
}
|
||||
@ -67,7 +59,7 @@ pub fn create(project: &Project, label: &str) -> Result<()> {
|
||||
None,
|
||||
&signature,
|
||||
&signature,
|
||||
label,
|
||||
&details.to_string(),
|
||||
&tree,
|
||||
&[&oplog_head_commit],
|
||||
)?;
|
||||
@ -102,7 +94,7 @@ pub fn create(project: &Project, label: &str) -> Result<()> {
|
||||
/// An alternative way of retrieving the snapshots would be to manually the oplog head `git log <oplog_head>` available in `.git/gitbutler/oplog.toml`.
|
||||
///
|
||||
/// If there are no snapshots, an empty list is returned.
|
||||
pub fn list(project: Project, limit: usize) -> Result<Vec<SnapshotEntry>> {
|
||||
pub fn list(project: Project, limit: usize) -> Result<Vec<Snapshot>> {
|
||||
let repo_path = project.path.as_path();
|
||||
let repo = git2::Repository::init(repo_path)?;
|
||||
|
||||
@ -128,9 +120,14 @@ pub fn list(project: Project, limit: usize) -> Result<Vec<SnapshotEntry>> {
|
||||
if commit.parent_count() > 1 {
|
||||
break;
|
||||
}
|
||||
snapshots.push(SnapshotEntry {
|
||||
sha: commit_id.to_string(),
|
||||
label: commit.summary().unwrap_or_default().to_string(),
|
||||
|
||||
let details = commit
|
||||
.summary()
|
||||
.and_then(|msg| SnapshotDetails::from_str(msg).ok());
|
||||
|
||||
snapshots.push(Snapshot {
|
||||
id: commit_id.to_string(),
|
||||
details,
|
||||
created_at: commit.time().seconds() * 1000,
|
||||
});
|
||||
|
||||
@ -167,8 +164,17 @@ pub fn restore(project: &Project, sha: String) -> Result<()> {
|
||||
)?;
|
||||
|
||||
// create new snapshot
|
||||
let label = format!("Restored from {}", &sha);
|
||||
create(project, &label)?;
|
||||
let details = SnapshotDetails {
|
||||
version: Default::default(),
|
||||
operation: OperationType::RestoreFromSnapshot,
|
||||
title: "Restored from snapshot".to_string(),
|
||||
body: None,
|
||||
trailers: vec![Trailer {
|
||||
key: "restored_from".to_string(),
|
||||
value: sha,
|
||||
}],
|
||||
};
|
||||
create(project, details)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -1,4 +1,10 @@
|
||||
use crate::{error::Error, snapshots::snapshot};
|
||||
use crate::{
|
||||
error::Error,
|
||||
snapshots::{
|
||||
entry::{OperationType, SnapshotDetails},
|
||||
snapshot,
|
||||
},
|
||||
};
|
||||
use std::{collections::HashMap, path::Path, sync::Arc};
|
||||
|
||||
use anyhow::Context;
|
||||
@ -407,7 +413,11 @@ impl ControllerInner {
|
||||
run_hooks,
|
||||
)
|
||||
.map_err(Into::into);
|
||||
snapshot::create(project_repository.project(), "create commit")?;
|
||||
|
||||
snapshot::create(
|
||||
project_repository.project(),
|
||||
SnapshotDetails::new(OperationType::CreateCommit),
|
||||
)?;
|
||||
result
|
||||
})
|
||||
}
|
||||
@ -455,7 +465,10 @@ impl ControllerInner {
|
||||
|
||||
self.with_verify_branch(project_id, |project_repository, _| {
|
||||
let branch_id = super::create_virtual_branch(project_repository, create)?.id;
|
||||
snapshot::create(project_repository.project(), "create branch")?;
|
||||
snapshot::create(
|
||||
project_repository.project(),
|
||||
SnapshotDetails::new(OperationType::CreateBranch),
|
||||
)?;
|
||||
Ok(branch_id)
|
||||
})
|
||||
}
|
||||
@ -484,7 +497,10 @@ impl ControllerInner {
|
||||
signing_key.as_ref(),
|
||||
user,
|
||||
)?;
|
||||
snapshot::create(project_repository.project(), "create branch")?;
|
||||
snapshot::create(
|
||||
project_repository.project(),
|
||||
SnapshotDetails::new(OperationType::CreateBranch),
|
||||
)?;
|
||||
Ok(result)
|
||||
})
|
||||
}
|
||||
@ -517,7 +533,10 @@ impl ControllerInner {
|
||||
let project = self.projects.get(project_id)?;
|
||||
let project_repository = project_repository::Repository::open(&project)?;
|
||||
let result = super::set_base_branch(&project_repository, target_branch)?;
|
||||
snapshot::create(project_repository.project(), "set base branch")?;
|
||||
snapshot::create(
|
||||
project_repository.project(),
|
||||
SnapshotDetails::new(OperationType::SetBaseBranch),
|
||||
)?;
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
@ -547,7 +566,10 @@ impl ControllerInner {
|
||||
user,
|
||||
)
|
||||
.map_err(Into::into);
|
||||
snapshot::create(project_repository.project(), "merge upstream")?;
|
||||
snapshot::create(
|
||||
project_repository.project(),
|
||||
SnapshotDetails::new(OperationType::MergeUpstream),
|
||||
)?;
|
||||
result
|
||||
})
|
||||
}
|
||||
@ -569,7 +591,10 @@ impl ControllerInner {
|
||||
|
||||
let result = super::update_base_branch(project_repository, user, signing_key.as_ref())
|
||||
.map_err(Into::into);
|
||||
snapshot::create(project_repository.project(), "update workspace base")?;
|
||||
snapshot::create(
|
||||
project_repository.project(),
|
||||
SnapshotDetails::new(OperationType::UpdateWorkspaceBase),
|
||||
)?;
|
||||
result
|
||||
})
|
||||
}
|
||||
@ -582,23 +607,23 @@ impl ControllerInner {
|
||||
let _permit = self.semaphore.acquire().await;
|
||||
|
||||
self.with_verify_branch(project_id, |project_repository, _| {
|
||||
let label = if branch_update.ownership.is_some() {
|
||||
"move hunk"
|
||||
let details = if branch_update.ownership.is_some() {
|
||||
SnapshotDetails::new(OperationType::MoveHunk)
|
||||
} else if branch_update.name.is_some() {
|
||||
"update branch name"
|
||||
SnapshotDetails::new(OperationType::UpdateBranchName)
|
||||
} else if branch_update.notes.is_some() {
|
||||
"update branch notes"
|
||||
SnapshotDetails::new(OperationType::UpdateBranchNotes)
|
||||
} else if branch_update.order.is_some() {
|
||||
"reorder branches"
|
||||
SnapshotDetails::new(OperationType::ReorderBranches)
|
||||
} else if branch_update.selected_for_changes.is_some() {
|
||||
"select default branch"
|
||||
SnapshotDetails::new(OperationType::SelectDefaultVirtualBranch)
|
||||
} else if branch_update.upstream.is_some() {
|
||||
"update remote branch name"
|
||||
SnapshotDetails::new(OperationType::UpdateBranchRemoteName)
|
||||
} else {
|
||||
"update branch"
|
||||
SnapshotDetails::new(OperationType::GenericBranchUpdate)
|
||||
};
|
||||
super::update_branch(project_repository, branch_update)?;
|
||||
snapshot::create(project_repository.project(), label)?;
|
||||
snapshot::create(project_repository.project(), details)?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
@ -612,7 +637,10 @@ impl ControllerInner {
|
||||
|
||||
self.with_verify_branch(project_id, |project_repository, _| {
|
||||
super::delete_branch(project_repository, branch_id)?;
|
||||
snapshot::create(project_repository.project(), "delete branch")?;
|
||||
snapshot::create(
|
||||
project_repository.project(),
|
||||
SnapshotDetails::new(OperationType::DeleteBranch),
|
||||
)?;
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
@ -639,7 +667,10 @@ impl ControllerInner {
|
||||
let result =
|
||||
super::apply_branch(project_repository, branch_id, signing_key.as_ref(), user)
|
||||
.map_err(Into::into);
|
||||
snapshot::create(project_repository.project(), "apply branch")?;
|
||||
snapshot::create(
|
||||
project_repository.project(),
|
||||
SnapshotDetails::new(OperationType::ApplyBranch),
|
||||
)?;
|
||||
result
|
||||
})
|
||||
}
|
||||
@ -654,7 +685,10 @@ impl ControllerInner {
|
||||
self.with_verify_branch(project_id, |project_repository, _| {
|
||||
let result =
|
||||
super::unapply_ownership(project_repository, ownership).map_err(Into::into);
|
||||
snapshot::create(project_repository.project(), "discard hunk")?;
|
||||
snapshot::create(
|
||||
project_repository.project(),
|
||||
SnapshotDetails::new(OperationType::DiscardHunk),
|
||||
)?;
|
||||
result
|
||||
})
|
||||
}
|
||||
@ -668,7 +702,10 @@ impl ControllerInner {
|
||||
|
||||
self.with_verify_branch(project_id, |project_repository, _| {
|
||||
let result = super::reset_files(project_repository, ownership).map_err(Into::into);
|
||||
snapshot::create(project_repository.project(), "discard file")?;
|
||||
snapshot::create(
|
||||
project_repository.project(),
|
||||
SnapshotDetails::new(OperationType::DiscardFile),
|
||||
)?;
|
||||
result
|
||||
})
|
||||
}
|
||||
@ -683,7 +720,10 @@ impl ControllerInner {
|
||||
|
||||
self.with_verify_branch(project_id, |project_repository, _| {
|
||||
let result = super::amend(project_repository, branch_id, ownership).map_err(Into::into);
|
||||
snapshot::create(project_repository.project(), "amend commit")?;
|
||||
snapshot::create(
|
||||
project_repository.project(),
|
||||
SnapshotDetails::new(OperationType::AmendCommit),
|
||||
)?;
|
||||
result
|
||||
})
|
||||
}
|
||||
@ -699,7 +739,10 @@ impl ControllerInner {
|
||||
self.with_verify_branch(project_id, |project_repository, _| {
|
||||
let result = super::reset_branch(project_repository, branch_id, target_commit_oid)
|
||||
.map_err(Into::into);
|
||||
snapshot::create(project_repository.project(), "undo commit")?;
|
||||
snapshot::create(
|
||||
project_repository.project(),
|
||||
SnapshotDetails::new(OperationType::UndoCommit),
|
||||
)?;
|
||||
result
|
||||
})
|
||||
}
|
||||
@ -715,7 +758,10 @@ impl ControllerInner {
|
||||
let result = super::unapply_branch(project_repository, branch_id)
|
||||
.map(|_| ())
|
||||
.map_err(Into::into);
|
||||
snapshot::create(project_repository.project(), "unapply branch")?;
|
||||
snapshot::create(
|
||||
project_repository.project(),
|
||||
SnapshotDetails::new(OperationType::UnapplyBranch),
|
||||
)?;
|
||||
result
|
||||
})
|
||||
}
|
||||
@ -755,7 +801,10 @@ impl ControllerInner {
|
||||
self.with_verify_branch(project_id, |project_repository, _| {
|
||||
let result =
|
||||
super::cherry_pick(project_repository, branch_id, commit_oid).map_err(Into::into);
|
||||
snapshot::create(project_repository.project(), "cherry pick")?;
|
||||
snapshot::create(
|
||||
project_repository.project(),
|
||||
SnapshotDetails::new(OperationType::CherryPick),
|
||||
)?;
|
||||
result
|
||||
})
|
||||
}
|
||||
@ -790,7 +839,10 @@ impl ControllerInner {
|
||||
self.with_verify_branch(project_id, |project_repository, _| {
|
||||
let result =
|
||||
super::squash(project_repository, branch_id, commit_oid).map_err(Into::into);
|
||||
snapshot::create(project_repository.project(), "squash commit")?;
|
||||
snapshot::create(
|
||||
project_repository.project(),
|
||||
SnapshotDetails::new(OperationType::SquashCommit),
|
||||
)?;
|
||||
result
|
||||
})
|
||||
}
|
||||
@ -807,7 +859,10 @@ impl ControllerInner {
|
||||
let result =
|
||||
super::update_commit_message(project_repository, branch_id, commit_oid, message)
|
||||
.map_err(Into::into);
|
||||
snapshot::create(project_repository.project(), "update commit message")?;
|
||||
snapshot::create(
|
||||
project_repository.project(),
|
||||
SnapshotDetails::new(OperationType::UpdateCommitMessage),
|
||||
)?;
|
||||
result
|
||||
})
|
||||
}
|
||||
@ -886,7 +941,10 @@ impl ControllerInner {
|
||||
signing_key.as_ref(),
|
||||
)
|
||||
.map_err(Into::into);
|
||||
snapshot::create(project_repository.project(), "moved commit")?;
|
||||
snapshot::create(
|
||||
project_repository.project(),
|
||||
SnapshotDetails::new(OperationType::MoveCommit),
|
||||
)?;
|
||||
result
|
||||
})
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
use crate::error::Error;
|
||||
use anyhow::Context;
|
||||
use gitbutler_core::{
|
||||
projects, projects::ProjectId, snapshots::snapshot, snapshots::snapshot::SnapshotEntry,
|
||||
projects, projects::ProjectId, snapshots::entry::Snapshot, snapshots::snapshot,
|
||||
};
|
||||
use tauri::Manager;
|
||||
use tracing::instrument;
|
||||
@ -12,7 +12,7 @@ pub async fn list_snapshots(
|
||||
handle: tauri::AppHandle,
|
||||
project_id: ProjectId,
|
||||
limit: usize,
|
||||
) -> Result<Vec<SnapshotEntry>, Error> {
|
||||
) -> Result<Vec<Snapshot>, Error> {
|
||||
let project = handle
|
||||
.state::<projects::Controller>()
|
||||
.get(&project_id)
|
||||
|
Loading…
Reference in New Issue
Block a user