Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
03ec56d
[Result migration] Return `Result` from `AnnotatedCommit::refname()`
DanielEScherzer Apr 27, 2026
d4eb617
[Result migration] Return `Result` from `BlameHunk::summary()`
DanielEScherzer Apr 27, 2026
3fbf477
[Result migration] Return `Result` from `Buf::as_str()`
DanielEScherzer Apr 27, 2026
818c7e7
[Result migration] Return `Result` from `Commit` methods
DanielEScherzer Apr 27, 2026
1131b3a
[Result migration] Return `Result` from `ConfigEntry` methods
DanielEScherzer Apr 27, 2026
de408ed
[Result migration] Return `Result` from `MergeFileResult::path()`
DanielEScherzer Apr 27, 2026
95fbb77
[Result migration] Return `Result` from `Note::message()`
DanielEScherzer Apr 27, 2026
f1451be
[Result migration] Return `Result` from `PackBuilder::name()`
DanielEScherzer Apr 27, 2026
2d9275f
[Result migration] Return `Result` from `PushUpdate` methods
DanielEScherzer Apr 27, 2026
1918d60
[Result migration] Return `Result` from `Rebase::orig_head_name()`
DanielEScherzer Apr 27, 2026
aa3e581
[Result migration] Return `Result` from `RebaseOperation::exec()`
DanielEScherzer Apr 27, 2026
6a8ff69
[Result migration] Return `Result` from `Reference` methods
DanielEScherzer Apr 27, 2026
067f4e7
[Result migration] Return `Result` from `ReflogEntry::message()`
DanielEScherzer Apr 27, 2026
1271fb6
[Result migration] Return `Result` from `Refspec` methods
DanielEScherzer Apr 27, 2026
57657e9
[Result migration] Return `Result` from `Remote` methods
DanielEScherzer Apr 27, 2026
c18421d
[Result migration] Return `Result` from `Repository::namespace()`
DanielEScherzer Apr 27, 2026
4dec2b8
[Result migration] Return `Result` from `Signature` methods
DanielEScherzer Apr 27, 2026
7e08d15
[Result migration] Return `Result` from `StatusEntry::path()`
DanielEScherzer Apr 27, 2026
31737c3
[Result migration] Return `Result` from `StringArray::get()`
DanielEScherzer Apr 27, 2026
201962b
[Result migration] Return `Result` from `Submodule` methods
DanielEScherzer Apr 27, 2026
d791501
[Result migration] Return `Result` from `Tag` methods
DanielEScherzer Apr 27, 2026
f1a78a6
[Result migration] Return `Result` from `TreeEntry::name()`
DanielEScherzer Apr 27, 2026
ba8cb90
[Result migration] Return `Result` from `Worktree::name()`
DanielEScherzer Apr 27, 2026
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
4 changes: 2 additions & 2 deletions examples/cat-file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ fn show_commit(commit: &Commit) {
}
show_sig("author", Some(commit.author()));
show_sig("committer", Some(commit.committer()));
if let Some(msg) = commit.message() {
if let Ok(msg) = commit.message() {
println!("\n{}", msg);
}
}
Expand All @@ -100,7 +100,7 @@ fn show_tag(tag: &Tag) {
println!("tag {}", tag.name().unwrap());
show_sig("tagger", tag.tagger());

if let Some(msg) = tag.message() {
if let Ok(Some(msg)) = tag.message() {
println!("\n{}", msg);
}
}
Expand Down
2 changes: 1 addition & 1 deletion examples/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ fn run(args: &Args) -> Result<(), Error> {
if !sig_matches(&commit.committer(), &args.flag_committer) {
return None;
}
if !log_message_matches(commit.message(), &args.flag_grep) {
if !log_message_matches(commit.message().ok(), &args.flag_grep) {
return None;
}
Some(Ok(commit))
Expand Down
6 changes: 3 additions & 3 deletions examples/pull.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ fn do_fetch<'a>(
// Always fetch all tags.
// Perform a download and also update tips
fo.download_tags(git2::AutotagOption::All);
println!("Fetching {} for repo", remote.name().unwrap());
println!("Fetching {} for repo", remote.name().unwrap().unwrap());
remote.fetch(refs, Some(&mut fo), None)?;

// If there are local objects (we got a thin pack), then tell the user
Expand Down Expand Up @@ -90,8 +90,8 @@ fn fast_forward(
rc: &git2::AnnotatedCommit,
) -> Result<(), git2::Error> {
let name = match lb.name() {
Some(s) => s.to_string(),
None => String::from_utf8_lossy(lb.name_bytes()).to_string(),
Ok(s) => s.to_string(),
Err(_) => String::from_utf8_lossy(lb.name_bytes()).to_string(),
};
let msg = format!("Fast-Forward: Setting {} to id: {}", name, rc.id());
println!("{}", msg);
Expand Down
2 changes: 1 addition & 1 deletion examples/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ fn show_branch(repo: &Repository, format: &Format) -> Result<(), Error> {
}
Err(e) => return Err(e),
};
let head = head.as_ref().and_then(|h| h.shorthand());
let head = head.as_ref().and_then(|h| h.shorthand().ok());

if format == &Format::Long {
println!(
Expand Down
6 changes: 3 additions & 3 deletions examples/tag.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ fn run(args: &Args) -> Result<(), Error> {
} else if args.flag_list {
let pattern = args.arg_pattern.as_ref().map(|s| &s[..]).unwrap_or("*");
for name in repo.tag_names(Some(pattern))?.iter() {
let name = name.unwrap();
let name = name.expect("Not invalid utf8").expect("Not None");
let obj = repo.revparse_single(name)?;

if let Some(tag) = obj.as_tag() {
Expand All @@ -83,7 +83,7 @@ fn run(args: &Args) -> Result<(), Error> {
fn print_tag(tag: &Tag, args: &Args) {
print!("{:<16}", tag.name().unwrap());
if args.flag_n.is_some() {
print_list_lines(tag.message(), args);
print_list_lines(tag.message().unwrap(), args);
} else {
println!();
}
Expand All @@ -92,7 +92,7 @@ fn print_tag(tag: &Tag, args: &Args) {
fn print_commit(commit: &Commit, name: &str, args: &Args) {
print!("{:<16}", name);
if args.flag_n.is_some() {
print_list_lines(commit.message(), args);
print_list_lines(commit.message().ok(), args);
} else {
println!();
}
Expand Down
12 changes: 7 additions & 5 deletions src/blame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,10 +186,12 @@ impl<'blame> BlameHunk<'blame> {
/// The returned message is the summary of the commit, comprising the first
/// paragraph of the message with whitespace trimmed and squashed.
///
/// `None` may be returned if an error occurs or if the summary is not valid
/// utf-8.
pub fn summary(&self) -> Option<&str> {
self.summary_bytes().and_then(|s| str::from_utf8(s).ok())
/// `Ok(None)` may be returned if there is no summary.
pub fn summary(&self) -> Result<Option<&str>, Error> {
match self.summary_bytes() {
Some(sb) => str::from_utf8(sb).map(|s| Some(s)).map_err(|e| e.into()),
None => Ok(None),
}
}

/// Get the short "summary" of the git commit message for the hunk.
Expand Down Expand Up @@ -422,7 +424,7 @@ mod tests {
assert_eq!(hunk.final_start_line(), 1);
assert_eq!(hunk.path(), Some(Path::new("foo/bar")));
assert_eq!(hunk.lines_in_hunk(), 0);
assert_eq!(hunk.summary(), Some("commit"));
assert_eq!(hunk.summary(), Ok(Some("commit")));
assert!(!hunk.is_boundary());

let blame_buffer = blame.blame_buffer("\n".as_bytes()).unwrap();
Expand Down
7 changes: 3 additions & 4 deletions src/buf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use std::str;

use crate::raw;
use crate::util::Binding;
use crate::Error;

/// A structure to wrap an intermediate buffer used by libgit2.
///
Expand Down Expand Up @@ -34,10 +35,8 @@ impl Buf {
}

/// Attempt to view this buffer as a string slice.
///
/// Returns `None` if the buffer is not valid utf-8.
pub fn as_str(&self) -> Option<&str> {
str::from_utf8(&**self).ok()
pub fn as_str(&self) -> Result<&str, Error> {
str::from_utf8(&**self).map_err(|e| e.into())
}
}

Expand Down
65 changes: 33 additions & 32 deletions src/commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,10 +63,8 @@ impl<'repo> Commit<'repo> {
///
/// The returned message will be slightly prettified by removing any
/// potential leading newlines.
///
/// `None` will be returned if the message is not valid utf-8
pub fn message(&self) -> Option<&str> {
str::from_utf8(self.message_bytes()).ok()
pub fn message(&self) -> Result<&str, Error> {
str::from_utf8(self.message_bytes()).map_err(|e| e.into())
}

/// Get the full message of a commit as a byte slice.
Expand All @@ -80,17 +78,18 @@ impl<'repo> Commit<'repo> {
/// Get the encoding for the message of a commit, as a string representing a
/// standard encoding name.
///
/// `None` will be returned if the encoding is not known
pub fn message_encoding(&self) -> Option<&str> {
/// `Ok(None)` will be returned if the encoding is not known
pub fn message_encoding(&self) -> Result<Option<&str>, Error> {
let bytes = unsafe { crate::opt_bytes(self, raw::git_commit_message_encoding(&*self.raw)) };
bytes.and_then(|b| str::from_utf8(b).ok())
match bytes {
Some(b) => str::from_utf8(b).map(|s| Some(s)).map_err(|e| e.into()),
None => Ok(None),
}
}

/// Get the full raw message of a commit.
///
/// `None` will be returned if the message is not valid utf-8
pub fn message_raw(&self) -> Option<&str> {
str::from_utf8(self.message_raw_bytes()).ok()
pub fn message_raw(&self) -> Result<&str, Error> {
str::from_utf8(self.message_raw_bytes()).map_err(|e| e.into())
}

/// Get the full raw message of a commit.
Expand All @@ -99,10 +98,8 @@ impl<'repo> Commit<'repo> {
}

/// Get the full raw text of the commit header.
///
/// `None` will be returned if the message is not valid utf-8
pub fn raw_header(&self) -> Option<&str> {
str::from_utf8(self.raw_header_bytes()).ok()
pub fn raw_header(&self) -> Result<&str, Error> {
str::from_utf8(self.raw_header_bytes()).map_err(|e| e.into())
}

/// Get an arbitrary header field.
Expand All @@ -129,10 +126,12 @@ impl<'repo> Commit<'repo> {
/// The returned message is the summary of the commit, comprising the first
/// paragraph of the message with whitespace trimmed and squashed.
///
/// `None` may be returned if an error occurs or if the summary is not valid
/// utf-8.
pub fn summary(&self) -> Option<&str> {
self.summary_bytes().and_then(|s| str::from_utf8(s).ok())
/// `Ok(None)` may be returned if there is no summary
pub fn summary(&self) -> Result<Option<&str>, Error> {
match self.summary_bytes() {
Some(sb) => str::from_utf8(sb).map(|s| Some(s)).map_err(|e| e.into()),
None => Ok(None),
}
}

/// Get the short "summary" of the git commit message.
Expand All @@ -151,10 +150,12 @@ impl<'repo> Commit<'repo> {
/// but the first paragraph of the message. Leading and trailing whitespaces
/// are trimmed.
///
/// `None` may be returned if an error occurs or if the summary is not valid
/// utf-8.
pub fn body(&self) -> Option<&str> {
self.body_bytes().and_then(|s| str::from_utf8(s).ok())
/// `Ok(None)` may be returned if there is no body.
pub fn body(&self) -> Result<Option<&str>, Error> {
match self.body_bytes() {
Some(sb) => str::from_utf8(sb).map(|s| Some(s)).map_err(|e| e.into()),
None => Ok(None),
}
}

/// Get the long "body" of the git commit message.
Expand Down Expand Up @@ -347,7 +348,7 @@ impl<'repo> std::fmt::Debug for Commit<'repo> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
let mut ds = f.debug_struct("Commit");
ds.field("id", &self.id());
if let Some(summary) = self.summary() {
if let Ok(Some(summary)) = self.summary() {
ds.field("summary", &summary);
}
ds.finish()
Expand Down Expand Up @@ -424,12 +425,12 @@ mod tests {
let head = repo.head().unwrap();
let target = head.target().unwrap();
let commit = repo.find_commit(target).unwrap();
assert_eq!(commit.message(), Some("initial\n\nbody"));
assert_eq!(commit.body(), Some("body"));
assert_eq!(commit.message(), Ok("initial\n\nbody"));
assert_eq!(commit.body(), Ok(Some("body")));
assert_eq!(commit.id(), target);
commit.message_raw().unwrap();
commit.raw_header().unwrap();
commit.message_encoding();
commit.message_encoding().expect("Should not be invalid");
commit.summary().unwrap();
commit.body().unwrap();
commit.tree_id();
Expand All @@ -441,10 +442,10 @@ mod tests {
crate::Oid::from_str(tree_header_bytes.as_str().unwrap()).unwrap(),
commit.tree_id()
);
assert_eq!(commit.author().name(), Some("name"));
assert_eq!(commit.author().email(), Some("email"));
assert_eq!(commit.committer().name(), Some("name"));
assert_eq!(commit.committer().email(), Some("email"));
assert_eq!(commit.author().name(), Ok("name"));
assert_eq!(commit.author().email(), Ok("email"));
assert_eq!(commit.committer().name(), Ok("name"));
assert_eq!(commit.committer().email(), Ok("email"));

let sig = repo.signature().unwrap();
let tree = repo.find_tree(commit.tree_id()).unwrap();
Expand All @@ -457,7 +458,7 @@ mod tests {
.amend(Some("HEAD"), None, None, None, Some("new message"), None)
.unwrap();
let new_head = repo.find_commit(new_head).unwrap();
assert_eq!(new_head.message(), Some("new message"));
assert_eq!(new_head.message(), Ok("new message"));
new_head.into_object();

repo.find_object(target, None).unwrap().as_commit().unwrap();
Expand Down
16 changes: 6 additions & 10 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -522,10 +522,8 @@ impl Drop for Config {

impl<'cfg> ConfigEntry<'cfg> {
/// Gets the name of this entry.
///
/// May return `None` if the name is not valid utf-8
pub fn name(&self) -> Option<&str> {
str::from_utf8(self.name_bytes()).ok()
pub fn name(&self) -> Result<&str, Error> {
str::from_utf8(self.name_bytes()).map_err(|e| e.into())
}

/// Gets the name of this entry as a byte slice.
Expand All @@ -535,13 +533,11 @@ impl<'cfg> ConfigEntry<'cfg> {

/// Gets the value of this entry.
///
/// May return `None` if the value is not valid utf-8
///
/// # Panics
///
/// Panics when no value is defined.
pub fn value(&self) -> Option<&str> {
str::from_utf8(self.value_bytes()).ok()
pub fn value(&self) -> Result<&str, Error> {
str::from_utf8(self.value_bytes()).map_err(|e| e.into())
}

/// Gets the value of this entry as a byte slice.
Expand Down Expand Up @@ -683,8 +679,8 @@ mod tests {
let mut entries = cfg.entries(None).unwrap();
while let Some(entry) = entries.next() {
let entry = entry.unwrap();
entry.name();
entry.value();
entry.name().unwrap();
entry.value().unwrap();
entry.level();
}
}
Expand Down
12 changes: 6 additions & 6 deletions src/mailmap.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@ mod tests {
let mut mm = t!(Mailmap::new());

let mailmapped_sig = t!(mm.resolve_signature(&sig));
assert_eq!(mailmapped_sig.name(), Some(sig_name));
assert_eq!(mailmapped_sig.email(), Some(sig_email));
assert_eq!(mailmapped_sig.name(), Ok(sig_name));
assert_eq!(mailmapped_sig.email(), Ok(sig_email));

t!(mm.add_entry(None, None, None, sig_email));
t!(mm.add_entry(
Expand All @@ -117,8 +117,8 @@ mod tests {
));

let mailmapped_sig = t!(mm.resolve_signature(&sig));
assert_eq!(mailmapped_sig.name(), Some("real name"));
assert_eq!(mailmapped_sig.email(), Some("real@email"));
assert_eq!(mailmapped_sig.name(), Ok("real name"));
assert_eq!(mailmapped_sig.email(), Ok("real@email"));
}

#[test]
Expand All @@ -128,7 +128,7 @@ mod tests {

let sig = t!(Signature::now("name", "email"));
let mailmapped_sig = t!(mm.resolve_signature(&sig));
assert_eq!(mailmapped_sig.name(), Some("name"));
assert_eq!(mailmapped_sig.email(), Some("prøper@emæil"));
assert_eq!(mailmapped_sig.name(), Ok("name"));
assert_eq!(mailmapped_sig.email(), Ok("prøper@emæil"));
}
}
21 changes: 10 additions & 11 deletions src/merge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,8 @@ impl<'repo> AnnotatedCommit<'repo> {
}

/// Get the refname that the given git_annotated_commit refers to
///
/// Returns None if it is not valid utf8
pub fn refname(&self) -> Option<&str> {
str::from_utf8(self.refname_bytes()).ok()
pub fn refname(&self) -> Result<&str, Error> {
str::from_utf8(self.refname_bytes()).map_err(|e| e.into())
}

/// Get the refname that the given git_annotated_commit refers to.
Expand Down Expand Up @@ -361,11 +359,12 @@ impl MergeFileResult {

/// The path that the resultant merge file should use.
///
/// returns `None` if a filename conflict would occur,
/// or if the path is not valid utf-8
pub fn path(&self) -> Option<&str> {
self.path_bytes()
.and_then(|bytes| str::from_utf8(bytes).ok())
/// returns `Ok(None)` if a filename conflict would occur
pub fn path(&self) -> Result<Option<&str>, Error> {
match self.path_bytes() {
Some(pb) => str::from_utf8(pb).map(|s| Some(s)).map_err(|e| e.into()),
None => Ok(None),
}
}

/// Gets the path as a byte slice.
Expand Down Expand Up @@ -403,7 +402,7 @@ impl Drop for MergeFileResult {
impl std::fmt::Debug for MergeFileResult {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut ds = f.debug_struct("MergeFileResult");
if let Some(path) = &self.path() {
if let Ok(Some(path)) = &self.path() {
ds.field("path", path);
}
ds.field("automergeable", &self.is_automergeable());
Expand Down Expand Up @@ -541,7 +540,7 @@ mod tests {
let merge_file_result = crate::merge_file(&base, &ours, &theirs, Some(&mut opts)).unwrap();

assert!(!merge_file_result.is_automergeable());
assert_eq!(merge_file_result.path(), Some("file"));
assert_eq!(merge_file_result.path(), Ok(Some("file")));
assert_eq!(
String::from_utf8_lossy(merge_file_result.content()).to_string(),
r"<<<<<<< ours
Expand Down
Loading