Skip to content

Commit

Permalink
fix: handle submodules whose entry in the index is a file.
Browse files Browse the repository at this point in the history
  • Loading branch information
Byron committed Sep 6, 2023
1 parent b35e544 commit 4971a48
Show file tree
Hide file tree
Showing 4 changed files with 41 additions and 6 deletions.
12 changes: 8 additions & 4 deletions gix/src/submodule/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,17 +160,21 @@ impl<'repo> Submodule<'repo> {
/// or `None` if it was deleted from the index.
///
/// If `None`, but `Some()` when calling [`Self::head_id()`], then the submodule was just deleted but the change
/// wasn't yet committed.
/// wasn't yet committed. Note that `None` is also returned if the entry at the submodule path isn't a submodule.
/// If `Some()`, but `None` when calling [`Self::head_id()`], then the submodule was just added without having committed the change.
pub fn index_id(&self) -> Result<Option<gix_hash::ObjectId>, index_id::Error> {
let path = self.path()?;
Ok(self.state.index()?.entry_by_path(&path).map(|entry| entry.id))
Ok(self
.state
.index()?
.entry_by_path(&path)
.and_then(|entry| (entry.mode == gix_index::entry::Mode::COMMIT).then_some(entry.id)))
}

/// Return the object id of the submodule as stored in `HEAD^{tree}` of the superproject, or `None` if it wasn't yet committed.
///
/// If `Some()`, but `None` when calling [`Self::index_id()`], then the submodule was just deleted but the change
/// wasn't yet committed.
/// wasn't yet committed. Note that `None` is also returned if the entry at the submodule path isn't a submodule.
/// If `None`, but `Some()` when calling [`Self::index_id()`], then the submodule was just added without having committed the change.
pub fn head_id(&self) -> Result<Option<gix_hash::ObjectId>, head_id::Error> {
let path = self.path()?;
Expand All @@ -180,7 +184,7 @@ impl<'repo> Submodule<'repo> {
.head_commit()?
.tree()?
.peel_to_entry_by_path(gix_path::from_bstr(path.as_ref()))?
.map(|entry| entry.inner.oid))
.and_then(|entry| (entry.mode() == gix_object::tree::EntryMode::Commit).then_some(entry.inner.oid)))
}

/// Return the path at which the repository of the submodule should be located.
Expand Down
4 changes: 2 additions & 2 deletions gix/tests/fixtures/generated-archives/make_submodules.tar.xz
Git LFS file not shown
9 changes: 9 additions & 0 deletions gix/tests/fixtures/make_submodules.sh
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,12 @@ git clone --bare with-submodules with-submodules-after-clone.git
git clone --bare ../module1 modules/m1
)

git clone with-submodules not-a-submodule
(cd not-a-submodule
git submodule update --init
cp .gitmodules modules.bak
git rm m1
echo fake > m1
mv modules.bak .gitmodules
git add m1 && git commit -m "no submodule in index and commit, but in configuration"
)
22 changes: 22 additions & 0 deletions gix/tests/submodule/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,18 @@ mod open {
},
)],
),
(
"not-a-submodule",
&[(
"m1",
gix::submodule::State {
repository_exists: true,
is_old_form: false,
worktree_checkout: false,
superproject_configuration: true,
},
)],
),
] {
let repo = repo(name)?;
for (sm, (name, expected)) in repo.submodules()?.expect("modules present").zip(expected) {
Expand Down Expand Up @@ -81,6 +93,16 @@ mod open {
Ok(())
}

#[test]
fn not_a_submodule() -> crate::Result {
let repo = repo("not-a-submodule")?;
let sm = repo.submodules()?.into_iter().flatten().next().expect("one submodule");
assert!(sm.open()?.is_some(), "repo available as it was cloned");
assert!(sm.index_id()?.is_none(), "no actual submodule");
assert!(sm.head_id()?.is_none(), "no actual submodule");
Ok(())
}

#[test]
fn old_form() -> crate::Result {
for name in ["old-form-invalid-worktree-path", "old-form"] {
Expand Down

0 comments on commit 4971a48

Please sign in to comment.