Skip to content

Commit

Permalink
git: on import, add GC-preventing refs to all seen refs
Browse files Browse the repository at this point in the history
To prevent git's GC from breaking a repo, we already add a git ref to
commits we create in the git backend. However, we don't add refs to
commits we import from git. This fixes that.

Closes #815.
  • Loading branch information
martinvonz committed Dec 4, 2022
1 parent 9df247f commit be383ce
Show file tree
Hide file tree
Showing 3 changed files with 19 additions and 1 deletion.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
later removed if you checked out another commit. You can now use `git` to
populate the submodule directory and `jj` will leave it alone.

* Git's GC could remove commits that were referenced from jj in some cases. We
are now better at adding Git refs to prevent that.
[#815](https://github.com/martinvonz/jj/issues/815)

### Contributors

Thanks to the people who made this release happen!
Expand Down
14 changes: 14 additions & 0 deletions lib/src/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use thiserror::Error;

use crate::backend::CommitId;
use crate::commit::Commit;
use crate::git_backend::NO_GC_REF_NAMESPACE;
use crate::op_store;
use crate::op_store::RefTarget;
use crate::repo::MutableRepo;
Expand Down Expand Up @@ -50,6 +51,17 @@ fn parse_git_ref(ref_name: &str) -> Option<RefName> {
}
}

fn prevent_gc(git_repo: &git2::Repository, id: &CommitId) {
git_repo
.reference(
&format!("{}{}", NO_GC_REF_NAMESPACE, id.hex()),
Oid::from_bytes(id.as_bytes()).unwrap(),
true,
"used by jj",
)
.unwrap();
}

/// Reflect changes made in the underlying Git repo in the Jujutsu repo.
pub fn import_refs(
mut_repo: &mut MutableRepo,
Expand All @@ -75,6 +87,7 @@ pub fn import_refs(
let head_commit_id = CommitId::from_bytes(head_git_commit.id().as_bytes());
let head_commit = store.get_commit(&head_commit_id).unwrap();
new_git_heads.insert(head_commit_id.clone());
prevent_gc(git_repo, &head_commit_id);
mut_repo.add_head(&head_commit);
mut_repo.set_git_head(head_commit_id);
} else {
Expand Down Expand Up @@ -112,6 +125,7 @@ pub fn import_refs(
let old_target = existing_git_refs.remove(&full_name);
let new_target = Some(RefTarget::Normal(id.clone()));
if new_target != old_target {
prevent_gc(git_repo, &id);
mut_repo.set_git_ref(full_name.clone(), RefTarget::Normal(id.clone()));
let commit = store.get_commit(&id).unwrap();
mut_repo.add_head(&commit);
Expand Down
2 changes: 1 addition & 1 deletion lib/src/git_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use crate::stacked_table::{TableSegment, TableStore};

const HASH_LENGTH: usize = 20;
/// Ref namespace used only for preventing GC.
const NO_GC_REF_NAMESPACE: &str = "refs/jj/keep/";
pub const NO_GC_REF_NAMESPACE: &str = "refs/jj/keep/";
const CONFLICT_SUFFIX: &str = ".jjconflict";

impl From<git2::Error> for BackendError {
Expand Down

0 comments on commit be383ce

Please sign in to comment.