mirror of
https://github.com/gitbutlerapp/gitbutler.git
synced 2024-12-01 12:26:02 +03:00
refactor reflog.rs and slightly adjust snapshot.rs
* reflog - use `gix` to parse reflog, both in code as well as in tests (to be sure it's not malformed) - avoid double-writes to reflog, instead finish transformation in memory and write final result - assure the ref is present, independently of the reflog, catching more 'weird' states. * minor improvements to `snapshot.rs` to avoid unnecessary clones
This commit is contained in:
parent
d952db0920
commit
e82950f177
@ -10,6 +10,9 @@ use anyhow::Result;
|
||||
use tracing::instrument;
|
||||
|
||||
use crate::git::diff::FileDiff;
|
||||
use crate::virtual_branches::integration::{
|
||||
GITBUTLER_INTEGRATION_COMMIT_AUTHOR_EMAIL, GITBUTLER_INTEGRATION_COMMIT_AUTHOR_NAME,
|
||||
};
|
||||
use crate::virtual_branches::Branch;
|
||||
use crate::{git, git::diff::hunks_by_filepath, projects::Project};
|
||||
|
||||
@ -232,9 +235,11 @@ impl Project {
|
||||
}
|
||||
|
||||
// Construct a new commit
|
||||
let name = "GitButler";
|
||||
let email = "gitbutler@gitbutler.com";
|
||||
let signature = git2::Signature::now(name, email).unwrap();
|
||||
let signature = git2::Signature::now(
|
||||
GITBUTLER_INTEGRATION_COMMIT_AUTHOR_NAME,
|
||||
GITBUTLER_INTEGRATION_COMMIT_AUTHOR_EMAIL,
|
||||
)
|
||||
.unwrap();
|
||||
let parents = if let Some(ref oplog_head_commit) = oplog_head_commit {
|
||||
vec![oplog_head_commit]
|
||||
} else {
|
||||
@ -255,7 +260,7 @@ impl Project {
|
||||
// grab the target tree sha
|
||||
let default_target_sha = vb_state.get_default_target()?.sha;
|
||||
|
||||
set_reference_to_oplog(self, default_target_sha, new_commit_oid.into())?;
|
||||
set_reference_to_oplog(&self.path, default_target_sha, new_commit_oid.into())?;
|
||||
|
||||
Ok(Some(new_commit_oid.into()))
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
use crate::fs::write;
|
||||
use crate::git;
|
||||
use anyhow::Result;
|
||||
use itertools::Itertools;
|
||||
use std::path::PathBuf;
|
||||
use anyhow::{Context, Result};
|
||||
use gix::config::tree::Key;
|
||||
use std::path::Path;
|
||||
|
||||
use crate::projects::Project;
|
||||
use crate::virtual_branches::integration::{
|
||||
GITBUTLER_INTEGRATION_COMMIT_AUTHOR_EMAIL, GITBUTLER_INTEGRATION_COMMIT_AUTHOR_NAME,
|
||||
};
|
||||
|
||||
/// Sets a reference to the oplog head commit such that snapshots are reachable and will not be garbage collected.
|
||||
/// We want to achieve 2 things:
|
||||
@ -14,20 +16,21 @@ use crate::projects::Project;
|
||||
/// This needs to be invoked whenever the target head or the oplog head change.
|
||||
///
|
||||
/// How it works:
|
||||
/// First a reference gitbutler/target is created, pointing to the head of the target (trunk) branch. This is a fake branch that we don't need to care about. If it doesn't exist, it is created.
|
||||
/// Then in the reflog entry logs/refs/heads/gitbutler/target we pretend that the the ref originally pointed to the oplog head commit like so:
|
||||
/// First a reference gitbutler/target is created, pointing to the head of the target (trunk) branch.
|
||||
/// This is a fake branch that we don't need to care about. If it doesn't exist, it is created.
|
||||
/// Then in the reflog entry logs/refs/heads/gitbutler/target we pretend that the ref originally pointed to the
|
||||
/// oplog head commit like so:
|
||||
///
|
||||
/// 0000000000000000000000000000000000000000 <target branch head sha>
|
||||
/// <target branch head sha> <oplog head sha>
|
||||
///
|
||||
/// The reflog entry is continuously updated to refer to the current target and oplog head commits.
|
||||
pub(crate) fn set_reference_to_oplog(
|
||||
project: &Project,
|
||||
pub(super) fn set_reference_to_oplog(
|
||||
worktree_dir: &Path,
|
||||
target_head_sha: git::Oid,
|
||||
oplog_head_sha: git::Oid,
|
||||
) -> Result<()> {
|
||||
let repo_path = project.path.as_path();
|
||||
let reflog_file_path = repo_path
|
||||
let reflog_file_path = worktree_dir
|
||||
.join(".git")
|
||||
.join("logs")
|
||||
.join("refs")
|
||||
@ -35,145 +38,244 @@ pub(crate) fn set_reference_to_oplog(
|
||||
.join("gitbutler")
|
||||
.join("target");
|
||||
|
||||
if !reflog_file_path.exists() {
|
||||
let repo = git2::Repository::init(repo_path)?;
|
||||
let commit = repo.find_commit(target_head_sha.into())?;
|
||||
repo.branch("gitbutler/target", &commit, false)?;
|
||||
let mut repo = gix::open_opts(
|
||||
worktree_dir,
|
||||
// We may override the username as we only write a specific commit log, unrelated to the user.
|
||||
gix::open::Options::isolated().config_overrides([
|
||||
gix::config::tree::User::NAME
|
||||
.validated_assignment(GITBUTLER_INTEGRATION_COMMIT_AUTHOR_NAME.into())?,
|
||||
gix::config::tree::User::EMAIL
|
||||
.validated_assignment(GITBUTLER_INTEGRATION_COMMIT_AUTHOR_EMAIL.into())?,
|
||||
]),
|
||||
)?;
|
||||
// The check is here only to avoid unnecessary writes
|
||||
if repo.try_find_reference("gitbutler/target")?.is_none() {
|
||||
repo.refs.write_reflog = gix::refs::store::WriteReflog::Always;
|
||||
repo.reference(
|
||||
"refs/heads/gitbutler/target",
|
||||
target_head_sha.to_string().parse::<gix::ObjectId>()?,
|
||||
gix::refs::transaction::PreviousValue::Any,
|
||||
format!("branch: Created from {target_head_sha}"),
|
||||
)?;
|
||||
}
|
||||
|
||||
if !reflog_file_path.exists() {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Could not create gitbutler/target which is needed for undo snapshotting"
|
||||
));
|
||||
}
|
||||
|
||||
set_target_ref(&reflog_file_path, &target_head_sha.to_string())?;
|
||||
set_oplog_ref(&reflog_file_path, &oplog_head_sha.to_string())?;
|
||||
let mut content = std::fs::read_to_string(&reflog_file_path)
|
||||
.context("A reflog for gitbutler/target which is needed for undo snapshotting")?;
|
||||
content = set_target_ref(&content, &target_head_sha.to_string()).with_context(|| {
|
||||
format!(
|
||||
"Something was wrong with \"{}\"",
|
||||
reflog_file_path.display()
|
||||
)
|
||||
})?;
|
||||
content = set_oplog_ref(&content, &oplog_head_sha.to_string())?;
|
||||
write(reflog_file_path, content)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn set_target_ref(file_path: &PathBuf, sha: &str) -> Result<()> {
|
||||
// 0000000000000000000000000000000000000000 82873b54925ab268e9949557f28d070d388e7774 Kiril Videlov <kiril@videlov.com> 1714037434 +0200 branch: Created from 82873b54925ab268e9949557f28d070d388e7774
|
||||
let content = std::fs::read_to_string(file_path)?;
|
||||
let mut lines = content.lines().collect::<Vec<_>>();
|
||||
let mut first_line = lines[0].split_whitespace().collect_vec();
|
||||
let len = first_line.len();
|
||||
first_line[1] = sha;
|
||||
first_line[len - 1] = sha;
|
||||
let binding = first_line.join(" ");
|
||||
lines[0] = &binding;
|
||||
let content = format!("{}\n", lines.join("\n"));
|
||||
write(file_path, content)
|
||||
fn set_target_ref(content: &str, sha: &str) -> Result<String> {
|
||||
// 0000000000000000000000000000000000000000 82873b54925ab268e9949557f28d070d388e7774 Kiril Videlov <kiril@videlov.com> 1714037434 +0200\tbranch: Created from 82873b54925ab268e9949557f28d070d388e7774
|
||||
let mut lines = gix::refs::file::log::iter::forward(content.as_bytes());
|
||||
let mut first_line = lines.next().context("need the creation-line in reflog")??;
|
||||
|
||||
first_line.new_oid = sha.into();
|
||||
let message = format!("branch: Created from {sha}");
|
||||
first_line.message = message.as_str().into();
|
||||
|
||||
Ok(serialize_line(first_line))
|
||||
}
|
||||
|
||||
fn set_oplog_ref(file_path: &PathBuf, sha: &str) -> Result<()> {
|
||||
// 82873b54925ab268e9949557f28d070d388e7774 7e8eab472636a26611214bebea7d6b79c971fb8b Kiril Videlov <kiril@videlov.com> 1714044124 +0200 reset: moving to 7e8eab472636a26611214bebea7d6b79c971fb8b
|
||||
let content = std::fs::read_to_string(file_path)?;
|
||||
let first_line = content.lines().collect::<Vec<_>>().remove(0);
|
||||
fn set_oplog_ref(content: &str, sha: &str) -> Result<String> {
|
||||
// 82873b54925ab268e9949557f28d070d388e7774 7e8eab472636a26611214bebea7d6b79c971fb8b Kiril Videlov <kiril@videlov.com> 1714044124 +0200\treset: moving to 7e8eab472636a26611214bebea7d6b79c971fb8b
|
||||
let mut lines = gix::refs::file::log::iter::forward(content.as_bytes());
|
||||
let first_line = lines.next().context("need the creation-line in reflog")??;
|
||||
|
||||
let target_ref = first_line.split_whitespace().collect_vec()[1];
|
||||
let the_rest = first_line.split_whitespace().collect_vec()[2..].join(" ");
|
||||
let the_rest = the_rest.replace("branch", " reset");
|
||||
let mut the_rest_split = the_rest.split(':').collect_vec();
|
||||
let new_msg = format!(" moving to {}", sha);
|
||||
the_rest_split[1] = &new_msg;
|
||||
let the_rest = the_rest_split.join(":");
|
||||
let new_msg = format!("reset: moving to {}", sha);
|
||||
let mut second_line = first_line.clone();
|
||||
second_line.previous_oid = first_line.new_oid;
|
||||
second_line.new_oid = sha.into();
|
||||
second_line.message = new_msg.as_str().into();
|
||||
|
||||
let second_line = [target_ref, sha, &the_rest].join(" ");
|
||||
Ok(format!(
|
||||
"{}\n{}\n",
|
||||
serialize_line(first_line),
|
||||
serialize_line(second_line)
|
||||
))
|
||||
}
|
||||
|
||||
let content = format!("{}\n", [first_line, &second_line].join("\n"));
|
||||
write(file_path, content)
|
||||
fn serialize_line(line: gix::refs::file::log::LineRef<'_>) -> String {
|
||||
let mut sig = Vec::new();
|
||||
line.signature
|
||||
.write_to(&mut sig)
|
||||
.expect("write to memory succeeds");
|
||||
|
||||
format!(
|
||||
"{} {} {}\t{}",
|
||||
line.previous_oid,
|
||||
line.new_oid,
|
||||
std::str::from_utf8(&sig).expect("no illformed UTF8"),
|
||||
line.message
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
mod set_target_ref {
|
||||
use super::{
|
||||
git, set_reference_to_oplog, GITBUTLER_INTEGRATION_COMMIT_AUTHOR_EMAIL,
|
||||
GITBUTLER_INTEGRATION_COMMIT_AUTHOR_NAME,
|
||||
};
|
||||
use gix::refs::file::log::LineRef;
|
||||
use pretty_assertions::assert_eq;
|
||||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
use tempfile::tempdir;
|
||||
|
||||
#[test]
|
||||
fn test_set_target_ref() {
|
||||
let (dir, commit_id) = setup_repo();
|
||||
let project = Project {
|
||||
path: dir.path().to_path_buf(),
|
||||
..Default::default()
|
||||
};
|
||||
fn reflog_present_but_branch_missing_recreates_branch() -> anyhow::Result<()> {
|
||||
let (dir, commit_id) = setup_repo()?;
|
||||
let worktree_dir = dir.path();
|
||||
|
||||
let log_file_path = dir
|
||||
.path()
|
||||
.join(".git")
|
||||
.join("logs")
|
||||
.join("refs")
|
||||
.join("heads")
|
||||
.join("gitbutler")
|
||||
.join("target");
|
||||
let oplog_sha = git::Oid::from_str("0123456789abcdef0123456789abcdef0123456")?;
|
||||
set_reference_to_oplog(&worktree_dir, commit_id.into(), oplog_sha).expect("success");
|
||||
|
||||
let loose_ref_file = worktree_dir.join(".git/refs/heads/gitbutler/target");
|
||||
std::fs::remove_file(&loose_ref_file)?;
|
||||
|
||||
set_reference_to_oplog(&worktree_dir, commit_id.into(), oplog_sha).expect("success");
|
||||
assert!(
|
||||
loose_ref_file.is_file(),
|
||||
"the file was recreated, just in case there is only a reflog and no branch"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn new_and_update() -> anyhow::Result<()> {
|
||||
let (dir, commit_id) = setup_repo()?;
|
||||
let worktree_dir = dir.path();
|
||||
|
||||
let log_file_path = worktree_dir.join(".git/logs/refs/heads/gitbutler/target");
|
||||
assert!(!log_file_path.exists());
|
||||
|
||||
// Set ref for the first time
|
||||
let oplog_sha = git::Oid::from_str("0123456789abcdef0123456789abcdef0123456").unwrap();
|
||||
assert!(set_reference_to_oplog(&project, commit_id.into(), oplog_sha).is_ok());
|
||||
let oplog_sha = git::Oid::from_str("0123456789abcdef0123456789abcdef0123456")?;
|
||||
set_reference_to_oplog(&worktree_dir, commit_id.into(), oplog_sha).expect("success");
|
||||
assert!(log_file_path.exists());
|
||||
let log_file = std::fs::read_to_string(&log_file_path).unwrap();
|
||||
let log_lines = log_file.lines().collect::<Vec<_>>();
|
||||
assert_eq!(log_lines.len(), 2);
|
||||
assert!(log_lines[0].starts_with(&format!(
|
||||
"0000000000000000000000000000000000000000 {}",
|
||||
commit_id
|
||||
)));
|
||||
assert!(log_lines[0].ends_with(&format!("branch: Created from {}", commit_id)));
|
||||
assert!(log_lines[1].starts_with(&format!("{} {}", commit_id, oplog_sha)));
|
||||
assert!(log_lines[1].ends_with(&format!("reset: moving to {oplog_sha}")));
|
||||
let contents = std::fs::read_to_string(&log_file_path)?;
|
||||
let lines = reflog_lines(&contents);
|
||||
assert_eq!(
|
||||
lines.len(),
|
||||
2,
|
||||
"lines parse and it's exactly two, one for branch creation, another for oplog id"
|
||||
);
|
||||
|
||||
let first_line = &lines[0];
|
||||
assert_eq!(
|
||||
first_line.previous_oid, "0000000000000000000000000000000000000000",
|
||||
"start from nothing"
|
||||
);
|
||||
assert_eq!(
|
||||
first_line.new_oid.to_string(),
|
||||
commit_id.to_string(),
|
||||
"the new hash is the target id"
|
||||
);
|
||||
let first_line_message = format!("branch: Created from {}", commit_id);
|
||||
assert_eq!(first_line.message, first_line_message);
|
||||
assert_signature(first_line.signature);
|
||||
|
||||
let second_line = &lines[1];
|
||||
assert_eq!(
|
||||
second_line.previous_oid.to_string(),
|
||||
commit_id.to_string(),
|
||||
"second entry starts where the first left off"
|
||||
);
|
||||
assert_eq!(second_line.new_oid.to_string(), oplog_sha.to_string());
|
||||
let line2_message = format!("reset: moving to {oplog_sha}");
|
||||
assert_eq!(second_line.message, line2_message);
|
||||
assert_signature(second_line.signature);
|
||||
|
||||
// Update the oplog head only
|
||||
let another_oplog_sha = git2::Oid::zero().into();
|
||||
assert!(set_reference_to_oplog(&project, commit_id.into(), another_oplog_sha).is_ok());
|
||||
let log_file = std::fs::read_to_string(&log_file_path).unwrap();
|
||||
let log_lines = log_file.lines().collect::<Vec<_>>();
|
||||
assert_eq!(log_lines.len(), 2);
|
||||
assert!(log_lines[0].starts_with(&format!(
|
||||
"0000000000000000000000000000000000000000 {}",
|
||||
commit_id
|
||||
)));
|
||||
assert!(log_lines[0].ends_with(&format!("branch: Created from {}", commit_id)));
|
||||
assert!(log_lines[1].starts_with(&format!("{} {}", commit_id, another_oplog_sha)));
|
||||
assert!(log_lines[1].ends_with(&format!("reset: moving to {another_oplog_sha}")));
|
||||
let another_oplog_sha = git::Oid::from_str("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb")?;
|
||||
set_reference_to_oplog(&worktree_dir, commit_id.into(), another_oplog_sha)
|
||||
.expect("success");
|
||||
|
||||
let contents = std::fs::read_to_string(&log_file_path)?;
|
||||
let lines: Vec<_> = reflog_lines(&contents);
|
||||
assert_eq!(lines.len(), 2);
|
||||
let first_line = &lines[0];
|
||||
assert_eq!(
|
||||
format!("{} {}", first_line.previous_oid, first_line.new_oid),
|
||||
format!("0000000000000000000000000000000000000000 {}", commit_id)
|
||||
);
|
||||
assert_eq!(first_line.message, first_line_message);
|
||||
assert_signature(first_line.signature);
|
||||
|
||||
let second_line = &lines[1];
|
||||
assert_eq!(
|
||||
format!("{} {}", second_line.previous_oid, second_line.new_oid),
|
||||
format!("{} {}", commit_id, another_oplog_sha)
|
||||
);
|
||||
let second_line_message = format!("reset: moving to {another_oplog_sha}");
|
||||
assert_eq!(second_line.message, second_line_message);
|
||||
assert_signature(second_line.signature);
|
||||
|
||||
// Update the target head only
|
||||
let new_target = git::Oid::from_str("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa").unwrap();
|
||||
assert!(set_reference_to_oplog(&project, new_target, another_oplog_sha).is_ok());
|
||||
let log_file = std::fs::read_to_string(&log_file_path).unwrap();
|
||||
let log_lines = log_file.lines().collect::<Vec<_>>();
|
||||
assert_eq!(log_lines.len(), 2);
|
||||
assert!(log_lines[0].starts_with(&format!(
|
||||
"0000000000000000000000000000000000000000 {new_target}"
|
||||
)));
|
||||
assert!(log_lines[0].ends_with(&format!("branch: Created from {new_target}")));
|
||||
assert!(log_lines[1].starts_with(&format!("{new_target} {another_oplog_sha}")));
|
||||
assert!(log_lines[1].ends_with(&format!("reset: moving to {another_oplog_sha}")));
|
||||
let new_target = git::Oid::from_str("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")?;
|
||||
set_reference_to_oplog(&worktree_dir, new_target, another_oplog_sha).expect("success");
|
||||
|
||||
let contents = std::fs::read_to_string(&log_file_path)?;
|
||||
let lines: Vec<_> = reflog_lines(&contents);
|
||||
assert_eq!(lines.len(), 2);
|
||||
let first_line = &lines[0];
|
||||
assert_eq!(
|
||||
format!("{} {}", first_line.previous_oid, first_line.new_oid),
|
||||
format!("0000000000000000000000000000000000000000 {}", new_target)
|
||||
);
|
||||
let line1_message = format!("branch: Created from {new_target}");
|
||||
assert_eq!(first_line.message, line1_message);
|
||||
assert_signature(first_line.signature);
|
||||
|
||||
let second_line = &lines[1];
|
||||
assert_eq!(
|
||||
format!("{} {}", second_line.previous_oid, second_line.new_oid),
|
||||
format!("{} {}", new_target, another_oplog_sha)
|
||||
);
|
||||
assert_eq!(second_line.message, second_line_message);
|
||||
assert_signature(second_line.signature);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_repo() -> (tempfile::TempDir, git2::Oid) {
|
||||
let dir = tempdir().unwrap();
|
||||
let repo = git2::Repository::init(dir.path()).unwrap();
|
||||
fn reflog_lines(contents: &str) -> Vec<LineRef<'_>> {
|
||||
gix::refs::file::log::iter::forward(contents.as_bytes())
|
||||
.map(Result::unwrap)
|
||||
.collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
fn assert_signature(sig: gix::actor::SignatureRef<'_>) {
|
||||
assert_eq!(sig.name, GITBUTLER_INTEGRATION_COMMIT_AUTHOR_NAME);
|
||||
assert_eq!(sig.email, GITBUTLER_INTEGRATION_COMMIT_AUTHOR_EMAIL);
|
||||
}
|
||||
|
||||
fn setup_repo() -> anyhow::Result<(tempfile::TempDir, git2::Oid)> {
|
||||
let dir = tempdir()?;
|
||||
let repo = git2::Repository::init(dir.path())?;
|
||||
let file_path = dir.path().join("foo.txt");
|
||||
std::fs::write(file_path, "test").unwrap();
|
||||
let mut index = repo.index().unwrap();
|
||||
index.add_path(&PathBuf::from("foo.txt")).unwrap();
|
||||
let oid = index.write_tree().unwrap();
|
||||
std::fs::write(file_path, "test")?;
|
||||
let mut index = repo.index()?;
|
||||
index.add_path(&PathBuf::from("foo.txt"))?;
|
||||
let oid = index.write_tree()?;
|
||||
let name = "Your Name";
|
||||
let email = "your.email@example.com";
|
||||
let signature = git2::Signature::now(name, email).unwrap();
|
||||
let commit_id = repo
|
||||
.commit(
|
||||
Some("HEAD"),
|
||||
&signature,
|
||||
&signature,
|
||||
"initial commit",
|
||||
&repo.find_tree(oid).unwrap(),
|
||||
&[],
|
||||
)
|
||||
.unwrap();
|
||||
(dir, commit_id)
|
||||
let signature = git2::Signature::now(name, email)?;
|
||||
let commit_id = repo.commit(
|
||||
Some("HEAD"),
|
||||
&signature,
|
||||
&signature,
|
||||
"initial commit",
|
||||
&repo.find_tree(oid)?,
|
||||
&[],
|
||||
)?;
|
||||
Ok((dir, commit_id))
|
||||
}
|
||||
}
|
||||
|
@ -86,15 +86,15 @@ impl Project {
|
||||
key: "name".to_string(),
|
||||
value: old_branch.name.to_string(),
|
||||
}])
|
||||
} else if let Some(name) = update.name.clone() {
|
||||
} else if let Some(name) = update.name.as_deref() {
|
||||
SnapshotDetails::new(OperationKind::UpdateBranchName).with_trailers(vec![
|
||||
Trailer {
|
||||
key: "before".to_string(),
|
||||
value: old_branch.name.to_string(),
|
||||
value: old_branch.name.clone(),
|
||||
},
|
||||
Trailer {
|
||||
key: "after".to_string(),
|
||||
value: name,
|
||||
value: name.to_owned(),
|
||||
},
|
||||
])
|
||||
} else if update.notes.is_some() {
|
||||
@ -124,19 +124,19 @@ impl Project {
|
||||
value: old_branch.name.clone(),
|
||||
},
|
||||
])
|
||||
} else if let Some(upstream) = update.upstream.clone() {
|
||||
} else if let Some(upstream) = update.upstream.as_deref() {
|
||||
SnapshotDetails::new(OperationKind::UpdateBranchRemoteName).with_trailers(vec![
|
||||
Trailer {
|
||||
key: "before".to_string(),
|
||||
value: old_branch
|
||||
.upstream
|
||||
.clone()
|
||||
.as_ref()
|
||||
.map(|r| r.to_string())
|
||||
.unwrap_or("".to_string()),
|
||||
.unwrap_or_default(),
|
||||
},
|
||||
Trailer {
|
||||
key: "after".to_string(),
|
||||
value: upstream,
|
||||
value: upstream.to_owned(),
|
||||
},
|
||||
])
|
||||
} else {
|
||||
|
@ -17,8 +17,8 @@ lazy_static! {
|
||||
}
|
||||
|
||||
const WORKSPACE_HEAD: &str = "Workspace Head";
|
||||
const GITBUTLER_INTEGRATION_COMMIT_AUTHOR_NAME: &str = "GitButler";
|
||||
const GITBUTLER_INTEGRATION_COMMIT_AUTHOR_EMAIL: &str = "gitbutler@gitbutler.com";
|
||||
pub const GITBUTLER_INTEGRATION_COMMIT_AUTHOR_NAME: &str = "GitButler";
|
||||
pub const GITBUTLER_INTEGRATION_COMMIT_AUTHOR_EMAIL: &str = "gitbutler@gitbutler.com";
|
||||
|
||||
fn get_committer<'a>() -> Result<git::Signature<'a>> {
|
||||
Ok(git::Signature::now(
|
||||
|
@ -30,11 +30,7 @@ impl Default for TestProject {
|
||||
let local_tmp = temp_dir();
|
||||
let local_repository = git::Repository::init_opts(local_tmp.path(), &init_opts())
|
||||
.expect("failed to init repository");
|
||||
local_repository
|
||||
.config()
|
||||
.unwrap()
|
||||
.set_local("commit.gpgsign", "false")
|
||||
.unwrap();
|
||||
setup_config(&local_repository.config().unwrap()).unwrap();
|
||||
let mut index = local_repository.index().expect("failed to get index");
|
||||
let oid = index.write_tree().expect("failed to write tree");
|
||||
let signature = git::Signature::now("test", "test@email.com").unwrap();
|
||||
@ -60,11 +56,7 @@ impl Default for TestProject {
|
||||
.external_template(false),
|
||||
)
|
||||
.expect("failed to init repository");
|
||||
remote_repository
|
||||
.config()
|
||||
.unwrap()
|
||||
.set_local("commit.gpgsign", "false")
|
||||
.unwrap();
|
||||
setup_config(&remote_repository.config().unwrap()).unwrap();
|
||||
|
||||
{
|
||||
let mut remote = local_repository
|
||||
@ -357,3 +349,8 @@ impl TestProject {
|
||||
submodule.add_finalize().unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn setup_config(config: &git::Config) -> anyhow::Result<()> {
|
||||
config.set_local("commit.gpgsign", "false")?;
|
||||
Ok(())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user