rust-lang / git2-rs

libgit2 bindings for Rust
https://docs.rs/git2
Apache License 2.0
1.64k stars 380 forks source link

How do I preform a simple `show`. #996

Closed madelaney closed 8 months ago

madelaney commented 8 months ago

All,

I'm trying to figure how to get the content of a file from a branch or HEAD. Normally, we'd run this command in a shell like git show :<file> (for example: git show :.gitignore).


Mike D.

ehuss commented 8 months ago

I think the outline is roughly:

  1. Get the commit object you are interested in (there are various ways to do this, like revparse_single)
  2. Get the tree object (commit.tree()).
  3. Get the entry from the tree you are interested in (tree.get_path(path)).
  4. Get the object of the entry (entry.to_object())
  5. Get the blob contents (object.as_blob().content()).

There are a bunch of examples at https://libgit2.org/docs/guides/101-samples/ that show how to do things. It is in C, but it should be pretty easy to convert to the Rust API.

madelaney commented 8 months ago

@ehuss , perfect. I can follow that path and it should get me close enough.

madelaney commented 8 months ago

This is the solution that I came up with:

/// Get the contents of a file from a git repository
///
/// # Arguments
///
/// * `file` - The relative path to the file
/// * `branch` - The branch to pull the version from
/// * `repo` - The repository to pull the file from
///
/// # Errors
///
/// [git2::Error]
///
/// # Examples
///
/// ```
/// let repo = git2::Repository::open(".")?;
/// let content = get_file_content(".gitignore", "main", &repo)?;
/// ```
fn get_file_content(
  file: &str,
  branch: &str,
  repo: &Repository,
) -> Result<String, Box<dyn std::error::Error>> {
  let rev = repo.revparse_single(branch)?;
  let tree = rev.peel_to_tree()?;

  let path = tree.get_path(Path::new(file))?;

  let obj_path = path.to_object(repo)?;
  let blob = obj_path.into_blob().unwrap();

  let content = std::str::from_utf8(blob.content())?;

  Ok(content.to_string())
}

There's room for improvement, but that does what I'm looking for.