mirror of
https://github.com/martinvonz/jj.git
synced 2025-01-09 05:58:55 +00:00
git: create no-gc ref by GitBackend
Since we now have an explicit method to import heads, it makes more sense to manage no-gc refs by the backend.
This commit is contained in:
parent
17f502c83a
commit
f744e5920b
2 changed files with 25 additions and 17 deletions
|
@ -26,7 +26,7 @@ use tempfile::NamedTempFile;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::backend::{BackendError, CommitId, ObjectId};
|
use crate::backend::{BackendError, CommitId, ObjectId};
|
||||||
use crate::git_backend::{GitBackend, NO_GC_REF_NAMESPACE};
|
use crate::git_backend::GitBackend;
|
||||||
use crate::op_store::{BranchTarget, RefTarget, RefTargetOptionExt};
|
use crate::op_store::{BranchTarget, RefTarget, RefTargetOptionExt};
|
||||||
use crate::repo::{MutableRepo, Repo};
|
use crate::repo::{MutableRepo, Repo};
|
||||||
use crate::revset;
|
use crate::revset;
|
||||||
|
@ -172,18 +172,6 @@ pub fn get_local_git_tracking_branch<'a>(view: &'a View, branch: &str) -> &'a Re
|
||||||
view.get_git_ref(&format!("refs/heads/{branch}"))
|
view.get_git_ref(&format!("refs/heads/{branch}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn prevent_gc(git_repo: &git2::Repository, id: &CommitId) -> Result<(), git2::Error> {
|
|
||||||
// If multiple processes do git::import_refs() in parallel, this can fail to
|
|
||||||
// acquire a lock file even with force=true.
|
|
||||||
git_repo.reference(
|
|
||||||
&format!("{}{}", NO_GC_REF_NAMESPACE, id.hex()),
|
|
||||||
Oid::from_bytes(id.as_bytes()).unwrap(),
|
|
||||||
true,
|
|
||||||
"used by jj",
|
|
||||||
)?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reflect changes made in the underlying Git repo in the Jujutsu repo.
|
/// Reflect changes made in the underlying Git repo in the Jujutsu repo.
|
||||||
///
|
///
|
||||||
/// This function detects conflicts (if both Git and JJ modified a branch) and
|
/// This function detects conflicts (if both Git and JJ modified a branch) and
|
||||||
|
@ -255,9 +243,6 @@ pub fn import_some_refs(
|
||||||
head_commits.push(commit);
|
head_commits.push(commit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for commit in &head_commits {
|
|
||||||
prevent_gc(git_repo, commit.id())?;
|
|
||||||
}
|
|
||||||
mut_repo.add_heads(&head_commits);
|
mut_repo.add_heads(&head_commits);
|
||||||
|
|
||||||
// Apply the change that happened in git since last time we imported refs.
|
// Apply the change that happened in git since last time we imported refs.
|
||||||
|
|
|
@ -43,7 +43,7 @@ use crate::stacked_table::{
|
||||||
const HASH_LENGTH: usize = 20;
|
const HASH_LENGTH: usize = 20;
|
||||||
const CHANGE_ID_LENGTH: usize = 16;
|
const CHANGE_ID_LENGTH: usize = 16;
|
||||||
/// Ref namespace used only for preventing GC.
|
/// Ref namespace used only for preventing GC.
|
||||||
pub const NO_GC_REF_NAMESPACE: &str = "refs/jj/keep/";
|
const NO_GC_REF_NAMESPACE: &str = "refs/jj/keep/";
|
||||||
const CONFLICT_SUFFIX: &str = ".jjconflict";
|
const CONFLICT_SUFFIX: &str = ".jjconflict";
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
@ -233,6 +233,9 @@ impl GitBackend {
|
||||||
&table_lock,
|
&table_lock,
|
||||||
&missing_head_ids,
|
&missing_head_ids,
|
||||||
)?;
|
)?;
|
||||||
|
for &id in &missing_head_ids {
|
||||||
|
prevent_gc(&locked_repo, id)?;
|
||||||
|
}
|
||||||
self.save_extra_metadata_table(mut_table, &table_lock)
|
self.save_extra_metadata_table(mut_table, &table_lock)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -371,6 +374,18 @@ fn create_no_gc_ref() -> String {
|
||||||
format!("{NO_GC_REF_NAMESPACE}{}", hex::encode(random_bytes))
|
format!("{NO_GC_REF_NAMESPACE}{}", hex::encode(random_bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn prevent_gc(git_repo: &git2::Repository, id: &CommitId) -> Result<(), BackendError> {
|
||||||
|
git_repo
|
||||||
|
.reference(
|
||||||
|
&format!("{NO_GC_REF_NAMESPACE}{}", id.hex()),
|
||||||
|
Oid::from_bytes(id.as_bytes()).unwrap(),
|
||||||
|
true,
|
||||||
|
"used by jj",
|
||||||
|
)
|
||||||
|
.map_err(|err| BackendError::Other(Box::new(err)))?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn validate_git_object_id(id: &impl ObjectId) -> Result<git2::Oid, BackendError> {
|
fn validate_git_object_id(id: &impl ObjectId) -> Result<git2::Oid, BackendError> {
|
||||||
if id.as_bytes().len() != HASH_LENGTH {
|
if id.as_bytes().len() != HASH_LENGTH {
|
||||||
return Err(BackendError::InvalidHashLength {
|
return Err(BackendError::InvalidHashLength {
|
||||||
|
@ -943,6 +958,14 @@ mod tests {
|
||||||
|
|
||||||
// Import the head commit and its ancestors
|
// Import the head commit and its ancestors
|
||||||
store.import_head_commits([&commit_id2]).unwrap();
|
store.import_head_commits([&commit_id2]).unwrap();
|
||||||
|
// Ref should be created only for the head commit
|
||||||
|
let git_refs = store
|
||||||
|
.git_repo()
|
||||||
|
.references_glob("refs/jj/keep/*")
|
||||||
|
.unwrap()
|
||||||
|
.map(|git_ref| git_ref.unwrap().target().unwrap())
|
||||||
|
.collect_vec();
|
||||||
|
assert_eq!(git_refs, vec![git_commit_id2]);
|
||||||
|
|
||||||
let commit = store.read_commit(&commit_id).unwrap();
|
let commit = store.read_commit(&commit_id).unwrap();
|
||||||
assert_eq!(&commit.change_id, &change_id);
|
assert_eq!(&commit.change_id, &change_id);
|
||||||
|
|
Loading…
Reference in a new issue