git2-rs
git2-rs copied to clipboard
Write vs write_tree
I am currently using git2 0.13.12.
If i read the documentation for write: https://docs.rs/git2/0.13.12/git2/struct.Index.html#method.write
Write an existing index object from memory back to disk using an atomic file lock.
and write_tree: https://docs.rs/git2/0.13.12/git2/struct.Index.html#method.write_tree
Write the index as a tree.
This method will scan the index and write a representation of its current state back to disk; it recursively creates tree objects for each of the subtrees stored in the index, but only returns the OID of the root tree. This is the OID that can be used e.g. to create a commit.
The index instance cannot be bare, and needs to be associated to an existing repository.
The index must not contain any file in conflict.
it sounds like i can just call write_tree, get the id and then commit. That is also how the init example explains it: https://github.com/rust-lang/git2-rs/blob/master/examples/init.rs:
/// Unlike regular "git init", this example shows how to create an initial empty
/// commit in the repository. This is the helper function that does that.
fn create_initial_commit(repo: &Repository) -> Result<(), Error> {
// First use the config to initialize a commit signature for the user.
let sig = repo.signature()?;
// Now let's create an empty tree for this commit
let tree_id = {
let mut index = repo.index()?;
// Outside of this example, you could call index.add_path()
// here to put actual files into the index. For our purposes, we'll
// leave it empty for now.
index.write_tree()?
};
let tree = repo.find_tree(tree_id)?;
// Ready to create the initial commit.
//
// Normally creating a commit would involve looking up the current HEAD
// commit and making that be the parent of the initial commit, but here this
// is the first commit so there will be no parent.
repo.commit(Some("HEAD"), &sig, &sig, "Initial commit", &tree, &[])?;
Ok(())
}
But i find that this only work on initial commit.
I have this example
use git2::Commit;
use git2::ObjectType;
use git2::Repository;
use std::env;
use std::fs::File;
use std::path::Path;
fn find_last_commit(repo: &Repository) -> Result<Commit, git2::Error> {
let obj = repo.head()?.resolve()?.peel(ObjectType::Commit)?;
obj.into_commit()
.map_err(|_| git2::Error::from_str("Couldn't find commit"))
}
fn main() {
let args: Vec<String> = env::args().collect();
let root = &args[1];
let file_name = &args[2];
let repo = if Path::new(root).exists() {
println!("open");
Repository::open(root).unwrap()
} else {
println!("init");
Repository::init(root).unwrap()
};
let mut index = repo.index().unwrap();
File::create(Path::new(root).join(file_name)).unwrap();
index.add_path(Path::new(file_name)).unwrap();
index.write().unwrap();
let lc_result = find_last_commit(&repo);
let mut parent_commits: Vec<&Commit> = vec![];
match lc_result.as_ref() {
Ok(c) => parent_commits.push(c),
Err(_) => (),
};
let id = index.write_tree().unwrap();
let tree = repo.find_tree(id).unwrap();
repo.commit(
Some("HEAD"),
&repo.signature().unwrap(),
&repo.signature().unwrap(),
"commit message",
&tree,
&parent_commits,
)
.unwrap();
}
When i run it the first time
cargo run /path/to/testrepo file1.txt
It commits fine, but i need the write call
index.add_path(Path::new(file_name)).unwrap();
index.write().unwrap();
let lc_result = find_last_commit(&repo);
if i want call it again
cargo run /path/to/testrepo file2.txt
If i dont have the write call, it will just show file1.txt and file2.txt as deleted.
Do I need this write call in my example? Or am i using the library wrong? Or is this a bug? If i read the example init and the docs, it shouldn't be necessary to do the write, but my example wont work without.
I dont find it clear on how to use this correctly.
If i am using this correctly, it could be super awesome to have it stated more clearly in the docs or examples, that you need the write call.
Totally agree, having an example on how to commit would be helpful. I've ended up with code very similar to yours @mslot :+1:
I am confused about the same thing, I just found myslef doing both write and write_tree with the latter being used to retrieve the tree Oid. write_tree performs a disk write so using it for that purpose feels very dumb
Totally agree, having an example on how to commit would be helpful. I've ended up with code very similar to yours @mslot 👍
This is exactly how I found this issue because I was also struggling with commit.