Skip to main content

Odb

Struct Odb 

Source
pub struct Odb { /* private fields */ }
Expand description

A loose-object database rooted at a given objects/ directory.

Implementations§

Source§

impl Odb

Source

pub fn new(objects_dir: &Path) -> Self

Create an Odb pointing at the given objects/ directory.

The directory does not need to exist yet; it will be created on the first write operation.

Source

pub fn with_work_tree(objects_dir: &Path, work_tree: &Path) -> Self

Create an Odb with a work tree for resolving relative alternate paths.

Source

pub fn register_submodule_object_directories_from_index( &self, work_tree: &Path, index: &Index, )

Register <submodule-git-dir>/objects for every stage-0 gitlink in index that has a checkout under work_tree, so reads can resolve submodule commits stored only in the nested repository (matches Git’s odb_add_submodule_source_by_path / register_all_submodule_sources).

Source

pub fn with_config_git_dir(self, git_dir: PathBuf) -> Self

Attach a git directory so Self::read can honor core.multiPackIndex when resolving packed objects.

Source

pub fn objects_dir(&self) -> &Path

Return the path to the objects/ directory.

Source

pub fn object_path(&self, oid: &ObjectId) -> PathBuf

Return the filesystem path for a given object ID.

Source

pub fn exists_local(&self, oid: &ObjectId) -> bool

Whether the object exists under this database directory only (loose or local packs).

Unlike Self::exists, this ignores info/alternates and GIT_ALTERNATE_OBJECT_DIRECTORIES. Used for partial-clone bookkeeping where objects reachable via alternates are still treated as “missing” until copied locally.

Objects stored only in promisor packs (sibling .promisor marker next to the .pack) are treated as absent: Git considers them fetchable on demand, and rev-list --missing=print lists them until materialized as loose objects or a non-promisor pack.

The empty tree object is treated as present without a loose file (matches Git).

Source

pub fn exists(&self, oid: &ObjectId) -> bool

Check whether an object exists in the loose store or any pack file.

Source

pub fn freshen_object(&self, oid: &ObjectId) -> bool

Touch the loose object file or pack file containing oid, matching Git’s odb_freshen_object (updates mtime so age-based prune keeps recently re-referenced objects).

Returns true if an on-disk object was found and touched.

Source

pub fn read_loose_verify_oid( path: &Path, expected_oid: &ObjectId, ) -> Result<Object>

Read a loose object file at path, verifying the uncompressed payload hashes to expected_oid.

Git stores loose objects under paths derived from the OID; if the file contents hash to a different id (for example after a mistaken mv), this returns Error::LooseHashMismatch.

§Errors
Source

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

Read and decompress an object from the loose store.

§Errors
Examples found in repository?
examples/cherry_pick.rs (line 44)
40fn tree_of_commit(
41    repo: &grit_lib::repo::Repository,
42    commit_oid: grit_lib::objects::ObjectId,
43) -> grit_lib::error::Result<grit_lib::objects::ObjectId> {
44    let obj = repo.odb.read(&commit_oid)?;
45    Ok(parse_commit(&obj.data)?.tree)
46}
47
48fn main() -> grit_lib::error::Result<()> {
49    let root = tempfile::tempdir()?;
50    let repo = init_repository(root.path(), false, "main", None, "files")?;
51
52    use grit_lib::index::{Index, IndexEntry, MODE_REGULAR};
53
54    // Base commit on main: one file.
55    let blob_a = repo.odb.write(ObjectKind::Blob, b"base\n")?;
56    let mut index = Index::new();
57    index.add_or_replace(IndexEntry {
58        ctime_sec: 0,
59        ctime_nsec: 0,
60        mtime_sec: 0,
61        mtime_nsec: 0,
62        dev: 0,
63        ino: 0,
64        mode: MODE_REGULAR,
65        uid: 0,
66        gid: 0,
67        size: 0,
68        oid: blob_a,
69        flags: 7,
70        flags_extended: None,
71        path: b"base.txt".to_vec(),
72        base_index_pos: 0,
73    });
74    repo.write_index(&mut index)?;
75    let index = repo.load_index()?;
76    let tree_a = write_tree_from_index(&repo.odb, &index, "")?;
77    let commit_a = commit_from_tree(&repo, tree_a, &[], "initial\n")?;
78    refs::write_ref(&repo.git_dir, "refs/heads/main", &commit_a)?;
79
80    // Topic commit: parent A, adds picked.txt (not on main yet).
81    let blob_pick = repo.odb.write(ObjectKind::Blob, b"hello from topic\n")?;
82    let mut index = Index::new();
83    index.add_or_replace(IndexEntry {
84        ctime_sec: 0,
85        ctime_nsec: 0,
86        mtime_sec: 0,
87        mtime_nsec: 0,
88        dev: 0,
89        ino: 0,
90        mode: MODE_REGULAR,
91        uid: 0,
92        gid: 0,
93        size: 0,
94        oid: blob_a,
95        flags: 7,
96        flags_extended: None,
97        path: b"base.txt".to_vec(),
98        base_index_pos: 0,
99    });
100    index.add_or_replace(IndexEntry {
101        ctime_sec: 0,
102        ctime_nsec: 0,
103        mtime_sec: 0,
104        mtime_nsec: 0,
105        dev: 0,
106        ino: 0,
107        mode: MODE_REGULAR,
108        uid: 0,
109        gid: 0,
110        size: 0,
111        oid: blob_pick,
112        flags: 9,
113        flags_extended: None,
114        path: b"picked.txt".to_vec(),
115        base_index_pos: 0,
116    });
117    repo.write_index(&mut index)?;
118    let index = repo.load_index()?;
119    let tree_b = write_tree_from_index(&repo.odb, &index, "")?;
120    let commit_b = commit_from_tree(&repo, tree_b, &[commit_a], "add picked file\n")?;
121    refs::write_ref(&repo.git_dir, "refs/heads/topic", &commit_b)?;
122
123    // Cherry-pick `topic` onto `main` (still at A).
124    let head = resolve_revision(&repo, "main")?;
125    let picked = resolve_revision(&repo, "topic")?;
126    let picked_obj = repo.odb.read(&picked)?;
127    let picked_data = parse_commit(&picked_obj.data)?;
128    let parent = picked_data.parents.first().copied().ok_or_else(|| {
129        grit_lib::error::Error::CorruptObject("picked commit has no parent".into())
130    })?;
131
132    let base_tree = tree_of_commit(&repo, parent)?;
133    let ours_tree = tree_of_commit(&repo, head)?;
134    let theirs_tree = picked_data.tree;
135
136    let merged = merge_trees_three_way(
137        &repo,
138        base_tree,
139        ours_tree,
140        theirs_tree,
141        MergeFavor::default(),
142        WhitespaceMergeOptions::default(),
143        grit_lib::merge_trees::TreeMergeConflictPresentation {
144            label_ours: "HEAD",
145            label_theirs: grit_lib::merge_trees::TheirsConflictLabel::Fixed("picked"),
146            label_base: "parent of picked commit",
147            style: grit_lib::merge_file::ConflictStyle::Merge,
148            checkout_merge: false,
149        },
150    )?;
151
152    if !merged.conflict_content.is_empty() {
153        return Err(grit_lib::error::Error::Message(format!(
154            "merge produced {} conflict path(s); this example expects a clean pick",
155            merged.conflict_content.len()
156        )));
157    }
158
159    let new_tree = write_tree_from_index(&repo.odb, &merged.index, "")?;
160    let config = ConfigSet::load_repo_local_only(&repo.git_dir)?;
161    let msg = commit_trailers::finalize_cherry_pick_message(
162        &picked_data.message,
163        true,
164        false,
165        "Example",
166        "example@example.com",
167        &config,
168        &picked.to_hex(),
169    );
170    let new_commit = commit_from_tree(&repo, new_tree, &[head], &msg)?;
171    refs::write_ref(&repo.git_dir, "refs/heads/main", &new_commit)?;
172
173    println!("cherry-picked {} onto {}", picked, head);
174    println!("new main: {new_commit}");
175    let out = repo.odb.read(&new_commit)?;
176    println!("message:\n{}", parse_commit(&out.data)?.message);
177
178    Ok(())
179}
More examples
Hide additional examples
examples/odb_blob.rs (line 16)
8fn main() -> grit_lib::error::Result<()> {
9    let root = tempfile::tempdir()?;
10    let repo = init_repository(root.path(), false, "main", None, "files")?;
11
12    let payload = b"hello, object database\n";
13    let oid = repo.odb.write(ObjectKind::Blob, payload)?;
14    println!("stored blob: {oid}");
15
16    let Object { kind, data } = repo.odb.read(&oid)?;
17    assert_eq!(kind, ObjectKind::Blob);
18    println!("round-trip: {}", String::from_utf8_lossy(&data));
19
20    Ok(())
21}
examples/walk_tree.rs (line 17)
12fn walk_tree(
13    repo: &grit_lib::repo::Repository,
14    tree_oid: grit_lib::objects::ObjectId,
15    prefix: &str,
16) -> grit_lib::error::Result<()> {
17    let obj = repo.odb.read(&tree_oid)?;
18    let entries = parse_tree(&obj.data)?;
19    for e in entries {
20        let name = String::from_utf8_lossy(&e.name);
21        let path = if prefix.is_empty() {
22            name.into_owned()
23        } else {
24            format!("{prefix}/{name}")
25        };
26        if e.mode == MODE_TREE {
27            println!("{path}/ (tree {})", e.oid);
28            walk_tree(repo, e.oid, &path)?;
29        } else {
30            println!("{path} -> {}", e.oid);
31        }
32    }
33    Ok(())
34}
35
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 hash_object_data(kind: ObjectKind, data: &[u8]) -> ObjectId

Hash raw content of a given kind and return the ObjectId.

This does not write anything to disk.

Source

pub fn write(&self, kind: ObjectKind, data: &[u8]) -> Result<ObjectId>

Write an object to the loose store and return its ObjectId.

If the object already exists it is not overwritten (Git behaviour).

§Errors
  • Error::Io — could not create the directory or write the file.
  • Error::Zlib — compression failed.
Examples found in repository?
examples/odb_blob.rs (line 13)
8fn main() -> grit_lib::error::Result<()> {
9    let root = tempfile::tempdir()?;
10    let repo = init_repository(root.path(), false, "main", None, "files")?;
11
12    let payload = b"hello, object database\n";
13    let oid = repo.odb.write(ObjectKind::Blob, payload)?;
14    println!("stored blob: {oid}");
15
16    let Object { kind, data } = repo.odb.read(&oid)?;
17    assert_eq!(kind, ObjectKind::Blob);
18    println!("round-trip: {}", String::from_utf8_lossy(&data));
19
20    Ok(())
21}
More examples
Hide additional examples
examples/cherry_pick.rs (line 37)
19fn commit_from_tree(
20    repo: &grit_lib::repo::Repository,
21    tree: grit_lib::objects::ObjectId,
22    parents: &[grit_lib::objects::ObjectId],
23    message: &str,
24) -> grit_lib::error::Result<grit_lib::objects::ObjectId> {
25    let commit = CommitData {
26        tree,
27        parents: parents.to_vec(),
28        author: "Example <example@example.com> 1700000000 +0000".to_owned(),
29        committer: "Example <example@example.com> 1700000000 +0000".to_owned(),
30        author_raw: Vec::new(),
31        committer_raw: Vec::new(),
32        encoding: None,
33        message: message.to_owned(),
34        raw_message: None,
35    };
36    repo.odb
37        .write(ObjectKind::Commit, &serialize_commit(&commit))
38}
39
40fn tree_of_commit(
41    repo: &grit_lib::repo::Repository,
42    commit_oid: grit_lib::objects::ObjectId,
43) -> grit_lib::error::Result<grit_lib::objects::ObjectId> {
44    let obj = repo.odb.read(&commit_oid)?;
45    Ok(parse_commit(&obj.data)?.tree)
46}
47
48fn main() -> grit_lib::error::Result<()> {
49    let root = tempfile::tempdir()?;
50    let repo = init_repository(root.path(), false, "main", None, "files")?;
51
52    use grit_lib::index::{Index, IndexEntry, MODE_REGULAR};
53
54    // Base commit on main: one file.
55    let blob_a = repo.odb.write(ObjectKind::Blob, b"base\n")?;
56    let mut index = Index::new();
57    index.add_or_replace(IndexEntry {
58        ctime_sec: 0,
59        ctime_nsec: 0,
60        mtime_sec: 0,
61        mtime_nsec: 0,
62        dev: 0,
63        ino: 0,
64        mode: MODE_REGULAR,
65        uid: 0,
66        gid: 0,
67        size: 0,
68        oid: blob_a,
69        flags: 7,
70        flags_extended: None,
71        path: b"base.txt".to_vec(),
72        base_index_pos: 0,
73    });
74    repo.write_index(&mut index)?;
75    let index = repo.load_index()?;
76    let tree_a = write_tree_from_index(&repo.odb, &index, "")?;
77    let commit_a = commit_from_tree(&repo, tree_a, &[], "initial\n")?;
78    refs::write_ref(&repo.git_dir, "refs/heads/main", &commit_a)?;
79
80    // Topic commit: parent A, adds picked.txt (not on main yet).
81    let blob_pick = repo.odb.write(ObjectKind::Blob, b"hello from topic\n")?;
82    let mut index = Index::new();
83    index.add_or_replace(IndexEntry {
84        ctime_sec: 0,
85        ctime_nsec: 0,
86        mtime_sec: 0,
87        mtime_nsec: 0,
88        dev: 0,
89        ino: 0,
90        mode: MODE_REGULAR,
91        uid: 0,
92        gid: 0,
93        size: 0,
94        oid: blob_a,
95        flags: 7,
96        flags_extended: None,
97        path: b"base.txt".to_vec(),
98        base_index_pos: 0,
99    });
100    index.add_or_replace(IndexEntry {
101        ctime_sec: 0,
102        ctime_nsec: 0,
103        mtime_sec: 0,
104        mtime_nsec: 0,
105        dev: 0,
106        ino: 0,
107        mode: MODE_REGULAR,
108        uid: 0,
109        gid: 0,
110        size: 0,
111        oid: blob_pick,
112        flags: 9,
113        flags_extended: None,
114        path: b"picked.txt".to_vec(),
115        base_index_pos: 0,
116    });
117    repo.write_index(&mut index)?;
118    let index = repo.load_index()?;
119    let tree_b = write_tree_from_index(&repo.odb, &index, "")?;
120    let commit_b = commit_from_tree(&repo, tree_b, &[commit_a], "add picked file\n")?;
121    refs::write_ref(&repo.git_dir, "refs/heads/topic", &commit_b)?;
122
123    // Cherry-pick `topic` onto `main` (still at A).
124    let head = resolve_revision(&repo, "main")?;
125    let picked = resolve_revision(&repo, "topic")?;
126    let picked_obj = repo.odb.read(&picked)?;
127    let picked_data = parse_commit(&picked_obj.data)?;
128    let parent = picked_data.parents.first().copied().ok_or_else(|| {
129        grit_lib::error::Error::CorruptObject("picked commit has no parent".into())
130    })?;
131
132    let base_tree = tree_of_commit(&repo, parent)?;
133    let ours_tree = tree_of_commit(&repo, head)?;
134    let theirs_tree = picked_data.tree;
135
136    let merged = merge_trees_three_way(
137        &repo,
138        base_tree,
139        ours_tree,
140        theirs_tree,
141        MergeFavor::default(),
142        WhitespaceMergeOptions::default(),
143        grit_lib::merge_trees::TreeMergeConflictPresentation {
144            label_ours: "HEAD",
145            label_theirs: grit_lib::merge_trees::TheirsConflictLabel::Fixed("picked"),
146            label_base: "parent of picked commit",
147            style: grit_lib::merge_file::ConflictStyle::Merge,
148            checkout_merge: false,
149        },
150    )?;
151
152    if !merged.conflict_content.is_empty() {
153        return Err(grit_lib::error::Error::Message(format!(
154            "merge produced {} conflict path(s); this example expects a clean pick",
155            merged.conflict_content.len()
156        )));
157    }
158
159    let new_tree = write_tree_from_index(&repo.odb, &merged.index, "")?;
160    let config = ConfigSet::load_repo_local_only(&repo.git_dir)?;
161    let msg = commit_trailers::finalize_cherry_pick_message(
162        &picked_data.message,
163        true,
164        false,
165        "Example",
166        "example@example.com",
167        &config,
168        &picked.to_hex(),
169    );
170    let new_commit = commit_from_tree(&repo, new_tree, &[head], &msg)?;
171    refs::write_ref(&repo.git_dir, "refs/heads/main", &new_commit)?;
172
173    println!("cherry-picked {} onto {}", picked, head);
174    println!("new main: {new_commit}");
175    let out = repo.odb.read(&new_commit)?;
176    println!("message:\n{}", parse_commit(&out.data)?.message);
177
178    Ok(())
179}
examples/index_add.rs (line 13)
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}
examples/rev_list.rs (line 15)
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 18)
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 18)
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}
Source

pub fn write_local(&self, kind: ObjectKind, data: &[u8]) -> Result<ObjectId>

Write an object as a loose file in this object directory only.

Unlike Self::write, this ignores info/alternates and GIT_ALTERNATE_OBJECT_DIRECTORIES: if the object exists only in an alternate store, it is still written here. That matches how Git’s unpack-objects materializes every packed object into the receiving repository even when the same OID is already reachable via alternates (see t5519-push-alternates).

§Errors

Same as Self::write.

Source

pub fn write_loose_materialize( &self, kind: ObjectKind, data: &[u8], ) -> Result<ObjectId>

Write a loose object file when it is missing, even if Self::exists is true because the object lives only in a pack.

Used when materializing a partial-clone layout: objects must be duplicated as loose files before local packs are removed. Unlike Self::write_local, objects present only in a promisor pack are still written because Self::exists_local treats those as absent.

Source

pub fn write_raw(&self, store_bytes: &[u8]) -> Result<ObjectId>

Write an already-serialized object (header + data) to the loose store.

Useful when the caller has the full store bytes (e.g. from stdin with --literally).

§Errors
Source

pub fn write_raw_local(&self, store_bytes: &[u8]) -> Result<ObjectId>

Like Self::write_raw but only consults this object directory, not alternates.

See Self::write_local.

§Errors

Same as Self::write_raw.

Source

pub fn loose_object_plumbing_ok(&self, oid: &ObjectId) -> bool

Returns true when a loose object exists at oid’s path and zlib-decompresses to a structurally valid <type> <size>\0<payload> object (type may be non-standard).

Used for git cat-file -e, which succeeds for hand-crafted loose objects that Self::read rejects due to Error::UnknownObjectType.

Trait Implementations§

Source§

impl Clone for Odb

Source§

fn clone(&self) -> Odb

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Odb

Source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl Freeze for Odb

§

impl RefUnwindSafe for Odb

§

impl Send for Odb

§

impl Sync for Odb

§

impl Unpin for Odb

§

impl UnsafeUnpin for Odb

§

impl UnwindSafe for Odb

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. 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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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.