Skip to content

Make author and committer date roundtrip #1935

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 14 commits into from
Apr 25, 2025
  •  
  •  
  •  
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -377,3 +377,7 @@ no_effect_underscore_binding = "allow" # x1
empty_docs = "allow"
too_long_first_doc_paragraph = "allow"
large_stack_arrays = "allow"

# Fix one day
result_large_err = "allow"
large_enum_variant = "allow"
2 changes: 1 addition & 1 deletion examples/log.rs
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ fn run(args: Args) -> anyhow::Result<()> {
commit_ref.author.actor().write_to(&mut buf)?;
buf.into()
},
time: commit_ref.author.time.format(format::DEFAULT),
time: commit_ref.author.time()?.format(format::DEFAULT),
message: commit_ref.message.to_owned(),
})
}),
Expand Down
7 changes: 4 additions & 3 deletions gitoxide-core/src/corpus/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,9 @@ impl Engine {
let repos = self.refresh_repos(&corpus_path, corpus_id)?;
self.state.progress.set_name("refresh repos".into());
self.state.progress.info(format!(
"Added or updated {} repositories under {corpus_path:?}",
repos.len()
"Added or updated {} repositories under '{corpus_path}'",
repos.len(),
corpus_path = corpus_path.display(),
));
Ok(())
}
Expand Down Expand Up @@ -316,7 +317,7 @@ impl Engine {
out.push(repo);
progress.inc();
}
Err(err) => progress.fail(format!("{repo_path:?}: {err:#?}")),
Err(err) => progress.fail(format!("{repo_path}: {err:#?}", repo_path = repo_path.display())),
}
}
statement.finalize()?;
Expand Down
14 changes: 6 additions & 8 deletions gitoxide-core/src/hours/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ const MINUTES_PER_HOUR: f32 = 60.0;
pub const HOURS_PER_WORKDAY: f32 = 8.0;

pub fn estimate_hours(
commits: &[(u32, gix::actor::SignatureRef<'static>)],
commits: &[(u32, super::SignatureRef<'static>)],
stats: &[(u32, FileStats, LineStats)],
) -> WorkByEmail {
assert!(!commits.is_empty());
Expand All @@ -31,7 +31,7 @@ pub fn estimate_hours(
let mut cur = commits.next().expect("at least one commit if we are here");

for next in commits {
let change_in_minutes = (next.time.seconds.saturating_sub(cur.time.seconds)) as f32 / MINUTES_PER_HOUR;
let change_in_minutes = (next.seconds().saturating_sub(cur.seconds())) as f32 / MINUTES_PER_HOUR;
if change_in_minutes < MAX_COMMIT_DIFFERENCE_IN_MINUTES {
hours += change_in_minutes / MINUTES_PER_HOUR;
} else {
Expand Down Expand Up @@ -166,13 +166,11 @@ pub fn spawn_tree_delta_threads<'scope>(
(true, true) => {
files.modified += 1;
if let Some(cache) = cache.as_mut() {
let mut diff = change.diff(cache).map_err(|err| {
std::io::Error::new(std::io::ErrorKind::Other, err)
})?;
let mut diff = change.diff(cache).map_err(std::io::Error::other)?;
let mut nl = 0;
if let Some(counts) = diff.line_counts().map_err(|err| {
std::io::Error::new(std::io::ErrorKind::Other, err)
})? {
if let Some(counts) =
diff.line_counts().map_err(std::io::Error::other)?
{
nl += counts.insertions as usize + counts.removals as usize;
lines.added += counts.insertions as usize;
lines.removed += counts.removals as usize;
Expand Down
17 changes: 14 additions & 3 deletions gitoxide-core/src/hours/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ use std::{collections::BTreeSet, io, path::Path, time::Instant};

use anyhow::bail;
use gix::{
actor,
bstr::{BStr, ByteSlice},
prelude::*,
progress, Count, NestedProgress, Progress,
Expand All @@ -27,6 +26,18 @@ pub struct Context<W> {
pub out: W,
}

pub struct SignatureRef<'a> {
name: &'a BStr,
email: &'a BStr,
time: gix::date::Time,
}

impl SignatureRef<'_> {
fn seconds(&self) -> gix::date::SecondsSinceUnixEpoch {
self.time.seconds
}
}

/// Estimate the hours it takes to produce the content of the repository in `_working_dir_`, with `_refname_` for
/// the start of the commit graph traversal.
///
Expand Down Expand Up @@ -85,7 +96,7 @@ where

out.push((
commit_idx,
actor::SignatureRef {
SignatureRef {
name,
email,
time: author.time,
Expand All @@ -97,7 +108,7 @@ where
out.sort_by(|a, b| {
a.1.email
.cmp(b.1.email)
.then(a.1.time.seconds.cmp(&b.1.time.seconds).reverse())
.then(a.1.seconds().cmp(&b.1.seconds()).reverse())
});
Ok(out)
});
Expand Down
3 changes: 2 additions & 1 deletion gitoxide-core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@
#![deny(rust_2018_idioms)]
#![forbid(unsafe_code)]

use anyhow::bail;
use std::str::FromStr;

use anyhow::bail;

#[derive(Debug, Eq, PartialEq, Hash, Clone, Copy)]
pub enum OutputFormat {
Human,
Expand Down
8 changes: 4 additions & 4 deletions gitoxide-core/src/organize.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use std::borrow::Cow;
use std::{
borrow::Cow,
ffi::OsStr,
path::{Path, PathBuf},
};
Expand Down Expand Up @@ -138,9 +138,9 @@ fn handle(

if let Some(parent_repo_path) = find_parent_repo(git_workdir) {
progress.fail(format!(
"Skipping repository at {:?} as it is nested within repository {:?}",
"Skipping repository at '{}' as it is nested within repository '{}'",
git_workdir.display(),
parent_repo_path
parent_repo_path.display()
));
return Ok(());
}
Expand All @@ -157,7 +157,7 @@ fn handle(
};
if url.path.is_empty() {
progress.info(format!(
"Skipping repository at {:?} whose remote does not have a path: {:?}",
"Skipping repository at '{}' whose remote does not have a path: {}",
git_workdir.display(),
url.to_bstring()
));
Expand Down
23 changes: 10 additions & 13 deletions gitoxide-core/src/pack/receive.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use crate::net;
use crate::pack::receive::protocol::fetch::negotiate;
use crate::OutputFormat;
use gix::config::tree::Key;
use gix::protocol::maybe_async;
use gix::remote::fetch::Error;
use gix::DynNestedProgress;
use std::{
io,
path::PathBuf,
sync::{atomic::AtomicBool, Arc},
};

use gix::{config::tree::Key, protocol::maybe_async, remote::fetch::Error, DynNestedProgress};
pub use gix::{
hash::ObjectId,
objs::bstr::{BString, ByteSlice},
Expand All @@ -18,11 +18,8 @@ pub use gix::{
},
NestedProgress, Progress,
};
use std::{
io,
path::PathBuf,
sync::{atomic::AtomicBool, Arc},
};

use crate::{net, pack::receive::protocol::fetch::negotiate, OutputFormat};

pub const PROGRESS_RANGE: std::ops::RangeInclusive<u8> = 1..=3;
pub struct Context<W> {
Expand Down Expand Up @@ -294,7 +291,7 @@ fn receive_pack_blocking(
None::<gix::objs::find::Never>,
options,
)
.map_err(|err| io::Error::new(io::ErrorKind::Other, err))?;
.map_err(io::Error::other)?;

if let Some(directory) = refs_directory.take() {
write_raw_refs(refs, directory)?;
Expand Down
8 changes: 6 additions & 2 deletions gitoxide-core/src/query/db.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ pub fn create(path: impl AsRef<std::path::Path>) -> anyhow::Result<rusqlite::Con
}
Some(version) if version != VERSION => match con.close() {
Ok(()) => {
std::fs::remove_file(path)
.with_context(|| format!("Failed to remove incompatible database file at {path:?}"))?;
std::fs::remove_file(path).with_context(|| {
format!(
"Failed to remove incompatible database file at {path}",
path = path.display()
)
})?;
con = rusqlite::Connection::open(path)?;
con.execute_batch(meta_table)?;
con.execute("INSERT into meta(version) values(?)", params![VERSION])?;
Expand Down
2 changes: 1 addition & 1 deletion gitoxide-core/src/query/engine/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ impl query::Engine {
usize,
) = row?;
let id = gix::ObjectId::from(hash);
let commit_time = id.attach(&self.repo).object()?.into_commit().committer()?.time;
let commit_time = id.attach(&self.repo).object()?.into_commit().committer()?.time()?;
let mode = FileMode::from_usize(mode).context("invalid file mode")?;
info.push(trace_path::Info {
id,
Expand Down
2 changes: 1 addition & 1 deletion gitoxide-core/src/repository/archive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ fn fetch_rev_info(
Ok(match object.kind {
gix::object::Kind::Commit => {
let commit = object.into_commit();
(Some(commit.committer()?.time.seconds), commit.tree_id()?.detach())
(Some(commit.committer()?.seconds()), commit.tree_id()?.detach())
}
gix::object::Kind::Tree => (None, object.id),
gix::object::Kind::Tag => fetch_rev_info(object.peel_to_kind(gix::object::Kind::Commit)?)?,
Expand Down
4 changes: 2 additions & 2 deletions gitoxide-core/src/repository/attributes/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ pub struct Options {
}

pub(crate) mod function {
use std::{borrow::Cow, io, path::Path};

use anyhow::bail;
use gix::bstr::BStr;
use std::borrow::Cow;
use std::{io, path::Path};

use crate::{
is_dir_to_mode,
Expand Down
4 changes: 2 additions & 2 deletions gitoxide-core/src/repository/attributes/validate_baseline.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ pub(crate) mod function {
if repo.is_bare() {
writeln!(
err,
"Repo {:?} is bare - disabling git-ignore baseline as `git check-ignore` needs a worktree",
repo.path()
"Repo at '{repo}' is bare - disabling git-ignore baseline as `git check-ignore` needs a worktree",
repo = repo.path().display()
)
.ok();
ignore = false;
Expand Down
4 changes: 2 additions & 2 deletions gitoxide-core/src/repository/blame.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use gix::bstr::ByteSlice;
use gix::config::tree;
use std::ffi::OsStr;

use gix::{bstr::ByteSlice, config::tree};

pub fn blame_file(
mut repo: gix::Repository,
file: &OsStr,
Expand Down
7 changes: 3 additions & 4 deletions gitoxide-core/src/repository/cat.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use crate::repository::revision::resolve::{BlobFormat, TreeMode};
use anyhow::{anyhow, Context};
use gix::diff::blob::ResourceKind;
use gix::filter::plumbing::driver::apply::Delay;
use gix::revision::Spec;
use gix::{diff::blob::ResourceKind, filter::plumbing::driver::apply::Delay, revision::Spec};

use crate::repository::revision::resolve::{BlobFormat, TreeMode};

pub fn display_object(
repo: &gix::Repository,
Expand Down
26 changes: 16 additions & 10 deletions gitoxide-core/src/repository/clean.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,23 @@ pub struct Options {
pub find_untracked_repositories: FindRepository,
}
pub(crate) mod function {
use crate::repository::clean::{FindRepository, Options};
use crate::OutputFormat;
use std::{borrow::Cow, path::Path};

use anyhow::bail;
use gix::bstr::BString;
use gix::bstr::ByteSlice;
use gix::dir::entry::{Kind, Status};
use gix::dir::walk::EmissionMode::CollapseDirectory;
use gix::dir::walk::ForDeletionMode::*;
use gix::dir::{walk, EntryRef};
use std::borrow::Cow;
use std::path::Path;
use gix::{
bstr::{BString, ByteSlice},
dir::{
entry::{Kind, Status},
walk,
walk::{EmissionMode::CollapseDirectory, ForDeletionMode::*},
EntryRef,
},
};

use crate::{
repository::clean::{FindRepository, Options},
OutputFormat,
};

pub fn clean(
repo: gix::Repository,
Expand Down
20 changes: 12 additions & 8 deletions gitoxide-core/src/repository/diff.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
use anyhow::Context;
use gix::bstr::{BString, ByteSlice};
use gix::diff::blob::intern::TokenSource;
use gix::diff::blob::unified_diff::{ContextSize, NewlineSeparator};
use gix::diff::blob::UnifiedDiff;
use gix::objs::tree::EntryMode;
use gix::odb::store::RefreshMode;
use gix::prelude::ObjectIdExt;
use gix::ObjectId;
use gix::{
bstr::{BString, ByteSlice},
diff::blob::{
intern::TokenSource,
unified_diff::{ContextSize, NewlineSeparator},
UnifiedDiff,
},
objs::tree::EntryMode,
odb::store::RefreshMode,
prelude::ObjectIdExt,
ObjectId,
};

pub fn tree(
mut repo: gix::Repository,
Expand Down
3 changes: 2 additions & 1 deletion gitoxide-core/src/repository/dirty.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::OutputFormat;
use anyhow::bail;

use crate::OutputFormat;

pub enum Mode {
IsClean,
IsDirty,
Expand Down
2 changes: 1 addition & 1 deletion gitoxide-core/src/repository/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ pub(crate) mod function {

let start = std::time::Instant::now();
progress.set_name("layout graph".into());
progress.info(format!("writing {path:?}…"));
progress.info(format!("writing {}…", path.display()));
let mut svg = SVGWriter::new();
vg.do_it(false, false, false, &mut svg);
std::fs::write(path, svg.finalize().as_bytes())?;
Expand Down
2 changes: 1 addition & 1 deletion gitoxide-core/src/repository/index/entries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ pub(crate) mod function {
io::{BufWriter, Write},
};

use gix::index::entry::Stage;
use gix::{
bstr::{BStr, BString},
index::entry::Stage,
worktree::IndexPersistedOrInMemory,
Repository,
};
Expand Down
4 changes: 2 additions & 2 deletions gitoxide-core/src/repository/mailmap.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use anyhow::bail;
use gix::bstr::{BString, ByteSlice};
use std::io;

use anyhow::bail;
use gix::bstr::{BString, ByteSlice};
#[cfg(feature = "serde")]
use gix::mailmap::Entry;

Expand Down
Loading
Loading