Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
36 changes: 20 additions & 16 deletions src/sources/git/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,6 @@ use std::time::{Duration, Instant};
/// checkout is ready to go. See [`GitCheckout::reset`] for why we need this.
const CHECKOUT_READY_LOCK: &str = ".cargo-ok";

/// A short abbreviated OID.
///
/// Exists for avoiding extra allocations in [`GitDatabase::to_short_id`].
pub struct GitShortID(git2::Buf);

impl GitShortID {
/// Views the short ID as a `str`.
pub fn as_str(&self) -> &str {
self.0.as_str().unwrap()
}
}

/// A remote repository. It gets cloned into a local [`GitDatabase`].
#[derive(PartialEq, Clone, Debug)]
pub struct GitRemote {
Expand Down Expand Up @@ -205,10 +193,26 @@ impl GitDatabase {
Ok(checkout)
}

/// Get a short OID for a `revision`, usually 7 chars or more if ambiguous.
pub fn to_short_id(&self, revision: git2::Oid) -> CargoResult<GitShortID> {
let obj = self.repo.find_object(revision, None)?;
Ok(GitShortID(obj.short_id()?))
/// Get a short OID for a `revision`, 7 chars or more if ambiguous.
///
/// Like [`git2::Object::short_id`]
/// but ignores the user's `core.abbrev` git config.
pub fn to_short_id(&self, rev: git2::Oid) -> CargoResult<String> {

@weihanglo weihanglo Jul 31, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have considered adding core.abbrev to our git database's config, though I don't feel comfortable with it. Git repo might be open and cloned elsewhere and we forget to set the config.

View changes since the review

const MIN_ABBREV_LEN: usize = 7; // this is git/libgit2's default
let odb = self.repo.odb()?;
let mut len = MIN_ABBREV_LEN;
let mut hex = rev.to_string();
// quasi- re-implementation of
// https://github.com/libgit2/libgit2/blob/26055f5af74ab/src/libgit2/object.c#L523-L573
while len < hex.len() {
match odb.exists_prefix(rev, len) {
Ok(_) => break,
Err(err) if err.code() == git2::ErrorCode::Ambiguous => len += 1,
Err(err) => return Err(err.into()),
}
}
hex.truncate(len);
Ok(hex)
}

/// Checks if the database contains the object of this `oid`..
Expand Down
43 changes: 43 additions & 0 deletions tests/testsuite/git.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3163,6 +3163,49 @@ fn templatedir_doesnt_cause_problems() {
p.cargo("check").run();
}

#[cargo_test]
fn checkout_name_with_core_abbrev_config() {
let git_project = git::new("dep1", |project| {
project
.file("Cargo.toml", &basic_manifest("dep1", "0.5.0"))
.file("src/lib.rs", "")
});

let p = project()
.file(
"Cargo.toml",
&format!(
r#"
[package]
name = "foo"
version = "0.1.0"
edition = "2015"

[dependencies]
dep1 = {{ git = "{}" }}
"#,
git_project.url()
),
)
.file("src/lib.rs", "")
.build();

fs::write(paths::home().join(".gitconfig"), "[core]\n\tabbrev = 4\n").unwrap();

p.cargo("fetch").run();

let mut co_paths = t!(glob::glob(
paths::home()
.join(".cargo/git/checkouts/dep1-*/*")
.to_str()
.unwrap()
));
let co_path = co_paths.next().unwrap().unwrap();
let rev = co_path.file_name().unwrap().to_str().unwrap();
// The checkout directory name ignores the user's `core.abbrev`.
assert_eq!(rev.len(), 7);
}

#[cargo_test(requires = "git")]
fn git_with_cli_force() {
// Supports a force-pushed repo.
Expand Down