Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ pub use crate::pathspec::{PathspecDiffEntries, PathspecEntries};
pub use crate::proxy_options::ProxyOptions;
pub use crate::push_update::PushUpdate;
pub use crate::rebase::{Rebase, RebaseOperation, RebaseOperationType, RebaseOptions};
pub use crate::refdb::Refdb;
pub use crate::reference::{Reference, ReferenceNames, References};
pub use crate::reflog::{Reflog, ReflogEntry, ReflogIter};
pub use crate::refspec::Refspec;
Expand Down Expand Up @@ -727,6 +728,7 @@ mod pathspec;
mod proxy_options;
mod push_update;
mod rebase;
mod refdb;
mod reference;
mod reflog;
mod refspec;
Expand Down
85 changes: 85 additions & 0 deletions src/refdb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
use std::marker;

use crate::util::Binding;
use crate::{raw, Error, Repository};

/// A structure to represent a git reference database.
pub struct Refdb<'repo> {
raw: *mut raw::git_refdb,
_marker: marker::PhantomData<&'repo Repository>,
}

impl Drop for Refdb<'_> {
fn drop(&mut self) {
unsafe { raw::git_refdb_free(self.raw) }
}
}

impl<'repo> Binding for Refdb<'repo> {
type Raw = *mut raw::git_refdb;

unsafe fn from_raw(raw: *mut raw::git_refdb) -> Refdb<'repo> {
Refdb {
raw,
_marker: marker::PhantomData,
}
}

fn raw(&self) -> *mut raw::git_refdb {
self.raw
}
}

impl<'repo> Refdb<'repo> {
/// Suggests that the reference database compress or optimize its
/// references. This mechanism is implementation specific. For on-disk
/// reference databases, for example, this may pack all loose references.
pub fn compress(&self) -> Result<(), Error> {
unsafe {
try_call!(raw::git_refdb_compress(self.raw));
}
Ok(())
}
}

#[cfg(test)]
mod tests {
#[test]
fn smoke() {
let (_td, repo) = crate::test::repo_init();
let refdb = repo.refdb().unwrap();
refdb.compress().unwrap();
}

#[test]
fn set_refdb_roundtrip() {
let (_td, repo) = crate::test::repo_init();
let refdb = repo.refdb().unwrap();
repo.set_refdb(&refdb).unwrap();
// References should still be resolvable after setting the same refdb back.
repo.refname_to_id("HEAD").unwrap();
}

#[test]
fn compress_with_loose_refs() {
let (_td, repo) = crate::test::repo_init();
let head_id = repo.refname_to_id("HEAD").unwrap();
for i in 0..10 {
repo.reference(
&format!("refs/tags/refdb-test-{}", i),
head_id,
false,
"test",
)
.unwrap();
}
let refdb = repo.refdb().unwrap();
refdb.compress().unwrap();
assert_eq!(
repo.references_glob("refs/tags/refdb-test-*")
.unwrap()
.count(),
10
);
}
}
6 changes: 3 additions & 3 deletions src/reference.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,20 +22,20 @@ const GIT_REFNAME_MAX: usize = 1024;
/// [`marker::PhantomData`], since all that matters is that it is tied to the
/// lifetime of the [`Repository`], but this helps distinguish the actual
/// references involved.
struct Refdb<'repo>(#[allow(dead_code)] &'repo Repository);
struct RefdbMarker<'repo>(#[allow(dead_code)] &'repo Repository);

/// A structure to represent a git [reference][1].
///
/// [1]: http://git-scm.com/book/en/Git-Internals-Git-References
pub struct Reference<'repo> {
raw: *mut raw::git_reference,
_marker: marker::PhantomData<Refdb<'repo>>,
_marker: marker::PhantomData<RefdbMarker<'repo>>,
}

/// An iterator over the references in a repository.
pub struct References<'repo> {
raw: *mut raw::git_reference_iterator,
_marker: marker::PhantomData<Refdb<'repo>>,
_marker: marker::PhantomData<RefdbMarker<'repo>>,
}

/// An iterator over the names of references in a repository.
Expand Down
26 changes: 18 additions & 8 deletions src/repo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ use crate::{
Blob, BlobWriter, Branch, BranchType, Branches, Commit, Config, Index, IndexEntry, Oid, Tree,
};
use crate::{Describe, IntoCString, Reflog, RepositoryInitMode, RevparseMode};
use crate::{DescribeOptions, Diff, DiffOptions, Odb, PackBuilder, TreeBuilder};
use crate::{DescribeOptions, Diff, DiffOptions, Odb, PackBuilder, Refdb, TreeBuilder};
use crate::{Note, Notes, ObjectType, Revwalk, Status, StatusOptions, Statuses, Tag, Transaction};

type MergeheadForeachCb<'a> = dyn FnMut(&Oid) -> bool + 'a;
Expand Down Expand Up @@ -1232,20 +1232,30 @@ impl Repository {
Ok(())
}

/// Suggests that the reference database compress or optimize its
/// references. This mechanism is implementation specific. For on-disk
/// reference databases, for example, this may pack all loose references.
pub fn refdb_compress(&self) -> Result<(), Error> {
/// Get the reference database for this repository.
pub fn refdb(&self) -> Result<Refdb<'_>, Error> {
let mut refdb = ptr::null_mut();
unsafe {
try_call!(raw::git_repository_refdb(&mut refdb, self.raw()));
let result = crate::call::c_try(raw::git_refdb_compress(refdb));
raw::git_refdb_free(refdb);
result?;
Ok(Binding::from_raw(refdb))
}
}

/// Override the reference database for this repository
pub fn set_refdb(&self, refdb: &Refdb<'_>) -> Result<(), Error> {
unsafe {
try_call!(raw::git_repository_set_refdb(self.raw(), refdb.raw()));
}
Ok(())
}

/// Suggests that the reference database compress or optimize its
/// references. This mechanism is implementation specific. For on-disk
/// reference databases, for example, this may pack all loose references.
pub fn refdb_compress(&self) -> Result<(), Error> {
self.refdb()?.compress()
}

/// Create a new branch pointing at a target commit
///
/// A new direct reference will be created pointing to this target commit.
Expand Down