Skip to main content

Repository

Struct Repository 

Source
pub struct Repository {
    pub git_dir: PathBuf,
    pub work_tree: Option<PathBuf>,
    pub odb: Odb,
    pub explicit_git_dir: bool,
    pub discovery_root: Option<PathBuf>,
    pub work_tree_from_env: bool,
    pub discovery_via_gitfile: bool,
    /* private fields */
}
Expand description

A handle to an open Git repository.

Fields§

§git_dir: PathBuf

Absolute path to the git directory (.git/ or bare repo root).

§work_tree: Option<PathBuf>

Absolute path to the working tree, or None for bare repos.

§odb: Odb

Loose object database.

§explicit_git_dir: bool

Discovery provenance: true when opened via GIT_DIR env or explicit API.

This suppresses safe.bareRepository implicit checks.

§discovery_root: Option<PathBuf>

When the repo was found by walking from a directory containing .git / a gitfile, that directory (matches Git’s setup trace using .git for the default git-dir).

§work_tree_from_env: bool

GIT_WORK_TREE was set without GIT_DIR and applied after discovery (t1510 #1, #5, …).

§discovery_via_gitfile: bool

.git was a gitfile (not a directory) when the repo was discovered.

Implementations§

Source§

impl Repository

Source

pub fn open(git_dir: &Path, work_tree: Option<&Path>) -> Result<Self>

Open a repository from an explicit git-dir and optional work-tree.

§Errors

Returns Error::NotARepository if git_dir does not look like a valid git directory (missing objects/, HEAD, etc.).

Examples found in repository?
examples/repo_init_and_open.rs (line 16)
8fn main() -> grit_lib::error::Result<()> {
9    let root = tempfile::tempdir()?;
10    let path = root.path();
11
12    let repo = init_repository(path, false, "main", None, "files")?;
13    println!("opened after init: git_dir = {}", repo.git_dir.display());
14    println!("work tree: {}", repo.work_tree.as_ref().unwrap().display());
15
16    let again = Repository::open(&repo.git_dir, repo.work_tree.as_deref())?;
17    println!("re-open by path: bare = {}", again.is_bare());
18
19    let marker = path.join("marker.txt");
20    fs::write(&marker, b"inside work tree\n")?;
21    let sub = path.join("subdir");
22    fs::create_dir_all(&sub)?;
23    assert!(std::env::set_current_dir(&sub).is_ok());
24    let discovered = Repository::discover(None)?;
25    println!(
26        "discover from subdir: same git_dir = {}",
27        discovered.git_dir == repo.git_dir
28    );
29
30    Ok(())
31}
Source

pub fn open_skipping_format_validation( git_dir: &Path, work_tree: Option<&Path>, ) -> Result<Self>

Like Self::open but skips [validate_repository_format].

Used after repository discovery when the format is unsupported so callers still learn the git directory (Git GIT_DIR_INVALID_FORMAT still records gitdir for read_early_config).

Source

pub fn discover(start: Option<&Path>) -> Result<Self>

Discover the repository starting from start (defaults to cwd if None).

Checks GIT_DIR first; if set, uses it directly. Otherwise walks up the directory tree looking for .git (regular directory or gitfile).

§Errors

Returns Error::NotARepository if no repository can be found.

Examples found in repository?
examples/repo_init_and_open.rs (line 24)
8fn main() -> grit_lib::error::Result<()> {
9    let root = tempfile::tempdir()?;
10    let path = root.path();
11
12    let repo = init_repository(path, false, "main", None, "files")?;
13    println!("opened after init: git_dir = {}", repo.git_dir.display());
14    println!("work tree: {}", repo.work_tree.as_ref().unwrap().display());
15
16    let again = Repository::open(&repo.git_dir, repo.work_tree.as_deref())?;
17    println!("re-open by path: bare = {}", again.is_bare());
18
19    let marker = path.join("marker.txt");
20    fs::write(&marker, b"inside work tree\n")?;
21    let sub = path.join("subdir");
22    fs::create_dir_all(&sub)?;
23    assert!(std::env::set_current_dir(&sub).is_ok());
24    let discovered = Repository::discover(None)?;
25    println!(
26        "discover from subdir: same git_dir = {}",
27        discovered.git_dir == repo.git_dir
28    );
29
30    Ok(())
31}
Source

pub fn effective_pathspec_cwd(&self) -> PathBuf

Current directory to use for pathspec / cwd-prefix logic.

When GIT_WORK_TREE points at a directory that does not contain the process cwd (alternate work tree + index from the main repo directory), Git treats pathspecs as relative to the work tree root — use that root as the effective cwd.

Source

pub fn index_path(&self) -> PathBuf

Path to the index file.

Source

pub fn index_path_for_env(&self) -> Result<PathBuf>

Resolve which index file to use, honouring GIT_INDEX_FILE like Git plumbing.

Relative paths are resolved from the process current directory.

Source

pub fn load_index(&self) -> Result<Index>

Load the index, expanding sparse-directory placeholders from the object database.

Commands that operate on individual paths should use this instead of Index::load.

Examples found in repository?
examples/index_add.rs (line 38)
9fn main() -> grit_lib::error::Result<()> {
10    let root = tempfile::tempdir()?;
11    let repo = init_repository(root.path(), false, "main", None, "files")?;
12
13    let blob_oid = repo.odb.write(ObjectKind::Blob, b"staged content\n")?;
14
15    let path = b"notes.txt".to_vec();
16    let entry = IndexEntry {
17        ctime_sec: 0,
18        ctime_nsec: 0,
19        mtime_sec: 0,
20        mtime_nsec: 0,
21        dev: 0,
22        ino: 0,
23        mode: MODE_REGULAR,
24        uid: 0,
25        gid: 0,
26        size: 0,
27        oid: blob_oid,
28        flags: (path.len().min(0xfff)) as u16,
29        flags_extended: None,
30        path,
31        base_index_pos: 0,
32    };
33
34    let mut index = Index::new();
35    index.add_or_replace(entry);
36    repo.write_index(&mut index)?;
37
38    let round_trip = repo.load_index()?;
39    println!("index entries: {}", round_trip.entries.len());
40    let first = &round_trip.entries[0];
41    println!(
42        "first path: {}, oid: {}",
43        String::from_utf8_lossy(&first.path),
44        first.oid
45    );
46
47    Ok(())
48}
More examples
Hide additional examples
examples/rev_list.rs (line 37)
12fn make_initial_commit(repo: &Repository) -> grit_lib::error::Result<grit_lib::objects::ObjectId> {
13    use grit_lib::index::{Index, IndexEntry, MODE_REGULAR};
14
15    let blob_oid = repo.odb.write(ObjectKind::Blob, b"log line\n")?;
16    let path = b"file.txt".to_vec();
17    let entry = IndexEntry {
18        ctime_sec: 0,
19        ctime_nsec: 0,
20        mtime_sec: 0,
21        mtime_nsec: 0,
22        dev: 0,
23        ino: 0,
24        mode: MODE_REGULAR,
25        uid: 0,
26        gid: 0,
27        size: 0,
28        oid: blob_oid,
29        flags: (path.len().min(0xfff)) as u16,
30        flags_extended: None,
31        path,
32        base_index_pos: 0,
33    };
34    let mut index = Index::new();
35    index.add_or_replace(entry);
36    repo.write_index(&mut index)?;
37    let index = repo.load_index()?;
38    let tree_oid = write_tree_from_index(&repo.odb, &index, "")?;
39
40    let commit = CommitData {
41        tree: tree_oid,
42        parents: Vec::new(),
43        author: "Example <example@example.com> 1700000000 +0000".to_owned(),
44        committer: "Example <example@example.com> 1700000000 +0000".to_owned(),
45        author_raw: Vec::new(),
46        committer_raw: Vec::new(),
47        encoding: None,
48        message: "root\n".to_owned(),
49        raw_message: None,
50    };
51    let oid = repo
52        .odb
53        .write(ObjectKind::Commit, &serialize_commit(&commit))?;
54    refs::write_ref(&repo.git_dir, "refs/heads/main", &oid)?;
55    Ok(oid)
56}
examples/merge_base.rs (line 40)
11fn commit_tree(
12    repo: &grit_lib::repo::Repository,
13    parent: Option<grit_lib::objects::ObjectId>,
14    message: &str,
15) -> grit_lib::error::Result<grit_lib::objects::ObjectId> {
16    use grit_lib::index::{Index, IndexEntry, MODE_REGULAR};
17
18    let blob_oid = repo.odb.write(ObjectKind::Blob, b"content\n")?;
19    let path = b"file.txt".to_vec();
20    let entry = IndexEntry {
21        ctime_sec: 0,
22        ctime_nsec: 0,
23        mtime_sec: 0,
24        mtime_nsec: 0,
25        dev: 0,
26        ino: 0,
27        mode: MODE_REGULAR,
28        uid: 0,
29        gid: 0,
30        size: 0,
31        oid: blob_oid,
32        flags: (path.len().min(0xfff)) as u16,
33        flags_extended: None,
34        path,
35        base_index_pos: 0,
36    };
37    let mut index = Index::new();
38    index.add_or_replace(entry);
39    repo.write_index(&mut index)?;
40    let index = repo.load_index()?;
41    let tree_oid = write_tree_from_index(&repo.odb, &index, "")?;
42
43    let mut parents = Vec::new();
44    if let Some(p) = parent {
45        parents.push(p);
46    }
47    let commit = CommitData {
48        tree: tree_oid,
49        parents,
50        author: "Example <example@example.com> 1700000000 +0000".to_owned(),
51        committer: "Example <example@example.com> 1700000000 +0000".to_owned(),
52        author_raw: Vec::new(),
53        committer_raw: Vec::new(),
54        encoding: None,
55        message: format!("{message}\n"),
56        raw_message: None,
57    };
58    repo.odb
59        .write(ObjectKind::Commit, &serialize_commit(&commit))
60}
examples/commit_tree.rs (line 42)
12fn main() -> grit_lib::error::Result<()> {
13    let root = tempfile::tempdir()?;
14    let repo = init_repository(root.path(), false, "main", None, "files")?;
15
16    let blob_oid = repo
17        .odb
18        .write(ObjectKind::Blob, b"hello from grit-lib examples\n")?;
19    let path = b"README".to_vec();
20    let entry = IndexEntry {
21        ctime_sec: 0,
22        ctime_nsec: 0,
23        mtime_sec: 0,
24        mtime_nsec: 0,
25        dev: 0,
26        ino: 0,
27        mode: MODE_REGULAR,
28        uid: 0,
29        gid: 0,
30        size: 0,
31        oid: blob_oid,
32        flags: (path.len().min(0xfff)) as u16,
33        flags_extended: None,
34        path,
35        base_index_pos: 0,
36    };
37
38    let mut index = Index::new();
39    index.add_or_replace(entry);
40    repo.write_index(&mut index)?;
41
42    let index = repo.load_index()?;
43    let tree_oid = write_tree_from_index(&repo.odb, &index, "")?;
44    println!("tree: {tree_oid}");
45
46    let commit = CommitData {
47        tree: tree_oid,
48        parents: Vec::new(),
49        author: "Example <example@example.com> 1700000000 +0000".to_owned(),
50        committer: "Example <example@example.com> 1700000000 +0000".to_owned(),
51        author_raw: Vec::new(),
52        committer_raw: Vec::new(),
53        encoding: None,
54        message: "initial example commit\n".to_owned(),
55        raw_message: None,
56    };
57    let raw = serialize_commit(&commit);
58    let commit_oid = repo.odb.write(ObjectKind::Commit, &raw)?;
59    println!("commit: {commit_oid}");
60
61    refs::write_ref(&repo.git_dir, "refs/heads/main", &commit_oid)?;
62    println!("updated refs/heads/main -> {commit_oid}");
63
64    Ok(())
65}
examples/rev_parse.rs (line 38)
11fn main() -> grit_lib::error::Result<()> {
12    let root = tempfile::tempdir()?;
13    let repo = init_repository(root.path(), false, "main", None, "files")?;
14
15    use grit_lib::index::{Index, IndexEntry, MODE_REGULAR};
16    let blob_oid = repo.odb.write(ObjectKind::Blob, b"x\n")?;
17    let path = b"a".to_vec();
18    let entry = IndexEntry {
19        ctime_sec: 0,
20        ctime_nsec: 0,
21        mtime_sec: 0,
22        mtime_nsec: 0,
23        dev: 0,
24        ino: 0,
25        mode: MODE_REGULAR,
26        uid: 0,
27        gid: 0,
28        size: 0,
29        oid: blob_oid,
30        flags: 1,
31        flags_extended: None,
32        path,
33        base_index_pos: 0,
34    };
35    let mut index = Index::new();
36    index.add_or_replace(entry);
37    repo.write_index(&mut index)?;
38    let index = repo.load_index()?;
39    let tree_oid = write_tree_from_index(&repo.odb, &index, "")?;
40    let commit = CommitData {
41        tree: tree_oid,
42        parents: Vec::new(),
43        author: "Example <example@example.com> 1700000000 +0000".to_owned(),
44        committer: "Example <example@example.com> 1700000000 +0000".to_owned(),
45        author_raw: Vec::new(),
46        committer_raw: Vec::new(),
47        encoding: None,
48        message: "r\n".to_owned(),
49        raw_message: None,
50    };
51    let oid = repo
52        .odb
53        .write(ObjectKind::Commit, &serialize_commit(&commit))?;
54    refs::write_ref(&repo.git_dir, "refs/heads/main", &oid)?;
55
56    let head = resolve_revision(&repo, "HEAD")?;
57    let full = resolve_revision(&repo, &oid.to_hex())?;
58    println!("HEAD resolves to {head}");
59    println!("full hex resolves to {full}");
60    assert_eq!(head, full);
61
62    Ok(())
63}
examples/walk_tree.rs (line 70)
36fn main() -> grit_lib::error::Result<()> {
37    let root = tempfile::tempdir()?;
38    let repo = init_repository(root.path(), false, "main", None, "files")?;
39
40    use grit_lib::index::{Index, IndexEntry, MODE_REGULAR};
41
42    let blob_a = repo.odb.write(ObjectKind::Blob, b"a\n")?;
43    let blob_b = repo.odb.write(ObjectKind::Blob, b"b\n")?;
44
45    let mut index = Index::new();
46    for (rel, oid) in [
47        (b"a.txt".as_slice(), blob_a),
48        (b"sub/b.txt".as_slice(), blob_b),
49    ] {
50        let entry = IndexEntry {
51            ctime_sec: 0,
52            ctime_nsec: 0,
53            mtime_sec: 0,
54            mtime_nsec: 0,
55            dev: 0,
56            ino: 0,
57            mode: MODE_REGULAR,
58            uid: 0,
59            gid: 0,
60            size: 0,
61            oid,
62            flags: (rel.len().min(0xfff)) as u16,
63            flags_extended: None,
64            path: rel.to_vec(),
65            base_index_pos: 0,
66        };
67        index.add_or_replace(entry);
68    }
69    repo.write_index(&mut index)?;
70    let index = repo.load_index()?;
71    let tree_oid = write_tree_from_index(&repo.odb, &index, "")?;
72
73    let commit = CommitData {
74        tree: tree_oid,
75        parents: Vec::new(),
76        author: "Example <example@example.com> 1700000000 +0000".to_owned(),
77        committer: "Example <example@example.com> 1700000000 +0000".to_owned(),
78        author_raw: Vec::new(),
79        committer_raw: Vec::new(),
80        encoding: None,
81        message: "tree walk\n".to_owned(),
82        raw_message: None,
83    };
84    let commit_oid = repo
85        .odb
86        .write(ObjectKind::Commit, &serialize_commit(&commit))?;
87    refs::write_ref(&repo.git_dir, "refs/heads/main", &commit_oid)?;
88
89    let head_commit = resolve_revision(&repo, "HEAD")?;
90    let commit_obj = repo.odb.read(&head_commit)?;
91    let parsed = grit_lib::objects::parse_commit(&commit_obj.data)?;
92    println!("walking tree at {}", parsed.tree);
93    walk_tree(&repo, parsed.tree, "")?;
94
95    Ok(())
96}
Source

pub fn load_index_at(&self, path: &Path) -> Result<Index>

Like Repository::load_index, but reads from an explicit index file path (e.g. GIT_INDEX_FILE or a worktree-specific index).

Source

pub fn write_index(&self, index: &mut Index) -> Result<()>

Write the index to the default path after optionally collapsing skip-worktree subtrees into sparse-directory placeholders (when sparse index is enabled).

Examples found in repository?
examples/index_add.rs (line 36)
9fn main() -> grit_lib::error::Result<()> {
10    let root = tempfile::tempdir()?;
11    let repo = init_repository(root.path(), false, "main", None, "files")?;
12
13    let blob_oid = repo.odb.write(ObjectKind::Blob, b"staged content\n")?;
14
15    let path = b"notes.txt".to_vec();
16    let entry = IndexEntry {
17        ctime_sec: 0,
18        ctime_nsec: 0,
19        mtime_sec: 0,
20        mtime_nsec: 0,
21        dev: 0,
22        ino: 0,
23        mode: MODE_REGULAR,
24        uid: 0,
25        gid: 0,
26        size: 0,
27        oid: blob_oid,
28        flags: (path.len().min(0xfff)) as u16,
29        flags_extended: None,
30        path,
31        base_index_pos: 0,
32    };
33
34    let mut index = Index::new();
35    index.add_or_replace(entry);
36    repo.write_index(&mut index)?;
37
38    let round_trip = repo.load_index()?;
39    println!("index entries: {}", round_trip.entries.len());
40    let first = &round_trip.entries[0];
41    println!(
42        "first path: {}, oid: {}",
43        String::from_utf8_lossy(&first.path),
44        first.oid
45    );
46
47    Ok(())
48}
More examples
Hide additional examples
examples/rev_list.rs (line 36)
12fn make_initial_commit(repo: &Repository) -> grit_lib::error::Result<grit_lib::objects::ObjectId> {
13    use grit_lib::index::{Index, IndexEntry, MODE_REGULAR};
14
15    let blob_oid = repo.odb.write(ObjectKind::Blob, b"log line\n")?;
16    let path = b"file.txt".to_vec();
17    let entry = IndexEntry {
18        ctime_sec: 0,
19        ctime_nsec: 0,
20        mtime_sec: 0,
21        mtime_nsec: 0,
22        dev: 0,
23        ino: 0,
24        mode: MODE_REGULAR,
25        uid: 0,
26        gid: 0,
27        size: 0,
28        oid: blob_oid,
29        flags: (path.len().min(0xfff)) as u16,
30        flags_extended: None,
31        path,
32        base_index_pos: 0,
33    };
34    let mut index = Index::new();
35    index.add_or_replace(entry);
36    repo.write_index(&mut index)?;
37    let index = repo.load_index()?;
38    let tree_oid = write_tree_from_index(&repo.odb, &index, "")?;
39
40    let commit = CommitData {
41        tree: tree_oid,
42        parents: Vec::new(),
43        author: "Example <example@example.com> 1700000000 +0000".to_owned(),
44        committer: "Example <example@example.com> 1700000000 +0000".to_owned(),
45        author_raw: Vec::new(),
46        committer_raw: Vec::new(),
47        encoding: None,
48        message: "root\n".to_owned(),
49        raw_message: None,
50    };
51    let oid = repo
52        .odb
53        .write(ObjectKind::Commit, &serialize_commit(&commit))?;
54    refs::write_ref(&repo.git_dir, "refs/heads/main", &oid)?;
55    Ok(oid)
56}
examples/merge_base.rs (line 39)
11fn commit_tree(
12    repo: &grit_lib::repo::Repository,
13    parent: Option<grit_lib::objects::ObjectId>,
14    message: &str,
15) -> grit_lib::error::Result<grit_lib::objects::ObjectId> {
16    use grit_lib::index::{Index, IndexEntry, MODE_REGULAR};
17
18    let blob_oid = repo.odb.write(ObjectKind::Blob, b"content\n")?;
19    let path = b"file.txt".to_vec();
20    let entry = IndexEntry {
21        ctime_sec: 0,
22        ctime_nsec: 0,
23        mtime_sec: 0,
24        mtime_nsec: 0,
25        dev: 0,
26        ino: 0,
27        mode: MODE_REGULAR,
28        uid: 0,
29        gid: 0,
30        size: 0,
31        oid: blob_oid,
32        flags: (path.len().min(0xfff)) as u16,
33        flags_extended: None,
34        path,
35        base_index_pos: 0,
36    };
37    let mut index = Index::new();
38    index.add_or_replace(entry);
39    repo.write_index(&mut index)?;
40    let index = repo.load_index()?;
41    let tree_oid = write_tree_from_index(&repo.odb, &index, "")?;
42
43    let mut parents = Vec::new();
44    if let Some(p) = parent {
45        parents.push(p);
46    }
47    let commit = CommitData {
48        tree: tree_oid,
49        parents,
50        author: "Example <example@example.com> 1700000000 +0000".to_owned(),
51        committer: "Example <example@example.com> 1700000000 +0000".to_owned(),
52        author_raw: Vec::new(),
53        committer_raw: Vec::new(),
54        encoding: None,
55        message: format!("{message}\n"),
56        raw_message: None,
57    };
58    repo.odb
59        .write(ObjectKind::Commit, &serialize_commit(&commit))
60}
examples/commit_tree.rs (line 40)
12fn main() -> grit_lib::error::Result<()> {
13    let root = tempfile::tempdir()?;
14    let repo = init_repository(root.path(), false, "main", None, "files")?;
15
16    let blob_oid = repo
17        .odb
18        .write(ObjectKind::Blob, b"hello from grit-lib examples\n")?;
19    let path = b"README".to_vec();
20    let entry = IndexEntry {
21        ctime_sec: 0,
22        ctime_nsec: 0,
23        mtime_sec: 0,
24        mtime_nsec: 0,
25        dev: 0,
26        ino: 0,
27        mode: MODE_REGULAR,
28        uid: 0,
29        gid: 0,
30        size: 0,
31        oid: blob_oid,
32        flags: (path.len().min(0xfff)) as u16,
33        flags_extended: None,
34        path,
35        base_index_pos: 0,
36    };
37
38    let mut index = Index::new();
39    index.add_or_replace(entry);
40    repo.write_index(&mut index)?;
41
42    let index = repo.load_index()?;
43    let tree_oid = write_tree_from_index(&repo.odb, &index, "")?;
44    println!("tree: {tree_oid}");
45
46    let commit = CommitData {
47        tree: tree_oid,
48        parents: Vec::new(),
49        author: "Example <example@example.com> 1700000000 +0000".to_owned(),
50        committer: "Example <example@example.com> 1700000000 +0000".to_owned(),
51        author_raw: Vec::new(),
52        committer_raw: Vec::new(),
53        encoding: None,
54        message: "initial example commit\n".to_owned(),
55        raw_message: None,
56    };
57    let raw = serialize_commit(&commit);
58    let commit_oid = repo.odb.write(ObjectKind::Commit, &raw)?;
59    println!("commit: {commit_oid}");
60
61    refs::write_ref(&repo.git_dir, "refs/heads/main", &commit_oid)?;
62    println!("updated refs/heads/main -> {commit_oid}");
63
64    Ok(())
65}
examples/rev_parse.rs (line 37)
11fn main() -> grit_lib::error::Result<()> {
12    let root = tempfile::tempdir()?;
13    let repo = init_repository(root.path(), false, "main", None, "files")?;
14
15    use grit_lib::index::{Index, IndexEntry, MODE_REGULAR};
16    let blob_oid = repo.odb.write(ObjectKind::Blob, b"x\n")?;
17    let path = b"a".to_vec();
18    let entry = IndexEntry {
19        ctime_sec: 0,
20        ctime_nsec: 0,
21        mtime_sec: 0,
22        mtime_nsec: 0,
23        dev: 0,
24        ino: 0,
25        mode: MODE_REGULAR,
26        uid: 0,
27        gid: 0,
28        size: 0,
29        oid: blob_oid,
30        flags: 1,
31        flags_extended: None,
32        path,
33        base_index_pos: 0,
34    };
35    let mut index = Index::new();
36    index.add_or_replace(entry);
37    repo.write_index(&mut index)?;
38    let index = repo.load_index()?;
39    let tree_oid = write_tree_from_index(&repo.odb, &index, "")?;
40    let commit = CommitData {
41        tree: tree_oid,
42        parents: Vec::new(),
43        author: "Example <example@example.com> 1700000000 +0000".to_owned(),
44        committer: "Example <example@example.com> 1700000000 +0000".to_owned(),
45        author_raw: Vec::new(),
46        committer_raw: Vec::new(),
47        encoding: None,
48        message: "r\n".to_owned(),
49        raw_message: None,
50    };
51    let oid = repo
52        .odb
53        .write(ObjectKind::Commit, &serialize_commit(&commit))?;
54    refs::write_ref(&repo.git_dir, "refs/heads/main", &oid)?;
55
56    let head = resolve_revision(&repo, "HEAD")?;
57    let full = resolve_revision(&repo, &oid.to_hex())?;
58    println!("HEAD resolves to {head}");
59    println!("full hex resolves to {full}");
60    assert_eq!(head, full);
61
62    Ok(())
63}
examples/walk_tree.rs (line 69)
36fn main() -> grit_lib::error::Result<()> {
37    let root = tempfile::tempdir()?;
38    let repo = init_repository(root.path(), false, "main", None, "files")?;
39
40    use grit_lib::index::{Index, IndexEntry, MODE_REGULAR};
41
42    let blob_a = repo.odb.write(ObjectKind::Blob, b"a\n")?;
43    let blob_b = repo.odb.write(ObjectKind::Blob, b"b\n")?;
44
45    let mut index = Index::new();
46    for (rel, oid) in [
47        (b"a.txt".as_slice(), blob_a),
48        (b"sub/b.txt".as_slice(), blob_b),
49    ] {
50        let entry = IndexEntry {
51            ctime_sec: 0,
52            ctime_nsec: 0,
53            mtime_sec: 0,
54            mtime_nsec: 0,
55            dev: 0,
56            ino: 0,
57            mode: MODE_REGULAR,
58            uid: 0,
59            gid: 0,
60            size: 0,
61            oid,
62            flags: (rel.len().min(0xfff)) as u16,
63            flags_extended: None,
64            path: rel.to_vec(),
65            base_index_pos: 0,
66        };
67        index.add_or_replace(entry);
68    }
69    repo.write_index(&mut index)?;
70    let index = repo.load_index()?;
71    let tree_oid = write_tree_from_index(&repo.odb, &index, "")?;
72
73    let commit = CommitData {
74        tree: tree_oid,
75        parents: Vec::new(),
76        author: "Example <example@example.com> 1700000000 +0000".to_owned(),
77        committer: "Example <example@example.com> 1700000000 +0000".to_owned(),
78        author_raw: Vec::new(),
79        committer_raw: Vec::new(),
80        encoding: None,
81        message: "tree walk\n".to_owned(),
82        raw_message: None,
83    };
84    let commit_oid = repo
85        .odb
86        .write(ObjectKind::Commit, &serialize_commit(&commit))?;
87    refs::write_ref(&repo.git_dir, "refs/heads/main", &commit_oid)?;
88
89    let head_commit = resolve_revision(&repo, "HEAD")?;
90    let commit_obj = repo.odb.read(&head_commit)?;
91    let parsed = grit_lib::objects::parse_commit(&commit_obj.data)?;
92    println!("walking tree at {}", parsed.tree);
93    walk_tree(&repo, parsed.tree, "")?;
94
95    Ok(())
96}
Source

pub fn write_index_with_post_index_change( &self, index: &mut Index, updated_workdir: bool, updated_skipworktree: bool, ) -> Result<()>

Write the index to the default path and pass explicit post-index-change hook flags.

Parameters:

  • index is the in-memory index to serialize.
  • updated_workdir reports that the write is paired with a working-tree update.
  • updated_skipworktree reports that skip-worktree related index state changed.

Returns Ok(()) after the index is written and the hook has been attempted.

Errors when the index cannot be finalized or written.

Source

pub fn write_index_at(&self, path: &Path, index: &mut Index) -> Result<()>

Like Repository::write_index, but writes to an explicit index file path.

Source

pub fn split_index_would_force_write(&self, index: &Index) -> bool

Whether reading index under this repository’s config would mark the cache changed solely to materialize a split index.

Git’s tweak_split_index runs after every index read: when core.splitIndex is true and the index is not yet a split index, add_split_index sets SPLIT_INDEX_ORDERED on cache_changed, which makes opportunistic writers such as status (repo_update_index_if_able) rewrite the index in split form, creating .git/sharedindex.<oid>. This returns true exactly when that would happen: split index is requested (config true or GIT_TEST_SPLIT_INDEX) and the supplied index does not already carry a link extension.

Returns false when split index is disabled/unset or the index is already split.

Source

pub fn write_index_at_with_post_index_change( &self, path: &Path, index: &mut Index, updated_workdir: bool, updated_skipworktree: bool, ) -> Result<()>

Like Repository::write_index_at, but passes explicit post-index-change hook flags.

Parameters:

  • path is the destination index file.
  • index is the in-memory index to serialize.
  • updated_workdir reports that the write is paired with a working-tree update.
  • updated_skipworktree reports that skip-worktree related index state changed.

Returns Ok(()) after the index is written and the hook has been attempted.

Errors when the index cannot be finalized or written.

Source

pub fn write_index_at_split( &self, path: &Path, index: &mut Index, split: WriteSplitIndexRequest, ) -> Result<()>

Write the index to path, optionally emitting a split index (shared base + link extension).

Source

pub fn write_index_at_split_with_post_index_change( &self, path: &Path, index: &mut Index, split: WriteSplitIndexRequest, updated_workdir: bool, updated_skipworktree: bool, ) -> Result<()>

Write the index to path, optionally emitting a split index, with explicit hook flags.

Parameters:

  • path is the destination index file.
  • index is the in-memory index to serialize.
  • split controls whether a split index should be written.
  • updated_workdir reports that the write is paired with a working-tree update.
  • updated_skipworktree reports that skip-worktree related index state changed.

Returns Ok(()) after the index is written and the hook has been attempted.

Errors when the index cannot be finalized or written.

Source

pub fn refs_dir(&self) -> PathBuf

Path to the refs/ directory.

Source

pub fn head_path(&self) -> PathBuf

Path to HEAD.

Source

pub fn bloom_pathspec_cwd(&self) -> Option<String>

Relative path from the work tree root to the process current directory, /-separated.

Used for :(top) / :/ pathspec Bloom lookups. Returns None for bare repositories or when paths cannot be resolved; callers should treat None like an empty prefix.

Source

pub fn is_bare(&self) -> bool

Whether this is a bare repository (no working tree).

Examples found in repository?
examples/repo_init_and_open.rs (line 17)
8fn main() -> grit_lib::error::Result<()> {
9    let root = tempfile::tempdir()?;
10    let path = root.path();
11
12    let repo = init_repository(path, false, "main", None, "files")?;
13    println!("opened after init: git_dir = {}", repo.git_dir.display());
14    println!("work tree: {}", repo.work_tree.as_ref().unwrap().display());
15
16    let again = Repository::open(&repo.git_dir, repo.work_tree.as_deref())?;
17    println!("re-open by path: bare = {}", again.is_bare());
18
19    let marker = path.join("marker.txt");
20    fs::write(&marker, b"inside work tree\n")?;
21    let sub = path.join("subdir");
22    fs::create_dir_all(&sub)?;
23    assert!(std::env::set_current_dir(&sub).is_ok());
24    let discovered = Repository::discover(None)?;
25    println!(
26        "discover from subdir: same git_dir = {}",
27        discovered.git_dir == repo.git_dir
28    );
29
30    Ok(())
31}
Source

pub fn read_replaced(&self, oid: &ObjectId) -> Result<Object>

Read an object, transparently following replace refs.

If refs/replace/<hex> exists for the requested OID and GIT_NO_REPLACE_OBJECTS is not set, this reads the replacement object instead. Otherwise it behaves identically to self.odb.read(oid).

Source§

impl Repository

Source

pub fn enforce_safe_directory(&self) -> Result<()>

Enforce safe.directory ownership checks, matching upstream behavior.

When GIT_TEST_ASSUME_DIFFERENT_OWNER=1, ownership is considered unsafe unless a matching safe.directory value is configured in system/global/ command scopes (repository-local config is ignored).

Source

pub fn enforce_safe_directory_git_dir(&self) -> Result<()>

Enforce safe.directory checks using the repository git-dir path.

Used by operations that explicitly open another repository by path (e.g. local clone source).

Source

pub fn enforce_safe_directory_git_dir_with_path( &self, checked: &Path, ) -> Result<()>

Enforce safe.directory checks against an explicit checked path.

Source

pub fn verify_safe_for_clone_source(&self) -> Result<()>

Verify the repository is safe to use as a git clone source (local clone).

When GIT_TEST_ASSUME_DIFFERENT_OWNER is set, applies the same safe.directory rules as discovery. Otherwise checks filesystem ownership of the git directory only (matching Git’s die_upon_dubious_ownership for clone).

Trait Implementations§

Source§

impl Debug for Repository

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.